Выполняется с использованием pyInstaller/UPX ошибки QtCore4.dll
Программа python, скомпилированная с pyInstaller, оказалась более 400 МБ. Графический интерфейс программы основан на htmlPY, который является "оберткой вокруг библиотеки PySide QtWebKit". Большой размер программы частично связан с тем, что он использует numpy, scipy и nltk, а частично благодаря графическим библиотекам.
Чтобы свести к минимуму размер программы, я установил UPX. Это уменьшило размер программы до чуть более 100 МБ, что является большим, но приемлемым.
Первая проблема заключается в том, что pyInstaller не обнаружил htmlPy и не включил его в скомпилированную программу. Это можно устранить, скопировав модуль htmlPy из моей установки Python в каталог "dist", созданный pyInstaller. После этого версия программы, скомпилированная без UPX, работала нормально.
После добавления htmlPy в каталог "dist" запуск исполняемого файла приводит к сбою программы в момент создания графического интерфейса. Я не уверен, что это связано с проблемным взаимодействием между UPX и QT или между UPX, QT и htmlPy. "Проблема с подписями" Windows следующая:
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
Любые идеи относительно того, что происходит здесь, и как его исправить?
EDIT:
Это содержимое моего файла .spec:
# -*- 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:
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):
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.
Ответы
Ответ 1
Ваши две большие проблемы связаны с:
- правильность - приложение с UPX не будет запускаться
- performance - 400 MiB "слишком велик", а 100 MiB позволяют вам обращаться к большему набору пользователей
Приложение может быть более полезным для большего количества людей, если оно меньше, но оно никому не полезно, если оно не будет работать. Вы подозреваете, что UPX улучшает беспокойство 2, но его взаимодействие влияет на проблему.
Было бы интересно создать простое приложение HelloWorld, упаковать его с помощью pyInstaller + UPX и сохранить его с дополнительными зависимостями (например, Qt), пока вы не увидите, как он сломается таким образом, как текущий обрыв.
Может быть более продуктивным отказаться от UPX в пользу других подходов, в том числе NSIS. Вы можете использовать такой инструмент, как strace(), чтобы контролировать, какие из ваших распределенных файлов фактически используются во время тестирования системы, и обрезать неиспользуемые файлы во время упаковки. Проксирование запросов через FUSE даст аналогичную информацию. Вы можете перечислить зависимости для вашего опубликованного приложения и полагаться на pip или conda для загрузки зависимостей параллельно, если "истекшее время установки" действительно то, что заставляет ваше желание сжимать 400 до 100 MiB.