【Pyinstaller+Pyside6】打包后运行错误 ImportError: DLL load failed while importing pyexpat: 找不到指定的模块 临时解决方法
本人使用Anaconda的一个虚拟环境(名称为py3.11),在项目根目录下使用venv包创建了专用于 Pyside6 项目开发的虚拟环境(目录为.\venv),利用旧电脑上生成的使用 pip 重新安装新环境。环境装好后,项目直接使用运行没有任何问题,但在使用打包后,运行dist下的 exe 可执行文件,程序直接闪退。的spec核心报错信息为:ImportError: DLL load faile
项目场景 & 问题描述:
由于更换电脑,本人将 Pyside6 工程项目迁移到新电脑(均为 Windows11 系统)。本人使用 Anaconda
的一个虚拟环境(名称为 py3.11
),在项目根目录下使用 venv
包创建了专用于 Pyside6 项目开发的虚拟环境(目录为 .\venv
),利用旧电脑上生成的 requirements.txt
使用 pip 重新安装新环境。
requirements.txt
内容如下:
altgraph==0.17.4
astroid==3.0.3
autopep8==2.0.4
colorama==0.4.6
contourpy==1.2.1
cycler==0.12.1
dill==0.3.8
docstring-to-markdown==0.15
flake8==7.0.0
fonttools==4.51.0
imageio==2.34.0
importlib-metadata==7.0.1
isort==5.13.2
jedi==0.19.1
kiwisolver==1.4.5
lazy_loader==0.3
llvmlite==0.42.0
matplotlib==3.8.4
mccabe==0.7.0
networkx==3.2.1
numba==0.59.1
numpy==1.26.4
opencv-python==4.9.0.80
packaging==23.2
parso==0.8.3
pefile==2023.2.7
pillow==10.2.0
platformdirs==4.2.0
pluggy==1.4.0
pycodestyle==2.11.1
pydocstyle==6.3.0
pyflakes==3.2.0
pylint==3.0.4
pyparsing==3.1.2
PySide6==6.6.2
PySide6_Addons==6.6.2
PySide6_Essentials==6.6.2
python-dateutil==2.9.0.post0
python-lsp-jsonrpc==1.1.2
python-lsp-server==1.10.0
pytoolconfig==1.3.1
pywin32-ctypes==0.2.2
PyYAML==6.0.1
rope==1.12.0
scikit-image==0.22.0
scipy==1.12.0
shiboken6==6.6.2
six==1.16.0
snowballstemmer==2.2.0
tifffile==2024.2.12
tomli==2.0.1
tomlkit==0.12.4
ujson==5.9.0
whatthepatch==1.0.5
yapf==0.40.2
zipp==3.17.0
环境装好后,项目直接使用 venv\Scripts\python.exe -u main.py
运行没有任何问题,但在使用 Pyinstaller
打包后,运行 dist
下的 exe 可执行文件,程序直接闪退。
Pyinstaller
的 spec
文件内容为:
# -*- mode: python ; coding: utf-8 -*-
# from PyInstaller.utils.hooks import collect_submodules
a = Analysis(
['mainwindow.py'],
pathex=[],
binaries=[],
datas=[('icons', 'icons'),('fonts','fonts'),('config.yaml', '.'),('log_update','.')],
hiddenimports=['skimage'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='xxx',
contents_directory='.',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='icons/xxx.ico',
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='xxx',
)
exe 的报错信息(使用命令行运行 exe 可观测到报错信息)如下:
Traceback (most recent call last):
File "PyInstaller\hooks\rthooks\pyi_rth_pkgres.py", line 170, in <module>
File "PyInstaller\hooks\rthooks\pyi_rth_pkgres.py", line 37, in _pyi_rthook
File "PyInstaller\loader\pyimod02_importers.py", line 384, in exec_module
File "pkg_resources\__init__.py", line 42, in <module>
File "PyInstaller\loader\pyimod02_importers.py", line 384, in exec_module
File "plistlib.py", line 70, in <module>
File "PyInstaller\loader\pyimod02_importers.py", line 384, in exec_module
File "xml\parsers\expat.py", line 4, in <module>
ImportError: DLL load failed while importing pyexpat: 找不到指定的模块。
[PYI-74984:ERROR] Failed to execute script 'pyi_rth_pkgres' due to unhandled exception!
核心报错信息为: ImportError: DLL load failed while importing pyexpat: 找不到指定的模块。
旧电脑上没有遇到该问题。
原因分析:
重装环境、查遍互联网,网友提出了很多解决方案,包括但不限于:
-
更新所有包,包括改变
Pyinstaller
、setuptools
版本(没用) -
指定
Pyinstaller
的path
参数为缺失的 DLL 路径--path
参数、spec
文件中的pathex
路径)(没用) -
指定
datas
、binaries
为 DLL 路径(不完全有用)将缺失的 DLL 文件全部加入
binaries
也可以,但不够优雅。请见后文分析。 -
hiddenimports
引入 exe 运行时报错的包(没用) -
其它奇奇怪怪的方法(
安装 Microsoft Visual C++ 2015 ???)
看来只能自行分析了(汗)。本人进入虚拟环境后,执行 import pyexpat
没有报错,说明库是正常安装的(而且 python 运行项目也没有报错),问题可能出在 Pyinstaller
。
检查 Pyinstaller
打包时的输出信息,发现在加载部分包时,丢失 DLL 文件:
116385 WARNING: Library not found: could not resolve 'ffi-8.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_ctypes.pyd'.
116386 WARNING: Library not found: could not resolve 'libcrypto-3-x64.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_hashlib.pyd'.
116386 WARNING: Library not found: could not resolve 'liblzma.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_lzma.pyd'.
116386 WARNING: Library not found: could not resolve 'libbz2.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_bz2.pyd'.
116387 WARNING: Library not found: could not resolve 'libcrypto-3-x64.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_ssl.pyd'.
116387 WARNING: Library not found: could not resolve 'libssl-3-x64.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_ssl.pyd'.
116388 WARNING: Library not found: could not resolve 'libexpat.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\pyexpat.pyd'.
116388 WARNING: Library not found: could not resolve 'tcl86t.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_tkinter.pyd'.
116388 WARNING: Library not found: could not resolve 'tk86t.dll', dependency of 'D:\\Software\\anaconda3\\envs\\py3.11\\DLLs\\_tkinter.pyd'.
116389 WARNING: Library not found: could not resolve 'tbb12.dll', dependency of '项目路径\\venv\\Lib\\site-packages\\numba\\np\\ufunc\\tbbpool.cp311-win_amd64.pyd'.
推测是 libexpat.dll
等关键 DLL 文件在 Anaconda
路径 D:\\Software\\anaconda3\\envs\\py3.11\\DLLs
无法找到 。
本人在项目的虚拟环境目录 .\venv
下搜索缺失的 DLL 文件,确实无法找到(不明原因),但在 Anaconda
环境中找到了这些 DLL 文件,路径为 D:\\Software\\anaconda3\\envs\\py3.11\\Library\\bin\\
,说明 Pyinstaller
找错地方了(不明原因)。
在 Pyinstaller
的输出信息中,观察 INFO: Extra DLL search directories (AddDllDirectory)
和 INFO: Extra DLL search directories (PATH)
路径,发现搜索路径不包含 D:\\Software\\anaconda3\\envs\\py3.11\\Library\\bin\\
,说明可能是路径错误导致找不到 DLL 文件。
- 一种解决方法是将缺失的 DLL 文件全部加入
Pyinstaller
的 binaries 中,但不太优雅;- 另一种方法是希望
Pyinstaller
自动查找缺失的 DLL 文件。查遍互联网,暂未找到如何将 DLL 路径加入AddDllDirectory
的方法,但是我们可以加入PATH
,曲线救国。
解决方案:
方法一(不太优雅):
在 spec
文件开头加上:
PYTHON_DLL_PATH = "D:\\Software\\anaconda3\\envs\\py3.11\\Library\\bin\\"
addition_dlls = ['libexpat.dll', 'liblzma.dll', 'libbz2.dll', 'libcrypto-3-x64.dll', 'libssl-3-x64.dll', 'ffi-8.dll', 'tk86t.dll', 'tcl86t.dll', 'tbb12.dll']
addition_binaries = [(f"{PYTHON_DLL_PATH}", dll) for dll in addition_dlls]
其中 addition_dlls
包含 Pyinstaller
找不到的 DLL 文件名,PYTHON_DLL_PATH
更换为读者自己的 Anaconda
虚拟环境的 Library\\bin
路径。
然后 binaries
赋值为:
a = Analysis(
...
binaries=addition_binaries,
...
)
再执行 pyinstaller xxx.spec
打包。
方法二(比较优雅):
将 DLL 路径临时加入系统 PATH
环境变量,即在 spec
文件开头加上:
import os
os.environ['PATH'] = f"{os.environ['PATH']};D:\\Software\\anaconda3\\envs\\py3.11\\Library\\bin\\"
DLL 路径 更换为读者自己的 Anaconda
虚拟环境的 Library\\bin
路径。
再执行 pyinstaller xxx.spec
打包。
运行 dist
下的 exe 文件,正常运行。
思考:
按理说 Pyinstaller
不应找不到 DLL 文件,且 DLL 文件竟然都在 Anaconda
环境中、而非项目的虚拟环境 .\venv
中,本人尚未知晓原因。以上方法仅为权宜之计,治标不治本,若有更好方法欢迎评论区交流。
更多推荐
所有评论(0)