nuitka打包windows exe程序实战教程及问题分析解决过程
样例代码:
代码的主要功能是定时修改指定目录下的文件扩展名,具体代码细节无关重要。
具体步骤:
1. 创建app.py文件并保存以下内容:
"""
定时更新指定目录下的所有文件的扩展名
重要:windows下config.ini文件保存为utf-8编码格式,不要保存为utf-8 bom.
"""
import configparser
import os
import schedule
import time
from datetime import datetime
def change_extension(directory, recursive):
if not os.path.isdir(directory):
print(f"目录不存在: {directory}")
return
for item in os.listdir(directory):
item_path = os.path.join(directory, item)
if os.path.isdir(item_path) and recursive:
change_extension(item_path, recursive)
elif os.path.isfile(item_path):
filename, ext = os.path.splitext(item_path)
if ext.lower() == '.mc4':
new_name = filename + '.mc5'
try:
os.rename(item_path, new_name)
print(f'>>>修改扩展名: {item_path} -> {new_name}')
except Exception as ex:
print(f'!!!修改扩展名失败: {item_path}, 具体错误: {ex}')
def scheduled_task(directory, recursive):
format_str = '%Y-%m-%d %H:%M:%S'
print(f'---定时任务开始: {datetime.now().strftime(format_str)}')
change_extension(directory, recursive)
print(f'---定时任务结束: {datetime.now().strftime(format_str)}')
def read_config():
default_directory = 'E:\mc_files'
default_interval = 60
default_recursive = False
config = configparser.ConfigParser()
try:
config.read('config.ini', encoding='utf-8')
recursive = config.getboolean('Settings', 'recursive', fallback=default_recursive)
interval = config.getint('Settings', 'interval', fallback=default_interval)
directory = config.get('Settings', 'directory', fallback=default_directory)
except Exception as e:
print(f"读取配置错误: {e}")
recursive = default_recursive
interval = default_interval
directory = default_directory
return directory, recursive, interval
def run():
directory, recursive, interval = read_config()
print(f'配置:检查目录 -> {directory}, 是否递归 -> {recursive}, 定时间隔 -> {interval}秒')
# 设置定时任务
schedule.every(interval).seconds.do(scheduled_task, directory, recursive)
print("按 Ctrl+C 退出程序.")
scheduled_task(directory, recursive) # 马上开始
try:
while True:
schedule.run_pending()
time.sleep(1) # 确保不会占用过多 CPU
except KeyboardInterrupt:
print("退出...")
if __name__ == '__main__':
run()
2. 创建一个新的虚拟环境(我这里是python 3.11.9),并安装以下模块:
Package Version
----------- -------
Nuitka 2.8.9
ordered-set 4.1.0
pip 23.2.1
schedule 1.2.2
setuptools 68.2.0
wheel 0.41.2
zstandard 0.25.0
3. 由于我是使用msvc编译C++的,所以已经预装好visual studio 2022,和windows(11) sdk。如果使用其他c++编译器的请自行进行相应配置。
4. 执行打包命令,进入到虚拟环境,执行以下命令打包为单文件的可执行程序
nuitka --standalone --onefile --output-filename=update_ext.exe app.py
备注:上述命令第一次执行时,会下载相关工具,所以会较慢。
命令成功执行后,会生成update_ext.exe文件。
5. 如果要生成32位的可执行程序,该如何做?
要创建32位的可执行程序,只需要安装32位的python版本,并使用该版本创建一个新的虚拟环境,然后进入到该环境并重新执行前面的nuitka命令即可,操作系统不必是32位的系统。
遇到问题及分析过程:
由于我最终的目标是需要生成32位exe程序在32位的windows 7(sp1)上运行,所以我需要在开发机(具体环境为win11 24h2 64位,visual studio 2022, python 3.11 64位)上创建一个32位的可执行程序,名字为update_ext32.exe,具体创建步骤不再赘述。
问题(1): update_ext32.exe部署到一个全新的windows 7 32位系统时,出现以下错误:无法启动此程序,因为计算机中丢失vcruntime140.dll。尝试重装安装该程序以解决此问题。
如下图所示:

解决办法(1)【不成功】
安装Visual C++ Redistributable v14,可从这里下载:https://aka.ms/vc14/vc_redist.x86.exe
但安装失败,从错误日志可以看到,得windows10或以上的系统才能安装,如下图所示:

解决办法(2)【不成功】
由于开发机vs 2022带的msvc版本为14.5, 所以尝试降一下编译时的vc版本看看
1. 先安装vs_BuildTools.exe,这是编译工具。不是vc redist,那个是运行时库。原始下载链接没有,可试试这里下载vs setup来安装msvc v140组件:Visual Studio 旧版下载 - 2019、2017、2015
安装时,只选msvc v14.0即可,如下图所示:

安装完成后,重新进入虚拟环境执行nuitka命令,加入--msvc=14.0参数,具体命令为:
nuitka --standalone --onefile --output-filename=update_ext32.exe --msvc=14.0 app.py
执行命令后,出现了错误:Nuitka-Scons: For Python version 3.11 MSVC 14.3 or later is required, not 14.0 which is too old.
FATAL: Error, cannot locate suitable C compiler. You have the following options:... 如下图所示:

2. 尝试将python版本降为3.10,使用python 3.10 32位创建一个新的虚拟环境,并重新安装上述的pip模块,然后再重新执行上述相同的nuitka命令:
nuitka --standalone --onefile --output-filename=update_ext32.exe --msvc=14.0 app.py
拿到部署机器上运行(windows 7 32位),也是同样之前的报错:无法启动此程序,因为计算机中丢失vcruntime140.dll。尝试重装安装该程序以解决此问题。而windows 7是不支持vc redist 14的,所以也不要指望安装该分发包来解决dll加载问题了。
3. 由于中间过程尝试过的方案太多,无非就是不停地换python版和安装不同的vs尝试罢了,具体细节不再赘述了。
3.1 一些失败的方案:
(1) vs 2010和python 3.10 32位,具体报错忘了
(2) mingw64和python 3.10 32位,无法启动此程序,因为计算机中丢失 api-ms-win-core-path-l1-1-0.dll。尝试重新安装该程序以解决此问题。 (大概原因是使用了高版本windows的win api, 在低版本的操作系统上不存在)
解决办法(3)【成功】
4. 最后成功的方案,将python降到3.8 32位版本创建新的虚拟环境,加入mingw64参数进行编译即可,最后命令如下:
nuitka --standalone --onefile --output-filename=update_ext32.exe --mingw64 app.py
其实早该直接使用mingw64参数来尝试,当时因为不熟这个,没去浅尝一下,导致兜了一大圈。
成功运行:

5. 其他可能方案,直接windows 7 32位做开发机进行打包编译
其他备注:
(1) 使用常规的msvc打包编译后,放在windows 7系统,出现错误:无法定位程序输入点 AddDllDirectory 于动态链接库 KERNEL32.dll
原因分析:因为是在win11打包的,用到了较新的api,而win7等旧系统没有这些windows api。
解决办法:看看有没有设置能降低版本使用旧api打包?例如msvc=10.0等
(2) 打包后放在win10(64位),一个全新的系统,没有安装任何的开发环境,出现错误:由于找不到VCRUNTIME140.dll,无法继续执行代码
解决办法: (1) 在系统上安装vc++库,如果程序是64位的,要安装VC_redist.x64.exe(64位的,大小为24MB)
如果程序是32位的,要安装VC_redist.x86.exe(32位,大小为6.5MB)
如果要同时运行32位版本和64位版本的update_ext程序,即两个VC_redist程序都要安装。
(3) 或者打包编译时把vc相关模块也弄进去。不要使用--onefile参数,那样就能打包进vcruntime140.dll, 但是这样的话就会附带一个文件夹,不再是单个文件了。
参考:https://github.com/Nuitka/Nuitka/issues/3583
相关参考:
Latest supported Visual C++ Redistributable downloads | Microsoft Learn
Would it be possible to enable cross-compilation ? · Issue #43 · Nuitka/Nuitka
How to build windows xp apps using nuitka? · Issue #110 · Nuitka/Nuitka
Nuitka listing MSVC, but not using it? · Issue #3317 · Nuitka/Nuitka
更多推荐


所有评论(0)