PyInstaller打包含PyQt5的脚本启动Mixxx时Qt平台插件加载失败
我开发了一个DJ自动化小程序,用PyInstaller编译脚本时,不导入PyQt5的话,打包后的exe能正常启动Mixxx;但取消PyQt5导入的注释后,运行exe会出现Qt平台插件qwindows.dll加载失败的错误,提示“无法找到指定过程”,导致Mixxx无法启动。
不导入PyQt5时,exe运行后Mixxx正常启动,日志显示加载了Mixxx自身的qwindows.dll等插件。问题仅出现在PyInstaller打包后、导入PyQt5并启动Mixxx的场景;单独打包仅含PyQt5导入的脚本或Qt Designer生成的pyuic5文件无错误,且导入PyQt5后启动其他程序(如calc)也正常。推测PyQt5的导入影响了C++ Qt编写的Mixxx的插件加载,求问题原因及解决方法?
相关代码
#from PyQt5 import QtCore, QtGui, QtWidgets from pywinauto.application import Application as PyWinAutoApplication from subprocess import Popen import time import os os.environ["QT_DEBUG_PLUGINS"] = "1" #Open mixxx Popen(r'C:\Program Files\Mixxx\mixxx.exe') #time.sleep(5) #mixxx_app = PyWinAutoApplication(backend="uia").connect(title="Mixxx") while(True): time.sleep(10)
错误日志
QFactoryLoader::QFactoryLoader() checking directory path "C:/Users/cpapp/OneDrive/???????????/dist/py_error_1/PyQt5/Qt5/plugins/platforms" ...
...
Cannot load library C:\Users\cpapp\OneDrive???????????\dist\py_error_1\PyQt5\Qt5\plugins\platforms\qwindows.dll: The specified procedure could not be found.
qt.qpa.plugin: Could not load the Qt platform plugin "windows" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized.
原因分析
核心问题是Qt库版本冲突:
- PyQt5自带一套独立的Qt库文件(包括
qwindows.dll),PyInstaller打包时会将这套库打包到exe的输出目录中。 - 当通过打包后的exe启动Mixxx时,系统会优先加载exe目录下PyQt5的Qt库,而非Mixxx自身安装目录下的Qt库。
- Mixxx是用特定版本的C++ Qt编译的,与PyQt5附带的Qt版本不兼容,导致
qwindows.dll中的关键函数无法被识别,触发插件加载失败。
解决方法
方法1:启动Mixxx前重置Qt相关环境变量
在调用Popen启动Mixxx前,修改环境变量,强制Mixxx优先加载自身目录下的Qt库:
from pywinauto.application import Application as PyWinAutoApplication from subprocess import Popen import time import os # 导入PyQt5 from PyQt5 import QtCore, QtGui, QtWidgets os.environ["QT_DEBUG_PLUGINS"] = "1" # 复制当前环境变量并重置Qt相关配置 env = os.environ.copy() # 移除PyQt5设置的Qt路径变量 env.pop("QTDIR", None) env.pop("QT_PLUGIN_PATH", None) # 将Mixxx安装目录放到PATH最前面,确保优先加载自身库 mixxx_dir = r'C:\Program Files\Mixxx' env["PATH"] = f"{mixxx_dir};{env['PATH']}" # 使用新环境变量启动Mixxx Popen(r'C:\Program Files\Mixxx\mixxx.exe', env=env) while(True): time.sleep(10)
方法2:延迟导入PyQt5
如果PyQt5的代码并非启动时必需,可以先启动Mixxx,等Mixxx加载完自身Qt库后再导入PyQt5:
from pywinauto.application import Application as PyWinAutoApplication from subprocess import Popen import time import os os.environ["QT_DEBUG_PLUGINS"] = "1" # 先启动Mixxx,给足加载时间 Popen(r'C:\Program Files\Mixxx\mixxx.exe') time.sleep(5) # 延迟导入PyQt5 from PyQt5 import QtCore, QtGui, QtWidgets # 后续PyQt5相关操作 mixxx_app = PyWinAutoApplication(backend="uia").connect(title="Mixxx") while(True): time.sleep(10)
方法3:修改PyInstaller打包配置隔离Qt库
- 生成打包配置文件:
pyi-makespec your_script.py - 打开生成的
.spec文件,调整binaries和pathex配置,将PyQt5的Qt库打包到独立子目录,避免干扰Mixxx的库加载路径;或者在打包时添加参数限制PyQt5库的优先级:
注:如果脚本需要使用PyQt5的UI组件,不要直接排除整个Qt5模块,仅需确保PyQt5的库不会覆盖系统对Mixxx库的加载优先级。pyinstaller --add-data "path/to/your/PyQt5/Qt5;PyQt5/Qt5" your_script.py
内容的提问来源于stack exchange,提问作者Chris P

