pyinstaller
这个打包库最大的好处是
会自动分析项目的依赖,比较智能方便。
其他的诸如
cx_Freeze、py2exe、nuitka都不是开箱即用的,都不如pyinstaller智能,这里就不再推荐。
查看版本
1  | pyinstaller --version  | 
卸载
1  | pip uninstall pyinstaller  | 
安装pyinstaller
1  | pip install pyinstaller==6.11.1  | 
Win上打包
1  | pyinstaller main.py -y --windowed  | 
设置ico
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico"  | 
单文件
1  | pyinstaller main.py -y -F --noconsole --name="xh-marking-client" --icon="logo.ico"  | 
注意
在Win上
--windowed和--noconsole作用一样,但是--windowed只能在Win上用,--noconsole还可以在Linux上打包。
关于打包报毒
每次打包的时候,
Windows 安全中心都报毒,生成的EXE文件就被删了,经过测试发现这个误报只会生成的时候误报,所以我们设置例外就行了。实测生成EXE后在其他设备上也是不会再误报了。
常见问题
pyzbar的DLL没有正常导入
pyinstaller 可能没有正确检测到 pyzbar 的隐藏导入,导致打包后程序找不到相关模块。
先运行一次打包生成xh-marking-client.spec文件
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico"  | 
修改xh-marking-client.spec如下部分datas中的内容
1  | a = Analysis(  | 
重新打包
1  | pyinstaller -y xh-marking-client.spec  | 
DLL引用
添加项目下dll
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico" --add-binary "dll\twain\32\TWAINDSM.dll;."  | 
上面这种方式TWAINDSM.dll会放在_internal目录中,这样虽然路径变了,但是_internal根路径的DLL因为可以正常加载,所以可以正常使用。
打包添加文件夹
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico" -D --add-binary "dll;dll"  | 
上面这种方式dll文件夹会放在_internal目录中,这样路径变了,根据路径加载的dll会无法加载。
其中
 -D 或 --onedir 选项时,PyInstaller 会把所有依赖项和资源文件组织到一个单独的目录中,而不是将它们打包进一个单一的可执行文件里。
该目录会包含主可执行文件以及程序运行所需的所有支持文件,像动态链接库(DLL)、Python 运行时库、数据文件等。
添加配置和图标
自 Pyinstaller>=6.0.0 版本后,在打包 one dir(-D 目录模式)时,除可执行文件外,其余文件都将被转移到 _internal 文件夹下
并且添加文件的时候我们也不能使用类似这样的写法--add-data "config.ini;.."来达到放在exe同级的目的,会报错
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico" -D --add-data "*.ini;." --add-data "logo.ico;."  | 
这会导致添加的配置文件和exe不在同级目录,读取配置会有问题
可以添加--contents-directory .参数恢复到之前的模式(注意此参数生效需要 pyinstaller>=6.1.0)
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico" --contents-directory . --add-data "config_app.ini;." --add-data "logo.ico;."  | 
另一种方法是降低pyinstaller版本,pyinstaller < 6.0.0
过滤DLL
PyInstaller 打包基本流程
PyInstaller 的打包过程主要包含以下关键阶段:
- 分析阶段(Analysis):PyInstaller 会分析主脚本及其依赖项,确定需要打包的所有 Python 模块、二进制文件(像 DLL)、数据文件等。此阶段会构建一个依赖图,明确各文件间的依赖关系。
 - 收集阶段(Collection):基于分析阶段的结果,PyInstaller 会收集所有必需的文件,包含 Python 模块、DLL 文件、数据文件等,并将它们复制到临时目录。在这个阶段,DLL 文件会被复制到相应位置。
 - 打包阶段(Packaging):将收集到的文件打包成一个或多个可执行文件,这可能涉及将文件压缩、加密等操作。
 - 运行时钩子执行阶段:当运行打包生成的可执行文件时,
--runtime-hooks指定的钩子文件会在 Python 解释器启动之后、主脚本执行之前运行。 
方式1
打包,同时会自动生成spec文件
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico"  | 
修改spec文件
1  | # -*- mode: python ; coding: utf-8 -*-  | 
使用修改后的spec文件打包
1  | pyinstaller xh-marking-client.spec --clean -y  | 
方式2(无效)
注意
这种方式我测试的没有效果,应该时钩子执行了,但是PySide2还有其他的钩子,执行顺序的原因导致没有效果。
创建一个钩子文件来排除指定的 DLL 文件。
步骤:
创建钩子文件:在项目目录下创建一个名为 hook-PySide2.py 的文件,内容如下:
1  | # hook-PySide2.py  | 
使用钩子文件进行打包:
1  | pyinstaller --additional-hooks-dir=. main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico"  | 
添加DLL
先运行
1  | pyinstaller main.py -y --noconsole --name="xh-marking-client" --icon="logo.ico" --contents-directory . --add-data "*.ini;." --add-data "logo.ico;."  | 
这会生成xh-marking-client.spec文件
修改该文件
1  | a = Analysis(  | 
修改后以后打包都使用下面的的命令
1  | pyinstaller -y xh-marking-client.spec  | 
整体配置
1  | # -*- mode: python ; coding: utf-8 -*-  | 
管理员身份运行
在.spec文件的 EXE参数中添加uac_admin=True
如下
1  | exe = EXE(  |