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

时间:2017-11-24 07:56:49

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

我的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平台插件而在启动时崩溃#39;窗户'"错误。如果您查看规范,您会注意到我尝试手动将DLL存储在二进制列表中,因此PyInstaller会将其存储在可执行文件中,但这并不起作用。

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

顺便说一下,这不是重复的。我查看了其他一些问题,所有这些问题都是针对不同类型的应用程序,或者解决方法是将DLL降级或存储在文件夹中,我无法执行其中任何一项。

编辑:所以我把它更改为onedir只是为了看看它是否在那里,并且qwindows.dll在文件夹内。还有一个qt5_plugins文件夹,它有一个平台文件夹,也有一个qwindows.dll。那怎么没有检测到dll ??

6 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

首先尝试了一个单文件夹包,在将平台和样式插件添加到 binaries 列表并将 PyQt6.sip 添加到 hiddenimports 后运行良好(后者可能只需要如果使用 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',
    ],
)

答案 3 :(得分:0)

我有一个问题,我的python代码可以正常工作,但是编译的.exe文件将提供“找不到或加载Qt平台插件窗口”的问题。通过将使用~PyQt5\Qt\plugins\platforms生成的程序目录中的pyinstaller --onedir main.py文件夹复制到包含.exe文件的文件夹中,我们解决了该问题。

在我看来,“帮助”程序检测所需.dll的唯一方法是在platforms旁边放置main.exe文件夹。使用platforms后将pyinstaller --onefile main.py文件夹粘贴到程序的目录中也会使程序正常工作。

答案 4 :(得分:0)

这是一个古老的问题,但是几天来我一直在寻找解决方案,我终于设法解决了该问题,而无需手动复制文件夹。 由于此问题也使用.spec文件,因此我认为这是正确的位置。 这个想法是.exe在路径.dll中寻找./platforms/*.dll,因此我只是将所有dll添加到spec文件中的binaries数组中,它们的路径位于束是platforms/*.dll。这是因为binaries是一个元组数组,其中第一个值是文件的路径,第二个值是bundle中的路径(几乎是.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尝试,但没有任何效果。最后,使用platforms复制dlls文件夹可以达到目的,编辑规范文件也可以避免手动操作。

答案 5 :(得分: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)