Исполняемый файл сделан с 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
Есть идеи, что здесь происходит и как это исправить?
РЕДАКТИРОВАТЬ:
Это содержимое моего.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 не запустится
- производительность - 400 МБ "слишком велико", а 100 МБ позволяют работать с большим количеством пользователей.
Приложение может быть более полезным для большего количества людей, если оно меньше, но никому не полезно, если оно не будет работать. Вы подозреваете, что UPX улучшает проблему 2, но ее взаимодействие влияет на проблему 1.
Было бы интересно создать простое приложение HelloWorld, упаковать его с помощью pyInstaller + UPX и продолжать украшать его дополнительными зависимостями (такими как Qt), пока вы не увидите, что оно ломается так же, как и текущая поломка.
Может быть более продуктивным отказаться от UPX в пользу других подходов, включая NSIS. Вы можете использовать такой инструмент, как strace(), чтобы отслеживать, какие из ваших распределенных файлов действительно используются во время тестов системы, и удалять неиспользуемые файлы во время упаковки. Прокси-запросы через FUSE выдают аналогичную информацию. Вы можете перечислить зависимости для вашего опубликованного приложения и полагаться на pip или conda для параллельной загрузки зависимостей, если "истекшее время установки" действительно побуждает ваше желание сократить 400 до 100 МБ.