【问题标题】:PyInstaller; "could not find or load the Qt platform plugin "windows"安装程序; “无法找到或加载 Qt 平台插件“windows”
【发布时间】:2018-05-08 04:46:43
【问题描述】:

我的 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')

所以我遇到了问题,我将使用来自 pip 的最新版本的 PyInstaller 编译我的 PyQt5 5.8.2(使用 Python 3.6.1)程序,它可以工作!静态链接的 onefile 可执行文件在我的计算机上运行,​​上面包含所有 Qt 内容。

然后我在尚未设置 Qt 环境的任何计算机或虚拟机上对其进行测试,但由于“找不到或加载 Qt 平台插件'windows'”错误,它在启动时崩溃。如果您查看规范,您会注意到我试图手动将 DLL 存储在二进制列表中,以便 PyInstaller 将其存储在可执行文件中,但这不起作用。

我想知道我需要改变什么,这样我就可以编译我的应用程序,而不必执行诸如将平台文件夹包含在可执行文件的文件夹中(我希望所有内容都在可执行文件中),会不会就像更改我没有意识到的规范文件一样简单,以便将 DLL 存储在可执行文件中?

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

编辑:所以我将其更改为 onedir 只是为了查看它是否在其中,并且 qwindows.dll 在文件夹内。还有一个 qt5_plugins 文件夹,其中有一个平台文件夹,该文件夹也有一个 qwindows.dll。那它是怎么检测不到dll的呢??

【问题讨论】:

  • 您可以尝试在 pathex 变量中添加这些库的路径
  • 刚刚尝试通过更改为 pathex=['C:\\Users\\admin\\compile', 'C:\\Python361\\Lib\\site-packages\\PyQt5\\ Qt\\plugins\\platforms'],没有改变任何东西
  • 还有@The4thIceman,如果重要的话,我会在干净的虚拟机上执行此操作
  • 我发现了一个重要的细节,所以我编辑了这个问题。

标签: python-3.x qt pyqt5 pyinstaller static-linking


【解决方案1】:

我只是将我的 pyqt5 包更新到 5.10.1 并修复它。

【讨论】:

  • 评论质量
【解决方案2】:

似乎有两种解决方案,第一个对我来说效果很好:

  • 将平台目录复制到可执行文件的目录。您会在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 平台插件窗口”的问题。我通过将使用pyinstaller --onedir main.py 生成的程序目录中的~PyQt5\Qt\plugins\platforms 文件夹复制到包含.exe 文件的文件夹来解决了这个问题。

    似乎在我的情况下,“帮助”我的程序检测所需的 .dll 的唯一方法是将 platforms 文件夹放在 main.exe 旁边。使用pyinstaller --onefile main.py后将platforms文件夹粘贴到程序的目录中也可以使程序工作。

    【讨论】:

    • 它对我有用。我有一个用 pyinstaller 编译的“应用程序”,其中涉及 matplotlibseaborn 图形。可执行文件有效,但在图表弹出时会出现错误。在 Pycharm 中运行 python 脚本可以正常工作。我复制了文件夹platforms,就我而言,位于C:\Anaconda3\Lib\site-packages\PyQt5\Qt\plugins --> 问题已解决
    【解决方案4】:

    这是一个老问题,但我几天来一直在寻找解决这个问题的方法,我终于设法解决了这个问题,而无需手动复制文件夹。 由于这个问题也使用了.spec 文件,我认为这是正确的地方。 这个想法是.exe 正在路径./platforms/*.dll 中寻找.dlls,所以我只是将所有的dll 添加到spec 文件中的二进制数组中,它们在包中的路径是platforms/*.dll。这是因为binaries 是一个元组数组,其中第一个值是文件的路径,第二个值是包内的路径(几乎是 .exe“容器”内的路径)。

    除此之外,我认为最上面的状态mode: python 表示它是作为python 脚本执行的,因此它应该支持变量、字符串和连接。所以我的规范文件最终看起来像这样:

    # -*- 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 版本并且没有 venvs,但没有任何效果。最后,用dlls 复制platforms 文件夹就成功了,规范文件编辑也是如此,以避免手动步骤。

    【讨论】:

    • 这在使用 winx64、python 3.7.x、venv + pyside6 时似乎不起作用。
    【解决方案5】:

    在试图解决这个问题时我的大脑几乎要爆炸后,我想出了一个对我有用的解决方案。

    在 SPEC 文件中我添加了子句:upx_exclude=['qwindows.dll'],

    原来这个 DLL 在 PyInstaller 冻结过程中被压缩时损坏了。将 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)
    

    【讨论】:

      【解决方案6】:

      在 PyQt6 6.0.3 和 PyInstaller 4.3 中遇到了同样的问题。

      首先尝试了一个单文件夹捆绑包,在将平台和样式插件添加到binaries 列表和PyQt6.siphiddenimports 列表后运行良好(后者可能仅在使用 PyQt6 时才需要)。

      当我尝试单文件包时,我得到了平台插件错误。首先,我通过查看在运行时解包捆绑包的临时文件夹(打开错误对话框)检查文件是否正在复制,并且所有 DLL 都在那里。当我将其复制到与可执行文件相同的文件夹时,它工作正常,问题是 Qt 没有在临时文件夹中找到它们。

      我在Qt documentation 中找到了有关QT_PLUGIN_PATH 的解决方案,然后在此PyInstaller commit 中查找。

      添加插件的 DLL 后,只需添加运行时挂钩以设置 QT_PLUGIN_PATH

      此外,如果使用 UPX,则需要将插件的 DLL 添加到 upx_exclude 列表中。

      这是我使用的钩子和规范文件,删除了默认选项:

      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',
          ],
      )
      

      【讨论】:

      • 我正在尝试和你一样几个小时。没办法……还是一样的错误……:-/
      最近更新 更多