Сама программа несложная, написалась относительно быстро. Намного больше времени отъела сборка ее под винду. Понятно, что выбранные инструменты (Python3 + Qt5) не родные, а универстальные, но что потребуется столько времени затратить на сборку, я не предполагал.
Соответственно, хочется поделиться практикой, может кому еще придется стучаться лбом в эту стену.
Под катом выстраданная инструкция как легко собирать PyQt5 приложения в single-file.exe не требующий инсталлятора.
Наиболее известные решения для моей задачи — сборки python приложений в .exe это: py2exe, cx_freeze и pyinstaller. Про каждый написано много всего. Но очень часто авторы грешат халтурой — легко и быстро собирается программа и запускается… на том же самом компьютере. Надо ли говорить, что это две большие разницы — запуск на дев-среде и у пользователя? У меня-то и так заработает безо всяких сборок и танцев с бубном. Кроме того — кто из пользователей будет ставить себе Qt?
Для каждого инструмента есть туториал. Но у каждого были свои проблемы: один не запускался (pyinstaller до сих пор поддерживает 3-й питон в экспериментальном режиме), другой собрал то, что не смог запустить, третий вообще долгое время ничего не собирал, ругая все вокруг.
После долгой борьбы был выбран py2exe.
Секрет успеха в правильной установке компонент из правильных источников (я не даю прямые ссылки, т.к. они все равно устареют, пишу что где искать):
- Win XP 32-bit (или другая, которую вы возьмете за базу — я специально взял самую старую систему)
- Python 3.4 — устанавливаем с www.python.ord/download Windows x86 msi installer. Можно сразу добавить C:\Python34\ в %PATH%
- PyWin32 — ставим с sf.net файл pywin32-219.win32.py3.4.exe
- Qt5.5 — ставим с официального сайта qt.io. Одновременно с ним ставится компилятор mingw4.9.2
- После установки добавляем C:\Qt\Tools\mingw492_32\bin в %PATH%.
- Git for Windows — он нам нужен в любом случае, ставим с git-scm.com
- PyQt5 — качаем и ставим riverbankcomputing.co.uk win32 x86 installer
- SIP — я так и не понял почему, но тот же самый riverbankcomputing.co.uk не удосужился собрать служебный модулек, поэтому качаем win сорцы, распаковываем, дальше удобно продолжить работу в консоли Git Bash:
- python configure.py -p win32-g++
- mingw32-make.exe
- mingw32-make.exe install.
- Само собой, инсталляция не сработает (. К счастью, нам нужно поставить всего 3 файла. Идем руками в подпапку sipgen/ folder и копируем sip.exe в C:\Python34.
- Затем иде в ../siplib и
- copy sip.pyd c:\python34\Lib\site-packages
- strip /c/Python34/Lib/site-packages/sip.pyd
- наконец, копируем .h-файл:
- cp sip.h /c/Python34/include/
- py2exe — ставим родным способом: python -m pip install py2exe
- pyreadline — так же: python -m pip install pyinstaller
- 7-Zip — c сайта 7-zip.org качаем x86 exe
- 7-zip extra — полезные дополнения качаем оттуда же, распаковываем в папку с установленным 7-zip folder. На конфликты txt-файлов можно забить.
- Resource Hacker — качаем angusj.com — впрочем, если вы не собираетесь заменять дефолтную пиктограмму программы на свою, то она вам не потребуется. Либо ее можно заменить на windres, которая идет в комплекте с mingw — но у меня уже было сделано с RH.
Делюсь своим setup.py:
from distutils.core import setup
import os, sys
import py2exe
from glob import glob
import PyQt5
NAME="Proga"
qt_platform_plugins = [("platforms", glob(PyQt5.__path__[0] + r'\plugins\platforms\*.*'))]
data_files.extend(qt_platform_plugins)
msvc_dlls = [('.', glob(r'C:\Windows\System32\msvc?100.dll'))]
data_files.extend(msvc_dlls)
# print(data_files)
sys.argv.append('py2exe')
setup(
data_files=data_files,
windows=[
{
"script": "pyftp1.py",
"icon_resources": [(0, "resources/favicon.ico")]
}
],
# zipfile=None,
options={
"py2exe": {
"includes":["sip", "atexit",], # даже если мы нигде не используем atexit его надо добавить, sip указываем явно - сборщики часто про него забывают
# "packages": ['PyQt5'],
"compressed": True,
"dist_dir": "dist/" + NAME,
# "bundle_files": 0, # не сработало ( с этой опцией на выходе прога не может найти msvc*.dll
# "zipfile": None, # тоже лишнее
"optimize": 2,
}
}
)
Это программа-минимум. Теперь можно собирать само приложение:
python setup.py py2exe
На выходе получаем папку с готовой прогой в dist.
Это хорошо, но не всегда удобно для пользователей. На эту папку можно натравить создаватель инсталляторов, типа Inno Setup и получить msi. В моем случае, надо было обеспечить работоспособность программы с минимальными правами пользователей — точно без права установки либ.
Поэтому я пошел дальше и запаковал в 1 файл с помощью 7-zip. Схема такая: создаем 7z-архив и к нему пристыковывается специальная SFX-голова и конфиг. Голова распаковывает архив во временную папку, смотрит в конфиг и запускает нужный exe-файл. Собирается примерно так:
cat 7zS.sfx resources/config.txt Proga.7z > Proga.exe
В файле конфига можно указать разные опции, я задал минимум:
;!@Install@!UTF-8!
Title="Proga"
RunProgram="Proga\\pyftp1.exe"
;!@InstallEnd@!
Единственный недостаток — некрасивая картинка у exe файла — стандартный распаковщик. Тут-то и подменяем ему картинку на нужную нам:
RESHACKER.exe -addoverwrite Proga.exe, Proga.exe, resources/favicon.ico, ICONGROUP, MAINICON, 0
Чтобы не мучаться с этим всем в консоли, я сделал небольшой Makefile:
# start settings
DIST=dist
# change NAME also in setup.py and resource/config.txt
NAME=Proga
EXT=exe
# final name and location of the built program
FINAL=$(DIST)/$(NAME).$(EXT)
# external programs
7ZIPDIR="C:\Program Files\7-Zip"
RESHACKER="/c/Program\ Files/Resource\ Hacker/ResourceHacker.exe"
# intermediate steps
# no icon version of program
NOICON=$(DIST)/$(NAME)_no_icon.$(EXT)
# name of .7z archive
7Z_BASENAME=$(NAME).7z
7Z=$(DIST)/$(7Z_BASENAME)
# folder with ready .exe
PROGDIR=$(DIST)/$(NAME)
all: $(FINAL)
$(FINAL): $(NOICON)
# change icon
"$(RESHACKER)" -addoverwrite $(NOICON), $(FINAL), resources/favicon.ico, ICONGROUP, MAINICON, 0
$(NOICON): $(7Z)
#build autorunning sfx with default icon
cat $(7ZIPDIR)/7zS.sfx resources/config.txt $(7Z) > $(NOICON)
$(7Z): exe
# compress program folder to .7z
cd $(DIST); $(7ZIPDIR)\\\7z.exe a $(7Z_BASENAME) $(NAME)
exe: $(DIST)
# build program itself
python setup.py py2exe
$(DIST):
# create dist directory
# echo $(DIST)/
clean:
rm -rf $(DIST)/*
Теперь можно очень легко пересобирать прогу:
mingw492-make.exe clean all
Успехов в сборке!
Расскажите про свой опыт!
Комментарии (16)
iroln
05.08.2015 22:30+1Мой опыт: приложение на Py3.4 и PyQt4 собирается cx_Freeze и запускается нормально. Правда там был какой-то баг в cx_Freeze, который исправили, но почему-то в официальный релиз на тот момент этот патч не попал. При этом исправленная версия была доступна на всем известном сайте. С PyQt5 собирать standalone-сборку честно не пробовал, надо будет проверить.
el777
05.08.2015 22:49+2У меня тоже cx_freeze шел в лидерах — раньше остальных смог собрать прогу, но не рабочую. Видимо, я на этот баг и напоролся.
Я пробовал самостоятельно компилить патченую версию, но это превратилось в такую мороку.
Самое смешное, что cx_freeze единственный из тройки не поддерживает сборку в single-executable, т.к. автору не нравятся те хаки, которые для этого применяют py2exe и pyinstaller. Из-за этого и появилась вторая часть моего рецепта — превращение в single exe.iroln
05.08.2015 22:55+2Да, я когда этот вопрос изучал, выделил cx_freeze как самый адекватный проект, он на тот момент умел собирать сложные штуки, типа pyqt/pyside+numpy+scipy+matplotlib и т.п. Это мне и было нужно. Помню, пробовал pyinstaller, переплевался и выкинул в мусорку.
cx_freeze не умеет собирать single exe, это да, но я в своё время проникся идеей не делать так, хотя бы потому что мой проект зависел от разных dll, и я их периодически обновлял, не пересобирая само приложение, что оказалось очень удобно.
danfe
06.08.2015 19:12Самое смешное, что cx_freeze единственный из тройки не поддерживает сборку в single-executable, т.к. автору не нравятся те хаки, которые для этого применяют py2exe и pyinstaller.
В свое время нам почему-то не подошел cx_Freeze, очень возможно, что как раз поэтому: требовался единственный экзешник.
Посмотрел в том проекте сейчас: для деплоймента в GNU/Linux я таки-писал спек-файл для PyInstaller, а для венды/вайна —setup.py
для py2exe, хотя он и не понимал .egg-bundles («does not eat eggs for breakfast»), т.е. пришлось писатьunpack_egg()
, а потом еще самостоятельно сжимать бинарник UPX'ом.
Не помню точно, почему не унифицировал: в комментарии написано, что Windows is currently not supported, and would require changing «excludes» list below (в обоих случаях я старался ужаться по минимуму, поэтому скрупулезно выкидывал ненужные либы). Возможно, py2exe, несмотря на недостатки, позволял получить файл меньшего размера.
veveve
06.08.2015 10:41+1Используйте Nuitka. Сейчас это лучшая из альтернатив (ИМХО, конечно). Я пробовал собирать небольшое приложение на PyQt5, всё прошло просто и без проблем.
nuitka.netel777
06.08.2015 11:04+1Была такая мысль, тоже его попробовал, но не задалось.
Может есть хороший мануал или какие нюансы его использования?veveve
06.08.2015 17:45Так нет никаких нюансов :) просто запускаете из консоли с нужными параметрами и всё. Я своё приложение собирал так:
nuitka --standalone --recurse-all --recurse-stdlib --windows-disable-console --windows-icon=ICON_FILE --recurse-directory=PROJECT_DIR
ICON_FILE и PROJECT_DIR надо заменить соответствующими путями.
Если будете использовать какие-то очень сложные модули, есть вероятность, что их dll'ки придётся вручную в каталог с exe'шником положить, чтобы всё работало. В случае с PyQt5, повторюсь, работает без этого.el777
07.08.2015 13:02Вы со вторым питоном использовали?
У меня не взлетело (:
Error, need to find Python2 executable under C:\Python26 or C:\Python27 to execute scons which is not Python3 compatible.
SeoJiHun
07.08.2015 18:00Ну так установите соответствующую версию Nuitka.
kentaskis
09.08.2015 15:12Лично мне помогла установка соотв. версии Python параллельно с тройкой, для которой и собиралось.
el777
12.08.2015 16:20Я ставил через pip:
python -m pip install nuitka
Питон в системе только 3, чтобы не мешать либы.
Nikobraz
Мне было влом есть кактус.
Пишу на 2.7 и PyQt4.
el777
Тоже вариант. С ним действительно проще собирается и тулзы нормально работают.
Но как-то больше понравилось как сама прога на Qt5 работает — быстрее запускается GUI.
А когда я начал собирать под Винду, все уже было написано — переписывать назад не хотелось :)
Nikobraz
Я как-то пытался PyQt5 собрать, так и не получилось его ни к MinGW, ни к MS VS прикрутить(просил 2010, а под рукой были только 2012 и 2013).
А Python 3 не использую, потому что пару раз нарывался на то, что нужных библиотек под него нет.
Я ничего серьезного пока не пишу, но все равно неприятно.
Если важна скорость попробуйте PyPy
http://habrahabr.ru/post/87364/
el777
> Я как-то пытался PyQt5 собрать…
Такая же картина, причем в pip есть целых два пакета (PyQt5 и python-qt5), которые либо не ставятся либо не собираются. Поэтому приходится качать готовый с сайта. До сих пор не понимаю, почему на том же самом сайте не захотели выложить SIP, который приходится руками собирать?
И вот эта магия «возьми SIP собранный в полнолуние с помощью MingW и плясок, добавь к нему PyQt5 с речного берега, потом щепотку нативного pyreadline, тщательно перемешай в ступе автоконфигом и т.п.» немного удручает.
PyPy надо посмотреть. Спасибо за наводку.
Пробовали его под виндой и в таких приложениях?
Nikobraz
Я из-за этих причин, стараюсь вообще не касаться изучения С++ и использования Open Source на нем.
Есть более интересные способы прожить жизнь, чем неделями собирать софт из исходников.
Как исключение системы портов и портежей, сами понимаете в каких операционках, они на удивление стабильны.
Не помню уже, что собирал. Там была ошибка в либах mysql. О баге уже знали, но когда выйдет исправление, черт его знает. Бывают хорошие люди, которые явно указывают какую версию либ использовать, а самые продуманные прикладывают к своему коду.
ИМХО, исходный код должен быть в таком состоянии, чтобы человек мог его скачать, скачать необходимые библиотеки с дефолтных сайтов и собрать без головных болей и красных глаз. Да чтобы еще запустилось.
Ситуация напоминает середину 2000-х, когда на коне была Delphi 7. Выпускалась масса компонентов с намеренными ошибками, не зная языка подключить их не представлялось возможным. Только тут ошибки ненамеренные и поиск их не имея боевого опыта программирования не имеет смысла.
PyPy пока не знаю куда воткнуть. Думаю сайтик поднять в 2 экземплярах и покрутить его одновременно на оригинальном интерпретаторе и PyPy, посмотреть самому на скорость и стабильность. Но не знаю дойдут ли руки.