Windows Python 打包实战:Nuitka 环境踩坑总结与 CI 自动化构建全指南

环境检测(是否依靠 exe 运行)

有些功能(如开机自启动)可能需要限制在依靠 exe 运行的情况,相信很多开发者第一反应就信手拈来 sys.executable 侦测:

isExe = sys.executable.lower() not in ('python.exe', 'pythonw.exe') # Wrong!

但是!Nuitka 构建之后的 sys.executable 很可能稳定指向 python 解释器的路径,这个方法是不可靠的!正确解法:Nuitka 构建完毕后会注入变量 compiled 为 True。

isExe = globals().get("compiled ", False) # Correct

Pyinstaller 打包是通过在 sys 下设置 frozen = True,所以如果你想要更强的兼容性

Ultimate Solution

import sys

def isExe() -> bool:

isNuitkaExe = globals().get("compiled ", False)

isPyInstallerExe = getattr(sys, "frozen", False)

return isNuitkaExe or isPyInstallerExe

CI 配置

如果要使用 Github Actions 构建 Nuitka 应用,仅仅将本地命令搬上去很可能会报错。

需要添加 --assume-yes-for-downloads 命令参数:--standalone 模式在 Windows 上需要 Dependency Walker。本地可能已在交互环境配置完毕;而 CI 非交互环境下默认选 "no" 导致 FATAL。

环境变量注入

Meta Assistant 是一款托盘工具,用于图形化地用子进程启动特定目录下的 Python 脚本而不需要每次进入命令行输入,其使用了 Tkinter 的文件目录选择器功能。

然而,诡异的事情发生了:

环境:本地 Python 3.11;Github CI Python 3.12

本地直接用 python 运行脚本:能够成功启动所有脚本

本地 Nuitka 构建:能够成功启动所有脚本

运行从 CI 下载的打包产物:所有调用子进程 Tkinter 的功能均告失效!

经过数小时的排查,最终确认:

Nuitka exe 注入了环境变量,随 Popen 注入到下游子脚本,与其他脚本的环境不一致,造成崩溃!

罪魁祸首:

TCL_LIBRARY = E:\META-A~1\tcl(Tcl 8.6.12)

TK_LIBRARY = E:\META-A~1\tk(Tk 8.6.12)

这个故事告诉我们,Nuitka 构建后如果设计"运行子进程",务必先检查自动注入的环境变量,及时去除,防止崩溃!

对于接入了 Tkinter 的工具,推荐加入下面的函数:

import os

import subprocess

def get_clean_env():

env = os.environ.copy()

移除 Nuitka 强制注入的环境变量,让子进程回归系统默认 Tcl/Tk 查找逻辑

env.pop("TCL_LIBRARY", None)

env.pop("TK_LIBRARY", None)

return env

subprocess.Popen("python", "sub_script.py", env=get_clean_env())

后记:SKILL.md

我一直坚持手动复制 SKILL 喂给 AI,这个 SKILL 文档浓缩了各种一路上 AI 犯过的错误,供读者放到本地复用,节省一个小时。


name: nuitka-build

description: Please read this if you are configuring GitHub Actions for Python project builds.

Dependency Walker 下载被拒

--standalone 模式在 Windows 上需要 Dependency Walker,CI 非交互环境下默认选 "no" 导致 FATAL。

必须添加 --assume-yes-for-downloads 或在环境中设置 NUITKA_ASSUME_YES_FOR_DOWNLOADS=1。

Release 403 错误

softprops/action-gh-release 创建 Release 时 403,原因是默认 GITHUB_TOKEN 只有 contents: read。

修复:在 release workflow 顶部添加 permissions: contents: write。

Windows runner 没有 zip 命令

windows-latest 上没有 Unix zip 命令,用 zip -r 会报错。

修复:使用 PowerShell 的 Compress-Archive -Path <source> -DestinationPath <output.zip>。

sys.executable 在新版 Nuitka 中不可靠

编译后 sys.executable 可能指向 Python 解释器而非 exe 路径,Path(sys.executable).name 检测失效。

修复 :改用 Nuitka 编译时注入的 __compiled__:

python 复制代码
if not globals().get("__compiled__", False):
    return  # 开发模式,跳过 exe 专属逻辑

--windows-installer 不存在

Nuitka没有 --windows-installer 这个选项。需要用安装包时,分两步:

  1. Nuitka 编译为 --standalone(产生 .dist 目录)
  2. 用 Inno Setup(iscc)配合 .iss 脚本打包
yaml 复制代码
- run: python -m nuitka --standalone ... --output-dir=dist ...
- run: iscc /DAPP_VERSION="${{ github.ref_name }}" installer.iss

ISS 脚本版本号用预处理器变量

GetEnv() 取的是系统环境变量,不是 /D 传入的预处理器变量。正确用法:

iss 复制代码
; ❌ GetEnv 读不到 /D 参数
AppVersion={#APP_VERSION}  ; ✓ 预处理器变量

Workflow 传值:

yaml 复制代码
- run: iscc /DAPP_VERSION="${{ github.ref_name }}" installer.iss

ISS AppId 要用真 UUID

AppId 不能随手编,每个项目必须用以下命令生成新的唯一 ID:

powershell 复制代码
python -c "import uuid; print(str(uuid.uuid4()).upper())"

生成后固定写死到 .iss。

--windows-icon-from-ico

Nuitka 真实选项,给 exe 设图标,支持 .ico 或 .png 格式,Nuitka 自动转换:

yaml 复制代码
--windows-icon-from-ico=assistant.ico
相关推荐
协皓家具3 小时前
2026年广州岛台吧台椅厂家有啥新变化
大数据·运维·python·devops
yuniko-n3 小时前
【Java】字符串相关坑点
java·开发语言·python
用户019027581613 小时前
如何用 Python 统计 A 股连续涨停(几连板)?
python
外收内放3 小时前
Python基础语法练习题(拓展1)
python·游戏
H_unique4 小时前
Chat2Excel:接口自动化测试
python·测试工具·自动化
ss2734 小时前
AI全栈实战 | 3.3-02 Python 并发:有 GIL 为什么还用多线程,asyncio 和 JS 事件循环同源不同味
开发语言·javascript·python
空心木偶☜4 小时前
Langgraph操作时常见的错误
python·ai·ai编程·langgraph
cpolar技术支持4 小时前
外网测试机的异常传不回内网?自托管 Sentry,用 cpolar 打通错误上报链路
python·nginx·docker·cpolar·sentry
小小龙学IT4 小时前
Python SQLAlchemy 2.0 深度解析:从 Core 到 ORM 的数据访问双引擎
开发语言·数据库·python
2601_962885724 小时前
如何用 Python 计算 ROC 变动率指标做动量分析?
开发语言·python·算法