SuperAPI AI Directory

generating-python-installer

Deployment & operations

View repository

Updated 10-15 10:36

About this skill

Generating Python Installer (Commercial-Grade)

You are a Python commercial deployment expert. Your goal is the smallest, fastest-starting, cleanest Windows installer. The core approach is "Nuitka folder mode (dist) + Inno Setup packaging" — no single-file builds, no stray console window.

When to Activate

Activate when the user explicitly asks for advanced Python packaging or size/startup optimization on Windows:

  • Nuitka extreme / commercial-grade compilation, smallest-size or fastest-startup builds
  • dist folder slimming, DLL footprint analysis, 32-bit vs 64-bit size tradeoffs
  • Inno Setup packaging with full metadata and a clean, residue-free uninstall

This skill targets advanced size/startup optimization — not basic one-file "script to exe" conversion.

How It Works

  1. Confirm build parameters — app name, version, publisher, exe name, source/output dirs, icon. Never auto-fill; ask the user.
  2. Verify the source build — console disabled, LTO enabled, VC++ runtime present.
  3. Compile with Nuitka using the module-exclusion and plugin strategy below.
  4. Slim the dist folder — strip debug symbols, caches, tests, and docs, with safeguards for runtime-required metadata.
  5. Analyze DLLs to find and trim the largest dependencies.
  6. Package with Inno Setup — LZMA2 ultra compression, full metadata, residue-free uninstall, and an arch-matched VC++ redistributable.

Examples

  • "Use Nuitka to package this PySide2 project into a minimal-size commercial installer" → run the full workflow: recommend 32-bit, exclude WebEngine/3D/Charts, slim dist, package with Inno Setup.
  • "My exe is 400 MB, how do I slim it down to half" → analyze DLLs, switch to opencv-python-headless, drop opengl32sw, apply dist slimming.
  • "After installation it won't open on a clean system" → ensure the matching-arch VC++ redistributable is bundled in the Inno Setup script.

Core Philosophy

Stick to the "Nuitka folder mode (dist) + Inno Setup packaging" approach. Reject single-file builds, reject console windows.


Real-world reference case (production-grade PySide2 desktop application, 323 MB, including OpenCV / Playwright)

Project Overview

  • Total size: 323 MB
  • Packaging tool: PyInstaller 4.7 (32-bit)
  • Main dependencies: PySide2 (22.52 MB), OpenCV (62.38 MB), Playwright (76.74 MB)
  • Python version: Python 3.8 (32-bit)
  • Number of DLLs: 71, totaling 93.23 MB

Key optimization strategies

  1. PASS: Use 32-bit Python → 20-30% size reduction
  2. PASS: base_library.zip compresses the standard library → 0.74 MB
  3. PASS: Streamlined module exclusion → no pytest/unittest/setuptools
  4. PASS: Streamlined Qt plugins → keep only the necessary plugins

Size distribution

Component Size Proportion Optimization suggestion
playwright 76.74 MB 23.8% Can be removed if not necessary
OpenCV 62.38 MB 19.3% Use opencv-python-headless
PySide2 22.52 MB 7.0% Exclude WebEngine/3D/Charts
Other dependencies 161.36 MB 49.9% -

Expected results comparison

Project type Nuitka raw After optimization Reference project actual measurement
Tkinter + standard library 150-250 MB 80-120 MB -
PyQt/PySide 200-400 MB 120-250 MB 323 MB (including OpenCV etc.)
Including numpy/pandas 300-600 MB 180-350 MB -

Core Workflow - WARNING: strictly enforced

When the user requests packaging, follow these steps:

Step 1: Mandatory parameter confirmation (FAIL: using default values is prohibited)

WARNING: Important rule: all of the following parameters must be confirmed with the user one by one; automatically filling in or using default values is prohibited!

You must ask the user and confirm the following information (only continue after the user gives an explicit reply):

Parameter Description Example
Software name (App Name) Software display name 红墨批注
Version number (Version) Semantic version number 1.0.0
Publisher/company name (Publisher) Publisher shown in Control Panel YourCompany
Main program (Exe Name) Main executable file name RedInk.exe
Source path (Source Dir) Absolute path to the Nuitka dist folder D:\project\dist
Output path (Output Dir) Location where the installer is generated D:\project\output
Icon path (Icon Path) Absolute path to the .ico file (optional but recommended) D:\project\icon.ico
Official website address (URL) Optional, used for the Control Panel link https://example.com

Prompt template:

"Please provide the following packaging parameters; I need you to confirm them one by one:

  1. Software name:
  2. Version number:
  3. Publisher/Company name:
  4. Main program file name (e.g. xxx.exe):
  5. Source path (Nuitka dist folder):
  6. Output path (installer save location):
  7. Icon path (.ico file, can be left empty):
  8. Official website address (can be left empty):

Please fill in one by one, or reply "skip" to use empty values."

Step 2: Source file quality and compilation check (critical) Before generating code, you must issue the following to the usercritical confirmation(because Inno Setup is only a packaging tool and cannot change the runtime attributes of the program itself):

"WARNING: Compilation parameter check:

  1. No black window: Please confirm that your dist folder was compiled using nuitka --windows-console-mode=disable . (Otherwise there will still be a black box after installation)
  2. High performance: Please confirm whether --lto=yeswas used. (Otherwise startup speed may be unsatisfactory)
  3. Runtime libraries: Please ensure that the dist folder contains the necessary VC++ runtime libraries to prevent it from failing to run on a clean system.

If you confirm the source files are ready, please reply "confirm", otherwise please recompile first."

Step 3: Generate code After the user confirms, output the code containing complete metadata and uninstall icon fix .


Nuitka extreme optimization compilation (based on reference project experience)

I. 32-bit vs 64-bit selection strategy

Reasons why reference project uses 32-bit Python:

Component 64-bit size 32-bit size Savings
python3x.dll ~4.5 MB ~3.8 MB 15%
Qt5Core.dll ~8 MB ~5 MB 37%
numpy ~30 MB ~20 MB 33%
Overall Baseline -20~30% -

Recommended conditions for using 32-bit:

  • PASS: Program memory usage < 2GB
  • PASS: Does not process very large files (< 2GB)
  • PASS: Target users are ordinary office computers

32-bit compilation method:

# 1. 安装 32 位 Python(和 64 位可以共存)
# 下载地址:https://www.python.org/downloads/windows/

# 2. 用 32 位 Python 安装依赖
py -3.12-32 -m pip install -r requirements.txt

# 3. 用 32 位 Python 编译
py -3.12-32 -m nuitka --standalone ...你的参数

II. Module exclusion list (verified by reference project)

Safe exclusion list(not needed at runtime):

unittest,test,pytest,_pytest,doctest,pdb,pdbpp,
setuptools,pip,distutils,pkg_resources,
email.mime,http.server,xmlrpc,pydoc

Expected effect: Save 30-50 MB

III. GUI framework-specific optimization

Tkinter extreme optimization (recommended, most lightweight)

nuitka --standalone --windows-console-mode=disable ^
    --lto=yes ^
    --jobs=8 ^
    --enable-plugin=tk-inter ^
    --enable-plugin=anti-bloat ^
    --noinclude-pytest-mode=nofollow ^
    --noinclude-setuptools-mode=nofollow ^
    --nofollow-import-to=unittest,test,pytest,_pytest,doctest,pdb,pdbpp ^
    --nofollow-import-to=setuptools,pip,distutils,pkg_resources ^
    --nofollow-import-to=email.mime,http.server,xmlrpc,pydoc ^
    --python-flag=no_docstrings ^
    --output-dir=dist ^
    --windows-icon-from-ico=icon.ico ^
    --remove-output ^
    main.py

Expected size: 80-120 MB (after optimization)

PyQt5 / PySide2 optimization

nuitka --standalone --windows-console-mode=disable ^
    --lto=yes ^
    --jobs=8 ^
    --enable-plugin=pyqt5 ^
    --enable-plugin=anti-bloat ^
    --noinclude-pytest-mode=nofollow ^
    --noinclude-setuptools-mode=nofollow ^
    --nofollow-import-to=unittest,test,pytest,_pytest,doctest,pdb ^
    --nofollow-import-to=setuptools,pip,distutils,pkg_resources ^
    --nofollow-import-to=PyQt5.QtWebEngine,PyQt5.QtWebEngineWidgets ^
    --nofollow-import-to=PyQt5.Qt3D,PyQt5.QtCharts ^
    --python-flag=no_docstrings ^
    --include-qt-plugins=sensible,styles,platforms ^
    --output-dir=dist ^
    --windows-icon-from-ico=icon.ico ^
    --remove-output ^
    main.py

Expected size: 120-250 MB (after optimization)

IV. One-click compilation script template

Save as build_optimized.bat(project root directory):

@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion

echo ========================================
echo Nuitka 极限优化编译(参考 参考项目)
echo ========================================

REM === 配置区域(请修改为你的实际值) ===
set APP_NAME=你的软件名
set MAIN_FILE=main.py
set ICON_FILE=icon.ico

REM === 自动检测 CPU 核心数 ===
REM 用 Windows 自带环境变量(wmic 在 Win11 22H2+ 已移除,探不到会让 --jobs=0 单线程编译)
set CPU_CORES=%NUMBER_OF_PROCESSORS%
if not defined CPU_CORES set CPU_CORES=4
set /a BUILD_JOBS=%CPU_CORES%

REM === 参考项目的模块排除清单 ===
set EXCLUDE_MODULES=unittest,test,pytest,_pytest,doctest,pdb,pdbpp
set EXCLUDE_MODULES=%EXCLUDE_MODULES%,setuptools,pip,distutils,pkg_resources
set EXCLUDE_MODULES=%EXCLUDE_MODULES%,email.mime,http.server,xmlrpc,pydoc

echo.
echo [1/4] 清理旧编译...
if exist dist rd /s /q dist
if exist build rd /s /q build

echo.
echo [2/4] Nuitka 编译中(应用 参考项目优化策略)...
echo - CPU 核心: %CPU_CORES% (使用 %BUILD_JOBS% 线程)
echo - 模块排除: %EXCLUDE_MODULES%
echo.

nuitka --standalone ^
    --windows-console-mode=disable ^
    --lto=yes ^
    --jobs=%BUILD_JOBS% ^
    --enable-plugin=anti-bloat ^
    --enable-plugin=tk-inter ^
    --noinclude-pytest-mode=nofollow ^
    --noinclude-setuptools-mode=nofollow ^
    --nofollow-import-to=%EXCLUDE_MODULES% ^
    --python-flag=no_docstrings ^
    --output-dir=dist ^
    --windows-icon-from-ico=%ICON_FILE% ^
    --remove-output ^
    %MAIN_FILE%

if %errorlevel% neq 0 (
    echo.
    echo [错误] 编译失败!
    pause
    exit /b 1
)

echo.
echo [3/4] 统计编译结果...
for /f %%a in ('powershell -NoProfile -Command "(Get-ChildItem -LiteralPath 'dist\%APP_NAME%.dist' -Recurse -File | Measure-Object -Property Length -Sum).Sum"') do set TOTAL_SIZE=%%a
set TOTAL_SIZE=%TOTAL_SIZE:,=%
set /a SIZE_MB=%TOTAL_SIZE% / 1048576
echo - 编译后体积: %SIZE_MB% MB

echo.
echo [4/4] 执行瘦身清理(参考 参考项目策略)...
powershell -ExecutionPolicy Bypass -File slim_dist.ps1 -DistPath "dist\%APP_NAME%.dist"

echo.
echo ========================================
echo 编译完成!
echo ========================================
pause

V. dist slimming script ( reference project-level cleanup)

Save as slim_dist.ps1(same directory as build_optimized.bat):

param(
    [string]$DistPath
)

$ErrorActionPreference = "Continue"  # 不静默吞错:删除失败会显示出来,避免假成功

Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "dist 瘦身清理(参考 参考项目策略)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan

if (-not (Test-Path $DistPath)) {
    Write-Host "[错误] 找不到目录: $DistPath" -ForegroundColor Red
    exit 1
}

# 统计初始体积
$InitialSize = (Get-ChildItem -Path $DistPath -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1MB
Write-Host "`n初始体积: $([math]::Round($InitialSize, 2)) MB" -ForegroundColor Yellow

# 参考项目特征:没有 .pdb, .pyi, __pycache__, test 等
Write-Host "`n[应用 参考项目的清理策略...]" -ForegroundColor Green

# 1. 删除调试符号
Write-Host "`n[1/7] 删除 .pdb 调试符号..." -ForegroundColor Green
$pdbFiles = Get-ChildItem -Path $DistPath -Recurse -Include *.pdb -File
$pdbSize = ($pdbFiles | Measure-Object -Property Length -Sum).Sum / 1MB
if ($pdbFiles.Count -gt 0) {
    $pdbFiles | Remove-Item -Force
    Write-Host "  删除 $($pdbFiles.Count) 个文件,节省 $([math]::Round($pdbSize, 2)) MB"
} else {
    Write-Host "  未发现 .pdb 文件(已优化)" -ForegroundColor Gray
}

# 2. 删除类型提示
Write-Host "`n[2/7] 删除 .pyi 类型提示..." -ForegroundColor Green
$pyiFiles = Get-ChildItem -Path $DistPath -Recurse -Include *.pyi -File
$pyiSize = ($pyiFiles | Measure-Object -Property Length -Sum).Sum / 1MB
if ($pyiFiles.Count -gt 0) {
    $pyiFiles | Remove-Item -Force
    Write-Host "  删除 $($pyiFiles.Count) 个文件,节省 $([math]::Round($pyiSize, 2)) MB"
} else {
    Write-Host "  未发现 .pyi 文件(已优化)" -ForegroundColor Gray
}

# 3. 删除 __pycache__
Write-Host "`n[3/7] 删除 __pycache__ 缓存..." -ForegroundColor Green
$pycacheDirs = Get-ChildItem -Path $DistPath -Recurse -Directory -Filter "__pycache__"
$pycacheSize = 0
foreach ($dir in $pycacheDirs) {
    $size = (Get-ChildItem -Path $dir.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
    $pycacheSize += $size
    Remove-Item -Path $dir.FullName -Recurse -Force
}
if ($pycacheDirs.Count -gt 0) {
    Write-Host "  删除 $($pycacheDirs.Count) 个目录,节省 $([math]::Round($pycacheSize / 1MB, 2)) MB"
} else {
    Write-Host "  未发现 __pycache__(已优化)" -ForegroundColor Gray
}

# 4. 删除测试目录
Write-Host "`n[4/7] 删除 test/tests 测试目录..." -ForegroundColor Green
$testDirs = Get-ChildItem -Path $DistPath -Recurse -Directory | Where-Object { $_.Name -match '^tests?$' }
$testSize = 0
foreach ($dir in $testDirs) {
    $size = (Get-ChildItem -Path $dir.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
    $testSize += $size
    Remove-Item -Path $dir.FullName -Recurse -Force
}
if ($testDirs.Count -gt 0) {
    Write-Host "  删除 $($testDirs.Count) 个目录,节省 $([math]::Round($testSize / 1MB, 2)) MB"
} else {
    Write-Host "  未发现测试目录(已优化)" -ForegroundColor Gray
}

# 5. 删除文档和示例
Write-Host "`n[5/7] 删除 docs/examples 文档目录..." -ForegroundColor Green
$docDirs = Get-ChildItem -Path $DistPath -Recurse -Directory | Where-Object { $_.Name -match '^(docs|examples|samples|demo)$' }
$docSize = 0
foreach ($dir in $docDirs) {
    $size = (Get-ChildItem -Path $dir.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
    $docSize += $size
    Remove-Item -Path $dir.FullName -Recurse -Force
}
if ($docDirs.Count -gt 0) {
    Write-Host "  删除 $($docDirs.Count) 个目录,节省 $([math]::Round($docSize / 1MB, 2)) MB"
} else {
    Write-Host "  未发现文档目录(已优化)" -ForegroundColor Gray
}

# 6. 删除 .pyc 文件
Write-Host "`n[6/7] 删除 .pyc 字节码..." -ForegroundColor Green
$pycFiles = Get-ChildItem -Path $DistPath -Recurse -Include *.pyc -File
$pycSize = ($pycFiles | Measure-Object -Property Length -Sum).Sum / 1MB
if ($pycFiles.Count -gt 0) {
    $pycFiles | Remove-Item -Force
    Write-Host "  删除 $($pycFiles.Count) 个文件,节省 $([math]::Round($pycSize, 2)) MB"
} else {
    Write-Host "  未发现 .pyc 文件(已优化)" -ForegroundColor Gray
}

# 7. 精简 .dist-info 元数据
Write-Host "`n[7/7] 精简 .dist-info 元数据..." -ForegroundColor Green
$distInfoDirs = Get-ChildItem -Path $DistPath -Recurse -Directory -Filter "*.dist-info"
$removedCount = 0
$removedSize = 0
foreach ($infoDir in $distInfoDirs) {
    # 仅删安装期记账文件;保留 METADATA 与 entry_points.txt(运行期被 importlib.metadata 读取,删除会破坏插件发现)
    $filesToRemove = @("RECORD", "INSTALLER", "direct_url.json")
    foreach ($fileName in $filesToRemove) {
        $file = Join-Path $infoDir.FullName $fileName
        if (Test-Path $file) {
            $size = (Get-Item $file).Length
            $removedSize += $size
            Remove-Item $file -Force
            $removedCount++
        }
    }
}
if ($removedCount -gt 0) {
    Write-Host "  删除 $removedCount 个元数据文件,节省 $([math]::Round($removedSize / 1MB, 2)) MB"
} else {
    Write-Host "  未发现可清理的元数据(已优化)" -ForegroundColor Gray
}

# 统计最终体积
$FinalSize = (Get-ChildItem -Path $DistPath -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1MB
$SavedSize = $InitialSize - $FinalSize
$SavedPercent = if ($InitialSize -gt 0) { ($SavedSize / $InitialSize) * 100 } else { 0 }

Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "清理完成!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "初始体积: $([math]::Round($InitialSize, 2)) MB" -ForegroundColor Yellow
Write-Host "最终体积: $([math]::Round($FinalSize, 2)) MB" -ForegroundColor Green
Write-Host "节省空间: $([math]::Round($SavedSize, 2)) MB ($([math]::Round($SavedPercent, 1))%)" -ForegroundColor Cyan
Write-Host "========================================`n" -ForegroundColor Cyan

# 对比 参考项目
Write-Host "[对比参考]" -ForegroundColor Yellow
Write-Host "参考项目总体积: 323 MB (包含 PyQt, OpenCV, Playwright 等重量级库)" -ForegroundColor Gray
Write-Host "如果你的项目是纯 Tkinter + 标准库,目标应该在 80-150 MB" -ForegroundColor Gray

Expected effect: Save 15-30% size

VI. DLL dependency analysis tool

Save as analyze_dlls.py(used to identify large size contributors):

"""
DLL 依赖分析工具
参考 参考项目的 DLL 管理策略,帮助识别体积大户和优化建议
"""
import sys
from pathlib import Path

def analyze_dlls(dist_path: str):
    """分析 dist 目录中的 DLL 依赖"""
    dist_dir = Path(dist_path)

    if not dist_dir.exists():
        print(f"[错误] 目录不存在: {dist_path}")
        return

    print("=" * 70)
    print("DLL 依赖分析(参考 参考项目策略)")
    print("=" * 70)

    # 收集所有 DLL
    dll_files = list(dist_dir.rglob("*.dll"))

    if not dll_files:
        print("\n未发现 DLL 文件")
        return

    # 按大小排序
    dll_data = [(dll, dll.stat().st_size) for dll in dll_files]
    dll_data.sort(key=lambda x: x[1], reverse=True)

    total_size = sum(size for _, size in dll_data)

    print(f"\n总 DLL 数量: {len(dll_files)}")
    print(f"总 DLL 体积: {total_size / 1024 / 1024:.2f} MB\n")

    # 参考项目对比
    print("[对比参考] 参考项目的 DLL 情况:")
    print("  - 总数量: 71 个")
    print("  - 总体积: 93.23 MB")
    print("  - 最大的: libopenblas (26.85 MB), opengl32sw (15.25 MB)\n")

    # 分析大于 3MB 的 DLL
    large_dlls = [(dll, size) for dll, size in dll_data if size > 3 * 1024 * 1024]

    if large_dlls:
        print("=" * 70)
        print("WARNING:  大于 3MB 的 DLL(需重点关注)")
        print("=" * 70)

        for dll, size in large_dlls:
            size_mb = size / 1024 / 1024
            relative_path = dll.relative_to(dist_dir)
            name_lower = dll.name.lower()

            print(f"\n{size_mb:8.2f} MB  {dll.name}")
            print(f"           位置: {relative_path.parent}")

            # 优化建议
            suggestions = get_optimization_suggestion(name_lower)
            if suggestions:
                for suggestion in suggestions:
                    print(f"            {suggestion}")

    # 检查冗余 DLL
    print("\n" + "=" * 70)
    print(" 冗余检查")
    print("=" * 70)

    # 检查调试版本
    debug_dlls = [dll for dll, _ in dll_data if dll.stem.endswith('d')]
    if debug_dlls:
        print(f"\nWARNING:  发现 {len(debug_dlls)} 个调试版本 DLL(可以删除):")
        for dll in debug_dlls:
            print(f"  - {dll.name}")
    else:
        print("\nPASS: 未发现调试版本 DLL(已优化)")

    # VC++ Runtime
    vc_runtimes = [dll for dll, _ in dll_data if 'vcruntime' in dll.name.lower() or 'msvcp' in dll.name.lower()]
    if vc_runtimes:
        print(f"\n[VC++ Runtime 库] 发现 {len(vc_runtimes)} 个:")
        for dll in vc_runtimes:
            size_mb = dll.stat().st_size / 1024 / 1024
            print(f"  - {dll.name} ({size_mb:.2f} MB)")
        print("   这些是必需的,参考项目也包含了这些文件")

    # 全部 DLL 列表
    print("\n" + "=" * 70)
    print(" 完整 DLL 列表(按体积排序,前 20)")
    print("=" * 70)
    print(f"\n{'体积 (MB)':>10}  {'文件名':<30}  位置")
    print("-" * 70)

    for dll, size in dll_data[:20]:
        size_mb = size / 1024 / 1024
        relative_path = dll.relative_to(dist_dir)
        location = str(relative_path.parent) if relative_path.parent != Path('.') else "根目录"
        print(f"{size_mb:10.2f}  {dll.name:<30}  {location}")

    if len(dll_data) > 20:
        remaining_size = sum(size for _, size in dll_data[20:]) / 1024 / 1024
        print(f"... 还有 {len(dll_data) - 20} 个 DLL,共 {remaining_size:.2f} MB")


def get_optimization_suggestion(dll_name: str) -> list:
    """根据 DLL 名称给出优化建议"""
    suggestions = []

    if "openblas" in dll_name or "mkl" in dll_name:
        suggestions.append("数学运算库,参考项目的 libopenblas 有 26.85 MB")
        suggestions.append("如不需要高性能计算可考虑轻量版")

    elif "opencv" in dll_name or "ffmpeg" in dll_name:
        suggestions.append("OpenCV 相关,参考项目的 opencv_videoio_ffmpeg 有 18.48 MB")
        suggestions.append("考虑用 opencv-python-headless")

    elif "qt5" in dll_name or "qt6" in dll_name or "pyside" in dll_name:
        suggestions.append("Qt 库,参考项目的 Qt5Core 有 5.13 MB")
        suggestions.append("可排除不需要的模块(WebEngine, 3D, Charts)")

    elif "opengl" in dll_name and "sw" in dll_name:
        suggestions.append("OpenGL 软件渲染器,参考项目保留了 15.25 MB")
        suggestions.append("通常可以删除(使用硬件渲染)")

    elif "d3dcompiler" in dll_name:
        suggestions.append("DirectX 编译器,参考项目有 3.53 MB")

    elif "mfc140" in dll_name:
        suggestions.append("MFC 库,参考项目有 4.89 MB")

    return suggestions


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python analyze_dlls.py <dist目录路径>")
        print("示例: python analyze_dlls.py dist/main.dist")
        sys.exit(1)

    analyze_dlls(sys.argv[1])

Usage:

python analyze_dlls.py dist/你的软件名.dist

Complete optimization workflow

Step 1: Modify compilation script configuration

Edit build_optimized.bat, modify these 3 lines:

set APP_NAME=你的软件名      REM 改成实际名称
set MAIN_FILE=main.py        REM 你的主程序文件
set ICON_FILE=icon.ico       REM 你的图标文件

Step 2: One-click compilation + slimming

# 在项目根目录执行
build_optimized.bat

Step 3: Analyze DLL dependencies

python analyze_dlls.py dist/你的软件名.dist

Step 4: Optimize based on analysis results

If OpenCV is used → switch to the headless version

pip uninstall opencv-python
pip install opencv-python-headless

If Qt is used → exclude unnecessary modules

# 在编译命令中添加
--nofollow-import-to=PyQt5.QtWebEngine,PyQt5.Qt3D,PyQt5.QtCharts

Remove the software renderer(if not needed)

# 在 dist 目录执行
Remove-Item "opengl32sw.dll" -Force

VC++ Runtime Handling Options

Option 1: Static linking (recommended)

nuitka --static-libpython=yes ...

Option 2: Bundle the runtime installer (recommended for commercial release)

Add the following to the Inno Setup script:

; WARNING: VC++ 运行库架构必须与 Python/Nuitka 构建架构一致。
; 本 skill 推荐 32 位 Python,故默认捆绑 vc_redist.x86.exe;
; 若用 64 位 Python 编译,请把下面两处改为 vc_redist.x64.exe。
[Files]
Source: "{#MySourceDir}\..\vc_redist.x86.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall

[Run]
Filename: "{tmp}\vc_redist.x86.exe"; Parameters: "/quiet /norestart"; StatusMsg: "正在安装运行库..."; Flags: waituntilterminated

Download URL:Microsoft Visual C++ Redistributable


Inno Setup Script Template (Commercial Ultimate Edition)

; =====================================================================
;  WARNING: 商业级 Python 安装脚本 (Inno Setup 6.x)
;  特性:LZMA2 极限压缩 | 全中文 | 完整元数据 | 无残留卸载
;  参考:参考项目(323 MB, LZMA2 压缩)
; =====================================================================

; --- 1. 参数定义 ---
#define MyAppName        "{{APP_NAME}}"
#define MyAppVersion     "{{APP_VERSION}}"
#define MyAppPublisher   "{{PUBLISHER}}"
#define MyAppURL         "{{APP_URL}}"
#define MyAppExeName     "{{EXE_NAME}}"
#define MySourceDir      "{{SOURCE_DIR}}"
#define MyOutputDir      "{{OUTPUT_DIR}}"
;#define MyIconPath      "{{ICON_PATH}}"

[Setup]
; --- 身份识别 ---
AppId={{GENERATE_RANDOM_GUID}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}

; --- 安装路径与权限 ---
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableDirPage=no
DisableProgramGroupPage=no
PrivilegesRequired=admin

; --- 输出设置 ---
OutputDir={#MyOutputDir}
OutputBaseFilename=Setup_{#MyAppName}_v{#MyAppVersion}

; --- 视觉体验 ---
WizardStyle=modern
#ifdef MyIconPath
SetupIconFile={#MyIconPath}
UninstallDisplayIcon={app}\{#MyAppExeName}
#endif

; ---  核心压缩 (参考 参考项目) ---
Compression=lzma2/ultra64
SolidCompression=yes
LZMAUseSeparateProcess=yes

; --- 架构 ---
; 注意:仅 64 位 Python 构建才设此项。本 skill 推荐 32 位 Python——
; 32 位构建请保持注释,使应用按 32 位安装并与上面捆绑的 vc_redist.x86.exe 匹配。
; 仅当用 64 位 Python 编译时才取消注释。
;ArchitecturesInstallIn64BitMode=x64compatible

[Languages]
Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"

[Files]
Source: "{#MySourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[UninstallDelete]
Type: filesandordirs; Name: "{app}\*"

[Icons]
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\卸载 {#MyAppName}"; Filename: "{uninstallexe}"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent

Placeholder Description

Placeholder Description Example Value
{{APP_NAME}} Software display name 红墨批注
{{APP_VERSION}} Version number 1.0.0
{{PUBLISHER}} Publisher/Company name MyCompany
{{APP_URL}} Official website URL https://example.com
{{EXE_NAME}} Main program file name RedInk.exe
{{SOURCE_DIR}} Nuitka dist folder path D:\project\dist\RedInk.dist
{{OUTPUT_DIR}} Installer output path D:\project\output
{{ICON_PATH}} Icon file path D:\project\icon.ico
{{GENERATE_RANDOM_GUID}} A unique GUID must be generated Use Inno Setup "Tools > Generate GUID"

Frequently Asked Questions (FAQ)

Q1: After installation, double-clicking the program does nothing?

  1. Open CMD and run the exe manually to view the error message
  2. Check whether the VC++ runtime is missing
  3. Check whether Nuitka compilation succeeded

Q2: The installer package is too large?

Optimization methods:

  1. Compile with 32-bit Python (saves 20-30%)
  2. Apply the module exclusion list from the reference project
  3. Enable the Anti-Bloat plugin
  4. Run the dist folder slimming script
  5. Analyze DLLs and remove unnecessary large files

Q3: Antivirus false positives?

Solutions:

  • Submit to major antivirus vendors for whitelist application
  • Purchase a code signing certificate (recommended: Sectigo, DigiCert)
  • Avoid using UPX compression

Q4: During installation, it says Windows protected your PC?

  • Purchase an EV code signing certificate (trust can be obtained immediately)
  • A regular code signing certificate requires accumulating installation volume to gradually gain trust

Practical Issue Handling Record (Updated 2026-02-07)

  • After installation, it reports missing python3xx.dll: Nuitka must be used --standalone; confirm that the dll exists in dist; do not build a single-file version.
  • After installation, clicking does nothing: During GUI startup, it may be blocked by heavy dependencies; delay heavy dependencies until "Start Export" before importing; add logging for troubleshooting.
  • Nuitka + MinGW reports an error on non-ASCII paths: Copy the source code to an ASCII directory before compiling; set PYTHONIOENCODING=utf-8。
  • Inno Setup warning x64 is deprecated (only when 64-bit install mode is needed for 64-bit builds): change to ArchitecturesInstallIn64BitMode=x64compatible; 32-bit builds do not need this item.
  • --disable-console is deprecated: change to --windows-console-mode=disable。
  • dist contains _nuitka_temp.exe: exclude it in [Files].

Expected Optimization Results

Optimization Combination Size Reduction Startup Improvement Risk Level
Basic compilation Baseline Baseline None
+ --lto=yes 5-10% 10-20% PASS: None
+ anti-bloat 15-25% - PASS: None
+ Module exclusion 20-35% 5% PASS: None
+ dist slimming 25-40% - PASS: None
+ 32-bit compilation 40-60% - PASS: None
All combinations 45-65% 15-25% PASS: No risk

WARNING: UPX compression is not recommended, although it can further reduce the size, it is very likely to trigger antivirus false positives.


Optimized based on practical experience from the reference project, helping you build a commercial-grade installer!