这里写目录标题
- 一级目录
- 二级目录
- 环境
- pyinstaller打包
- 配置.spec 文件
- windows server 2008 无法引入cv2
- ModuleNotFoundError (statsmodels)
- jieba(运行时,找不到dict.txt 或者 idf.txt)
- linux下, Error loading Python lib,not found xx.so
- linux下,缺少xx.so
- linux下,缺少整个包(如pykbase)
- linux下,打包transformer遇到 importlib.metadata.PackageNotFoundError: xxx问题
- python3.10打包,报错:IndexError: tuple index out of range
- 缺少binutils
一级目录
二级目录
三级目录
最近工作中需要将python打包成exe,我是用pyinstaller打包的,其他的没有试过。这期间查了不少帖子,遇到了不少坑,最终打包成功,并在其他windows机器上通过测试。一点经验之谈,希望可以帮助到更多人。
环境
我打包的python代码,依赖了paddle,opencv、numpy以及若干第三方库。打包的机器环境是win10,测试机器环境:win10和window server 2008,python环境3.7.9,并且使用了anconda的虚拟环境。
pyinstaller打包
pyinstaller比较重要的命令,-F,-D(默认方式,可不指定),-w
-F 把所有依赖的dll都打包到了exe中,缺点是启动巨慢,特别是依赖了深度学习框架等多种包后
-D 除了exe还会生成很多动态库,启动比-F方式要快很多,但是相比脚本执行,依然会慢很多
-w 不弹出终端
其他命令就不详细说了,有兴趣的朋友可以谷歌、百度一下。比如换图标等等
配置.spec 文件
第一次运行打包命令后,会生成xx.spec文件,如果打包后,exe成功启动,那我恭喜你。如果没有成功,就需要修改.spec文件了。
其实,打包后exe无法正常启动的原因就一个,缺少了dll。那么解决方式也就简单粗暴了,缺啥补啥!
至于缺啥,可以看看终端中输出的信息。我总结了一下,主要分为一下两种:
提示xxx包或者xx.dll not found
这种方式在hidden-import中引入缺失的包即可
提示 dll not found
这种不提示具体的dll的,就要看exe启动中报错的信息了,一般是因为动态编译方式引入的包没有打进去。在spec文件的 binaries中添加包所在的路径即可。
如:binaries=[(‘E:\Anaconda3\envs\paddleOCR\Lib\site-packages\paddle\libs’, ‘.’)]
windows server 2008 无法引入cv2
opencv-python成功安装后,无法import cv2的解决方法:在控制面板→程序和功能→打开关闭windwos功能→功能→添加功能中添加 桌面体检 功能。重启服务器,ok。
ModuleNotFoundError (statsmodels)
针对 no module named ‘statsmodels.tsa.statespace._filters’ 错误的解决方法
具体错误如下如所示:
解决方法:
修改spec文件
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['app.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a.datas += Tree("D:/Anaconda3/envs/textclf36/Lib/site-packages/statsmodels", prefix="statsmodels")
a.datas += Tree("D:/Anaconda3/envs/textclf36/Lib/site-packages/numpy", prefix="numpy")
a.datas += Tree("D:/Anaconda3/envs/textclf36/Lib/site-packages/pandas", prefix="pandas")
a.datas += Tree("D:/Anaconda3/envs/textclf36/Lib/site-packages/scipy", prefix="scipy")
a.datas += Tree("D:/Anaconda3/envs/textclf36/Lib/site-packages/dateutil", prefix="dateutil")
a.datas += Tree("D:/Anaconda3/envs/textclf36/Lib/site-packages/patsy", prefix="patsy")
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='app',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )
方法参考自文章:https://www.coder.work/article/1245029
statsmodels是 PyInstaller 的复杂模块之一,这是因为它依赖于一些其他模块,它们会弄乱 PyInstaller 导入图。我的解决方案可能看起来没有优化,但可以完成工作。
hidden-imports只会告诉 PyInstaller 查找该模块,但有时它无法跟踪模块依赖项(如 DLL、外部 py 文件等)。所以对于 statsmodels 它没有帮助。
整个过程是首先告诉 PyInstaller 不要使用 exclude-module 跟踪 statsmodels并将模块手动提供给最终的可执行文件。 此外,我们需要将一些模块(numpy、pandas 等)与 Tree 捆绑在一起。
jieba(运行时,找不到dict.txt 或者 idf.txt)
修改 spec 文件
datas=[('你的python库路径/jieba','jieba')],
# 如果datas与copy_metadata冲突,可以使用以下方式代替
a.datas += Tree("/home/nlp/anacondas/envs/server/lib/python3.8/site-packages/jieba", prefix="jieba")
linux下, Error loading Python lib,not found xx.so
# 1、获取xx.so路径
sudo find / -name libpython3.6m.so
# 2、在spec文件的 binaries中添加包所在的路径
# 此处,我使用textclf36虚拟环境进行打包,需要关联虚拟环境之内的包
binaries=[('/home/nlp/anaconda3/envs/textclf36/lib/','.')]
linux下,缺少xx.so
# 找到xx.so的具体路径
sudo find / -name libpython3.6m.so.1.0
# 通过binaries引入
binaries=[('/home/nlp/anaconda3/envs/textclf36/lib','.')]
linux下,缺少整个包(如pykbase)
a.datas += Tree("/home/nlp/anaconda3/envs/textclf36/lib/python3.6/site-packages/pykbase", prefix="pykbase")
linux下,打包transformer遇到 importlib.metadata.PackageNotFoundError: xxx问题
- 找到需要使用copy_metadata方法告知pyinstaller需要添加的数据文件,在你程序对应的python环境中查看需要拷贝的数据文件的包有哪些
from transformers.dependency_versions_check import pkgs_to_check_at_runtime
print(pkgs_to_check_at_runtime)
# ['python', 'tqdm', 'regex', 'sacremoses', 'requests', 'packaging', 'filelock', 'numpy', 'tokenizers', 'huggingface-hub','safetensors','pyyaml']
- 修改.spec文件:
添加以下代码
from PyInstaller.utils.hooks import collect_data_files, copy_metadata
datas = copy_metadata('tqdm')
datas += copy_metadata('torch') # torch与TensorFlow必须有一个,如果程序中用到
datas += copy_metadata('regex')
datas += copy_metadata('requests')
datas += copy_metadata('packaging')
datas += copy_metadata('filelock')
datas += copy_metadata('numpy')
datas += copy_metadata('tokenizers')
datas += copy_metadata('huggingface-hub')
datas += copy_metadata('safetensors')
datas += copy_metadata('pyyaml')
a = Analysis(...
datas=datas,
...)
python3.10打包,报错:IndexError: tuple index out of range
找到 C:\Users\Admin\AppData\Local\Programs\Python\Python310\Lib\dis.py 文件,修改这个函数
def _unpack_opargs(code):
extended_arg = 0
for i in range(0, len(code), 2):
op = code[i]
if op >= HAVE_ARGUMENT:
arg = code[i+1] | extended_arg
extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
else:
arg = None
extended_arg = 0
yield (i, op, arg)
缺少binutils
错误信息:
On Linux, objdump is required. It is typically provided by the ‘binutils’ package installable via your Linux distribution’s package manager.
解决方法:
apt install binutils
参考文章:https://www.dandelioncloud.cn/article/details/1565669150247055362