关于python:使用pyInstaller / UPX制成的可执行文件遇到QtCore4.dll错误

Executable made with pyInstaller/UPX experiences QtCore4.dll error

我使用pyInstaller编译的python程序原来超过400 MB。该程序的GUI基于htmlPY,它是"围绕PySide的QtWebKit库的包装"。该程序之所以大,部分原因是它使用了numpy,scipy和nltk,部分是由于图形库。

为了最小化程序的大小,我安装了UPX。这将程序的大小减小到略大于100MB,这虽然很大,但是可以接受。

第一个问题是pyInstaller没有检测到htmlPy,也没有将其包含在编译程序中。可以通过将Python安装中的htmlPy模块复制到pyInstaller创建的'dist'目录中来解决此问题。完成此操作后,不使用UPX编译的程序版本运行正常。

将htmlPy添加到'dist'目录后,运行可执行文件会使GUI创建时的程序崩溃。我不确定这是否是由于UPX和QT之间或UPX,QT和htmlPy之间的交互问题。 Windows"问题签名"如下:

1
2
3
4
5
6
7
8
9
10
Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: main.exe
  Application Version:  0.0.0.0
  Application Timestamp:    00000000
  Fault Module Name:    QtCore4.dll
  Fault Module Version: 4.8.7.0
  Fault Module Timestamp:   561e435a
  Exception Code:   c0000005
  Exception Offset: 000000000010883a

关于这里发生的事情以及如何解决的任何想法?

编辑:

这些是我的.spec文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# -*- mode: python -*-

block_cipher = None

added_files = [
     ( 'htmlPy/binder.js', 'htmlPy' ),
     ( 'templates/*', 'templates' ),
   ]
a = Analysis(['main.py'],
             pathex=['C:\\\\..\\\\My_App'],
             binaries=None,
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=['rthook_pyqt4.py'],
             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,
          exclude_binaries=True,
          name='My_App',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='My_App')

这些是rthook_pyqt4.py的内容:

1
2
3
4
5
6
7
8
9
import sip

sip.setapi(u'QDate', 2)
sip.setapi(u'QDateTime', 2)
sip.setapi(u'QString', 2)
sip.setapi(u'QTextStream', 2)
sip.setapi(u'QTime', 2)
sip.setapi(u'QUrl', 2)
sip.setapi(u'QVariant', 2)

编辑2:

这是一些初始化代码(标准htmlPy票价):

1
2
3
4
5
6
7
app.static_path = path.join(BASE_DIR,"static/")
print"Step 1"
app.template_path = path.join(BASE_DIR,"templates/")
print"Step 2"
app.template = ("index.html", {"username":"htmlPy_user"})
print"Step 3"
...

程序在进入步骤3之前崩溃。


您的两个主要问题涉及:

  • 正确性-带有UPX的应用程序将无法运行
  • 性能-400 MiB太大了,而100 MiB则可以满足更多用户的需求
  • 如果该应用较小,则该应用可能对更多人有用,但如果该应用无法运行,则对没人有用。您怀疑UPX改善了关注点2,但是其交互影响了关注点1。

    构建一个简单的HelloWorld应用程序,将其与pyInstaller + UPX打包,并继续使用其他依赖项(例如Qt)对其进行修饰,直到您看到它的破坏方式类似于当前的破坏方式,将是很有意思的。

    放弃UPX而采用其他方法(包括NSIS)可能会更有效率。您可能会使用strace()之类的工具来监视在系统测试运行期间实际使用了哪些分布式文件,并在打包过程中修剪了未使用的文件。通过FUSE代理请求将产生类似的信息。您可能会列出已发布应用程序的依赖项,并依靠pip或conda并行下载依赖项,如果"经过的安装时间"确实是促使您将400缩小到100 MiB的愿望的话。