python(pyinstaller) 打包总结以及dll not found 、ModuleNotFoundError解决方法

一级目录

二级目录

三级目录

最近工作中需要将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问题

  1. 找到需要使用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']
  1. 修改.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

  • 17
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值