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 -*- |