解决 matplotlib 打包为 exe 后闪退的问题

解决 matplotlib 打包为 exe 后闪退的问题

现象

最近将一段 python 算法打包为独立的 exe 后,发现会闪退,定位问题是调用 matplotlib.figure() 或 subplots() 等函数创建绘图窗口时就会闪退,没有任何错误提示。但奇怪的是在 PyCharm 开发环境中却能正常运行,没有问题。Python 版本是 2.7、使用 Anaconda 环境,用 PyInstaller 打包 exe。

解决方案

从网上找了一些相关问题的解决方案,说是要用新版本等等,逐一尝试,都失败了。例如下面这个失败的尝试:

删除 py27sgeo环境中的 matplotlib、pyqt 后,重新用 conda install 最新版本
结果:还是失败,会闪退。

分析发现,如果是在 conda env 环境下,即显示 activate py27的环境下,那么执行agg后端是可以成功,但不是在激活环境下,就会执行失败,会闪退,这是因为 PATH 环境变量在激活情况下会包含一些路径,如下:

set Path=E:\anaconda3\envs\py27;E:\anaconda3\envs\py27\Library\mingw-w64\bin;E:\anaconda3\envs\py27\Library\usr\bin;E:\anaconda3\envs\py27\Library\bin;E:\anaconda3\envs\py27\Scripts;E:\anaconda3\envs\py27\bin;E:\anaconda3\condabin;%PATH%

其中有需要用到的 DLL!继续排查,发现是这个目录起作用了

set PATH=E:\anaconda3\envs\py27\Library\bin

我们来看下这个目录下都有什么,原来是 python 运行环境的 DLL。于是想到可能是 DLL 缺失或者版本不对造成的。通过排除法,排除了 DLL 版本不对的原因,定位了 DLL 缺失是问题的根源。

具体的定位步骤如下。

拷贝一个文件试试,msvcr90.dll,失败。
复制全部的 dll 过去,成功!压缩后 7zip 文件大小为160MB。
删除其中Qt5*.dll,还可以成功!说明和Qt5没有关系了。
用 skip all 方式将 E:\anaconda3\envs\py27\Library\bin下的 DLL 复制到安装目录下,运行成功!说明是缺少 DLL!
不是 libjpeg.dll、vcomp90.dll、sqlite3.dll、svml_dispmd.dll、ssleay32.dll、pythoncomloader27.dll、atl90.dll、icu*.dll

最后发现是 lib*.dll 起作用了!
具体看是哪个 lib*.dll。

发现是 libiomp5md.dll这个DLL缺失了!

它是在用 conda install numpy 时添加的 dll !需要在打包 numpy 时加上的!是 Intel-Open-MP 并行计算库的 DLL!

这个 libiomp5md.dll是 Intel 的 OpenMP 加速计算库的,位于 E:\anaconda3\envs\<你的虚拟环境>\Library\bin 目录中,PyInstaller 打包时不会拷贝,需要手工复制到目标程序的根目录下,缺失的话就会导致打包后的程序运行闪退。

但是最好有办法让 PyInstaller 自动复制这个文件。
下面就是 PyInstaller 的 .spec 文件添加的内容,来自动拷贝libiomp5md.dll
如果是 exploded directory 的打包模式,还可以自动复制 Qt5Agg 所需的插件目录。

import os
import sys
python_root = os.path.dirname(sys.executable)

block_cipher = None

a = Analysis(['test\\test_plot_vline.py'],
             pathex=['.'],
             binaries=[],
             datas=[
                # add Intel OpenMP DLL, missing will cause numpy, 
                # fft or matplotlib crash application
                (python_root + '\\Library\\bin\\libiomp5md.dll', '.'),
                # add Qt5 windows plugin, only work for exploded directory mode
                (python_root + '\\Library\\plugins\\platforms', 'platforms')
             ],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)

用上面的 .spec 打包为目录执行模式是可以运行 Qt5Agg 后端的,但打包为单独 exe 文件会不工作。即便将 platforms 目录下的dll复制到 exe 打包文件的根下,也不行,这是 Qt 的约定,要从 exe 的目录下寻找插件 DLL,只能将 platforms/ 目录复制到 exe 同级目录下去使用,无法用 pyinstaller 打包到 exe 内部使用!

注意,如果不指定 matplotlib 的后端,默认就会用 Qt5Agg 后端,所以也需要如上进行额外处理。
如果使用 ‘agg’ 后端只生成绘图图片而不弹出绘图窗口进行交互的话,就不用管这个Qt5的插件 DLL 问题了。

参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值