PyInstaller;“无法找到或加载Qt平台插件”windows"。

10

我的 PyInstaller 规范:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['test.py'],
             pathex=['C:\\Users\\admin\\compile'],
             binaries=[('C:\\Python361\\Lib\\site-packages\\PyQt5\\Qt\\plugins\\platforms\\qwindows.dll', 'qwindows.dll')],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)

pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='test',
          debug=False,
          strip=False,
          upx=False,
          runtime_tmpdir=None,
          console=False , icon='icon.ico')

我遇到了问题,我用PyQt5 5.8.2(Python 3.6.1)编写的程序可以使用最新版本的pip安装的PyInstaller进行编译,并且可以在我的计算机上工作。静态链接的单文件可执行文件可以在我的电脑上正常运行。

但是,在任何没有设置Qt环境的计算机或虚拟机上测试它时,它在启动时崩溃,因为出现了“找不到或加载Qt平台插件“windows””错误。如果您查看spec文件,您会注意到我尝试手动将DLL存储在二进制列表中,以便PyInstaller将其存储在可执行文件中,但这并没有起作用。

我想知道需要更改什么,以便我可以编译我的应用程序,而无需像在可执行文件夹中包含平台文件夹那样做一些事情(我希望所有东西都在可执行文件中),难道只需改变spec文件中的某些内容,使其将DLL存储在可执行文件中?

顺便说一句,这不是重复的问题。我看了其他一些问题,但它们要么是针对不同类型的应用程序,要么解决方案是降级或将DLL存储在文件夹中,我都不能这样做。

编辑:所以我将其更改为onedir,只是为了看看它是否在里面,qwindows.dll位于文件夹内。还有一个名为qt5_plugins的文件夹,其中包含一个平台文件夹,该文件夹也包含一个qwindows.dll。所以它为什么无法检测到dll?


您可以尝试在pathex变量中添加这些库的路径。 - The4thIceman
刚刚尝试了一下,将pathex更改为['C:\Users\admin\compile', 'C:\Python361\Lib\site-packages\PyQt5\Qt\plugins\platforms'],但没有改变任何东西。 - J. Doe
另外,@The4thIceman,如果有影响的话,我是在一个干净的虚拟机上进行这个操作的。 - J. Doe
我修改了问题,因为我发现了一个重要的细节。 - J. Doe
6个回答

8

看起来有两个解决方案,第一个对我来说效果非常好:

  • 将platform目录复制到可执行文件的目录中。您可以在类似于c:\ Users \<username>\ envs \<environmentname>\ Library \ plugins \ platforms的位置找到平台目录或者

  • 升级到较新版本的pyqt:conda install -c anaconda pyqt

小心使用第二个选项:如果您有conda环境,请不要尝试使用pip进行pyqt安装,否则可能会破坏您的conda安装: https://github.com/ContinuumIO/anaconda-issues/issues/1970


3
我遇到了一个问题,我的Python代码可以正常工作,但编译后的.exe文件会出现“找不到或加载Qt平台插件Windows”的问题。我通过将使用pyinstaller --onedir main.py生成的程序目录中的~PyQt5\Qt\plugins\platforms文件夹复制到保存.exe文件的文件夹中来解决了这个问题。
看起来在我的情况下,“帮助”程序检测所需的.dll文件的唯一方法是将platforms文件夹放在main.exe旁边。在使用pyinstaller --onefile main.py后将platforms文件夹粘贴到程序目录中也可以使程序正常工作。

它对我起作用了。我有一个使用pyinstaller编译的“应用程序”,涉及matplotlibseaborn图形。可执行文件可以工作,但在弹出绘图时会出现错误。在Pycharm中运行Python脚本可以正常工作。我复制了位于C:\Anaconda3\Lib\site-packages\PyQt5\Qt\plugins的文件夹platforms-->问题解决了。 - Andrea

1
我刚刚将我的pyqt5软件包更新到5.10.1并修复了问题。

评论质量 - Mathews Sunny

1

我使用PyQt6 6.0.3和PyInstaller 4.3时遇到了同样的问题。

首先,我尝试了一个文件夹捆绑包,在将平台和样式插件添加到binaries列表和将PyQt6.sip添加到hiddenimports列表之后,它可以正常工作(如果使用PyQt6,则后者可能仅需要)。

当我尝试使用单个文件捆绑包时,出现了平台插件错误。首先,我检查了文件是否被复制到临时文件夹中(在运行时解压缩捆绑包时会打开错误对话框),所有DLL都在那里。当我将它们复制到可执行文件相同的文件夹中时,它可以正常工作,问题是Qt无法在临时文件夹中找到它们。

我在Qt文档中了解到QT_PLUGIN_PATH的解决方案,然后查看了此PyInstaller commit添加插件DLL后,只需添加运行时钩子以设置QT_PLUGIN_PATH 此外,如果使用UPX,则需要将插件DLL添加到upx_exclude列表中。
以下是我使用的钩子和spec文件,已删除默认选项:

pyQtHook.py

import os
import sys
from pathlib import Path

os.environ['QT_PLUGIN_PATH'] = str( Path( sys._MEIPASS ) / 'PyQt6/Qt6' )

oneFile.spec

from pathlib import Path

root = Path.cwd()
qtRoot = root / 'env/Lib/site-packages/PyQt6/Qt6'

analysis = Analysis(
    scripts = [
        root / 'src/main.py',
    ],
    pathex = [
        root,
        qtRoot / 'bin',
    ],
    binaries = [
        ( qtRoot / 'plugins/platforms/qwindows.dll', 'PyQt6/Qt6/plugins/platforms' ),
        ( qtRoot / 'plugins/styles/qwindowsvistastyle.dll', 'PyQt6/Qt6/plugins/styles' ),
    ],
    hiddenimports =[
        'PyQt6.sip',
    ],
    runtime_hooks = [
        'pyQtHook.py',
    ],
)

pyz = PYZ( analysis.pure, analysis.zipped_data )

exe = EXE(
    pyz,
    analysis.scripts,
    analysis.binaries,
    analysis.zipfiles,
    analysis.datas,
    name = 'MyApp',
    console = False,
    upx = True,
    upx_exclude = [
        'qwindows.dll',
        'qwindowsvistastyle.dll',
    ],
)

我也尝试了好几个小时,和你一样。但是还是无法解决这个错误… :-/ - Nils

0

在我几乎要炸裂的情况下,尝试解决这个问题后,我找到了一个适合我的解决方案。

在 SPEC 文件中,我添加了以下条款:upx_exclude=['qwindows.dll'],

结果发现,在 PyInstaller 的冻结过程中压缩此 DLL 时会导致其损坏。将 DLL 添加到 upx_exclude 条款可以防止出现此问题。

您可以在此处检查我的 SPEC 文件的一部分:

...

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='Hydro Tax Automation App',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=['qwindows.dll'],
          runtime_tmpdir=None,
          console=False)

0
这是一个老问题,但我已经寻找解决方案几天了,最终成功修复了它,而不必手动复制文件夹。 由于这个问题也使用了.spec文件,所以我认为这是正确的地方。 思路是.exe在路径./platforms/*.dll中查找.dll,因此我只需将所有的dll添加到spec文件中的binaries数组中,它们在bundle中的路径为platforms/*.dll。这是因为binaries是一个元组数组,第一个值是文件的路径,第二个值是bundle中的路径(基本上是.exe“容器”内部的路径)。
除此之外,顶部声明了mode: python,我认为这意味着它作为python脚本执行,因此应该支持变量、字符串和连接。因此,我的spec文件最终看起来像这样:
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

pf_foldr='C:\\Users\\Gabryxx7\\anaconda3\\envs\\<env_name>\\Library\\plugins\\platforms\\'

a = Analysis(['C:\\Users\\Gabryxx7\\PycharmProjects\\<proj_name>\\program.py'],
             pathex=['C:\\Users\\Gabryxx7\\PycharmProjects\\<proj_name>\\'],
             binaries=[(pf_foldr+'qwindows.dll', 'platforms\\qwindows.dll'),
             (pf_foldr+'qdirect2d.dll', 'platforms\\qdirect.dll'),
             (pf_foldr+'qoffscreen.dll', 'platforms\\qoffscreen.dll'),
             (pf_foldr+'qwebgl.dll', 'platforms\\qwebgl.dll')
             ],
             datas=[],
             hiddenimports=['GUI', 'API', 'Threading', 'ssl', 'pyodbc'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='programName',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True ) # False to avoid the console

我之前尝试了网上找到的所有解决方案:设置环境变量QT_QPA_PLATFORM_PLUGIN_PATH,重新安装Anaconda,更新所有软件包,尝试使用PyPi版本和无虚拟环境,但都没有起作用。最后,复制带有dllsplatforms文件夹解决了问题,编辑spec文件以避免手动步骤也起了作用。

1
在使用winx64、Python 3.7.x、venv + pyside6时,似乎出现了问题。 - Dariusz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接