Исполняемый файл, созданный с помощью 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.


person Boa    schedule 22.09.2016    source источник
comment
Можешь показать нам свой setoop.py ? Как добавить свой модуль в качестве импортного или дополнительного?   -  person dsgdfg    schedule 29.09.2016
comment
@dsgdfg Извините, что такое setoop.py и какие импортированные модули вы имеете в виду?   -  person Boa    schedule 29.09.2016
comment
Код setup.py, как добавить библиотеку?   -  person dsgdfg    schedule 30.09.2016
comment
Хотя иногда это работает, копировать модуль в папку pyinstaller — не лучшая идея. Попробуйте добавить недостающий модуль с помощью --hidden-import вариант и посмотрите, есть ли еще проблема.   -  person Repiklis    schedule 30.09.2016
comment
@Repiklis: я пробовал --hidden-import, и мне все еще нужно скопировать и вставить папку htmlPy и содержащийся в ней файл binder.js (файлы python в папке можно опустить) вручную в каталог исполняемой программы, потому что UPX пропускает это. Еще раз, после того, как я вручную скопировал / вставил в каталог htmlPy (на этот раз только содержащий binder.js) и запустил программу, она вылетает. Может ли проблема быть связана с тем, что UPX пропускает/не сжимает файл binder.js htmlPy? Есть ли способ заставить UPX включить эту папку в каталог распространения, который он генерирует?   -  person Boa    schedule 30.09.2016
comment
@dsfdfg - файл setup.py не участвует ни в какой части процесса компиляции.   -  person Boa    schedule 30.09.2016
comment
Я предполагаю, что отсутствие setup.py означает отсутствие файла .spec. Я боюсь, что в этом случае вам понадобится добавить binder.js в качестве файл данных. Я добавлю подробный ответ ниже.   -  person Repiklis    schedule 02.10.2016
comment
@Repiklis - мне удалось использовать файл .spec для включения необходимых файлов данных, и, похоже, они были успешно добавлены. Как и прежде, программа вылетает при запуске.   -  person Boa    schedule 02.10.2016
comment
Можете ли вы запустить из командной строки и опубликовать ошибку? Будет лучше, если вы добавите небольшой фрагмент кода, воспроизводящий проблему.   -  person Repiklis    schedule 02.10.2016
comment
@Repiklis - я запускал из командной строки. Интерпретатор Python никогда не генерирует исключение. Единственным сообщением об ошибке является сигнатура проблемы Windows, которую я разместил выше. Я отредактировал комментарий, чтобы указать точку, в которой происходит сбой программы.   -  person Boa    schedule 02.10.2016
comment
Спасибо за плюсы, всем. Я хотел бы присудить бонусные баллы (на это осталось 23 часа), но у нас пока нет ни ответов, предполагающих возможные диагностические меры, ни вероятного пути к решению. Думаю, я попытаюсь связаться с ребятами из UPX и pyInstaller, чтобы узнать, могут ли они предложить какие-либо предложения.   -  person Boa    schedule 04.10.2016
comment
Вы используете виртуалку? Кроме того, вы пытались добавить путь к QtCore4.dll в добавленные файлы - например, добавив ('C:\\Python35-32\\Lib\\site-packages\\....\\Qt4Core.dll', '.')   -  person sytech    schedule 13.10.2016
comment
@Gator_Python - я не использую виртуальную среду. Я не пробовал добавлять файлы QT в added_files, но они присутствуют (включая QT4Core.dll) в основной папке сгенерированной программы.   -  person Boa    schedule 13.10.2016
comment
Если вы не используете виртуальную среду, вы должны указать на системные dll, чтобы убедиться, что перехватчики времени выполнения работают должным образом. Скорее всего, это dll, используемые при выполнении в Python. Я смутно припоминаю, что видел аналогичную проблему в прошлом, и это было решением, но, возможно, это не ваш случай. Странные вещи происходят, когда вы копируете/вставляете в новые каталоги — это частая причина этой ошибки Windows. Я думаю, что @Repiklis был на правильном пути со своим предыдущим комментарием. Согласно PyInstaller, также рекомендуется использовать virtualenv.   -  person sytech    schedule 13.10.2016
comment
@Gator_Python - я вставил содержимое файла rthook_pyqt4.py выше - если я не ошибаюсь, разве предложение runtime_hooks=['rthook_pyqt4.py'] в файле спецификаций не гарантирует, что включены правильные версии DLL QT?   -  person Boa    schedule 14.10.2016
comment
У меня также были некоторые проблемы с pyinstaller, некоторые из них похожи на ваши. Это кратко описано в stackoverflow.com/questions/46818993/.   -  person Stéphane    schedule 10.11.2017


Ответы (1)


Две ваши большие проблемы связаны с:

  1. правильность - приложение с UPX не запустится
  2. производительность — 400 МБ «слишком велики», а 100 МБ позволяют обращаться к большему количеству пользователей.

Приложение может быть более полезным для большего количества людей, если оно меньше, но оно никому не будет полезно, если оно не будет работать. Вы подозреваете, что UPX улучшает проблему 2, но его взаимодействие влияет на проблему 1.

Было бы интересно создать простое приложение HelloWorld, упаковать его с помощью pyInstaller + UPX и продолжать украшать его дополнительными зависимостями (например, Qt), пока вы не увидите, что оно ломается так же, как текущая поломка.

Возможно, было бы более продуктивно отказаться от UPX в пользу других подходов, включая NSIS. Вы можете использовать такой инструмент, как strace(), чтобы контролировать, какие из ваших распределенных файлов фактически используются во время тестов системы, и удалять неиспользуемые файлы во время упаковки. Прокси-запросы через FUSE дадут аналогичную информацию. Вы можете перечислить зависимости для своего опубликованного приложения и полагаться на pip или conda для параллельной загрузки зависимостей, если «истекшее время установки» действительно вызывает ваше желание уменьшить 400 до 100 МБ.

person J_H    schedule 01.01.2018