第一次用PyInstaller打包Python项目时,我踩过的坑能绕地球三圈。记得当时要给客户部署一个OCR系统,依赖了PaddlePaddle、OpenCV这些重量级库,光是解决DLL缺失问题就折腾了两天。现在我把这些经验整理成保姆级教程,让你少走弯路。
虚拟环境是打包前的第一道保险。我强烈建议用conda创建独立环境,能有效避免库版本冲突。比如我的项目基于Python 3.7,就这样搭建环境:
bash复制conda create -n paddle_env python=3.7.9
conda activate paddle_env
pip install paddlepaddle opencv-python numpy
Windows平台有个隐藏雷区——VC++运行库。如果目标机器是Windows Server 2008这类老系统,务必安装VC++ 2015-2019运行库。我有次在客户现场调试到凌晨,最后发现就是缺了这个运行时组件。
Linux环境下更要注意glibc版本兼容性。曾经在Ubuntu 20.04打包的程序放到CentOS 7上就跑不起来,因为glibc版本不兼容。后来我改用CentOS 7作为打包环境才解决这个问题。
PyInstaller的-F和-D参数选择是个技术活。刚开始我觉得-F参数生成的单文件很酷,直到发现启动要等30秒——深度学习框架把exe撑到了800MB!后来改用-D参数,启动速度直接快10倍。
几个实用参数组合:
bash复制# 开发调试用(显示控制台输出)
pyinstaller -D your_script.py
# 生产环境用(隐藏控制台)
pyinstaller -w -D your_script.py
# 带自定义图标(图标需.ico格式)
pyinstaller -i logo.ico your_script.py
有个坑我踩了三次:UPX压缩。虽然它能减小包体积,但会导致某些加密算法异常。如果程序涉及加密解密,记得加--upx-exclude参数。
第一次打包生成的spec文件就像个黑盒子,现在我把它当救命稻草。遇到模块缺失时,hiddenimports能解决80%的问题。比如处理jieba分词时:
python复制a = Analysis(
hiddenimports=['jieba'],
...
)
但有些情况更棘手。有次打包包含statsmodels的项目,光加hiddenimports没用。后来发现要用Tree引入整个包:
python复制a.datas += Tree("/path/to/statsmodels", prefix="statsmodels")
DLL问题最让人头疼。上周处理PaddleOCR时,发现缺少paddle_inference.dll。解决方法是在binaries里添加库路径:
python复制binaries=[('C:/paddle/libs', '.')]
Windows Server 2008上的OpenCV问题让我记忆犹新。明明打包时正常,到服务器上就报错。最后发现要开启"桌面体验"功能:
Linux下的libpython缺失更常见。通过find命令定位so文件后,要在spec里指定路径:
bash复制find / -name libpython*.so # 查找具体路径
然后在spec中:
python复制binaries=[('/usr/local/lib', '.')]
Python 3.10有个专属坑——dis.py的bug会导致打包失败。解决方法是用文本编辑器打开dis.py,找到_unpack_opargs函数,按前文提到的代码修改保存。
Transformer模型的打包需要特殊处理。除了常规依赖,还要用copy_metadata引入元数据:
python复制from PyInstaller.utils.hooks import copy_metadata
datas = copy_metadata('transformers')
最后提醒:Linux打包前先装binutils,否则会报objdump缺失错误。在Ubuntu上很简单:
bash复制sudo apt install binutils