Сама программа несложная, написалась относительно быстро. Намного больше времени отъела сборка ее под винду. Понятно, что выбранные инструменты (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
Успехов в сборке!
Расскажите про свой опыт!

