Python

индекс
250,37

Немного про py2exe

Есть такое приложение. Называется py2exe. Оно позволяет упаковать, сконвертировать программу на python в exe файл (ну, точнее, exe и еще кучку других). Зачем оно все надо? Ну, далеко не у всех пользователей windows установлен интерпретатор python с нужными библиотеками. А вот упакованная программа в идеале должна запуститься на любой windows-машине.


Установка


К сожалению, py2exe не поддерживает третью версию питона.
Скачать py2exe можно на SourceForge.
Если у вас стоит python (а он у вас наверняка стоит), проблем с установкой возникнуть не должно. Ставится в директорию python.

Конвертация


Теперь начинается самое интересное. В директории, где лежит Ваша программа на python, надо создать файл setup.py со следующим содержанием
Copy Source | Copy HTML
  1. from distutils.core import setup
  2. import py2exe
  3.  
  4. setup(
  5.     windows=[{"script":"main.py"}],
  6.     options={"py2exe": {"includes":["sip"]}}
  7. )
Где main.py имя Вашего скрипта.

Далее запускаем упаковку командой:
setup.py py2exe

Да-да, именно так.

Смотрим, что у нас получилось. Две папки.
build — служебная, можно сразу снести.
dist — собственно, в ней и лежит наша программа.

Как было сказанно выше, это не один файлик:
  • main.exe — программа
  • pythonXX.dll — интерпретатор python'a
  • library.zip — архив со скомпилированными исходниками (всего, кроме собственно программы, как я понимаю)
  • .pyd — модули python, которые импортирует программа
  • .dll — библиотеки, оказавшиеся необходимыми
  • и еще файлы по мелочи, ниже будет сказано еще

Неужели все так просто? Неправда;)

Сложности


Скорее всего возникнут какие-то проблемы.

Например, пути к файлам. Не следует использовать относительные пути. Они ведут неведомо куда. Лучше использовать абсолютные.
Как его узнать? в интернете есть решение, функция module_path.
Copy Source | Copy HTML
  1. import os, sys
  2.  
  3. def module_path():
  4.     if hasattr(sys, "frozen"):
  5.         return os.path.dirname(
  6.             unicode(sys.executable, sys.getfilesystemencoding( ))
  7.         )
  8.     return os.path.dirname(unicode(__file__, sys.getfilesystemencoding( )))

Или приложение наотрез откажется запускаться (возможно, не у Вас, а у кого-то еще). Из-за отсутствие библиотек Visual Studio.
В качестве решения проблемы можно установить их на компьютер (но это же не наш метод) или кинуть dll и файл манифеста в папку с программой.
msvcr90.dll и Microsoft.VC90.CRT.manifest (не знаю как это лицензируется и выкладывать не буду)
Где их взять? Для меня самым простым было переустановить python (все остальное осталось на месте) в режиме «только для меня». И искомые файлы оказались в папке с python.

Целью топика не являлось раскрыть всех особенностей py2exe. Здесь находится туториал, а тут некоторые советы и трюки.

Размер


В силу некоторых особенностей, приложение может получиться ужасающего размера. Но с этим можно и нужно бороться. Идеи подсказал kAIST (ну, кроме upx’а =р)

  1. Самое действенное. Сжать библиотеки upx’ом. Консольное приложение. Работает элементарно. На вход передается файл, оно его сжимает. Для моей игры реверси размер уменьшился в ~3 раза.
  2. Удалить unicodedata.pyd, bz2.pyd, select.pyd, w9xpopen.exe. Веса немного, но, как минимум, в проекте станет меньше файлов
  3. Если в setup.py указать опцию optimize:2, то модули будут компилироваться в .pyo (python optimized code), а не в .pyc (python compiler script). Это не дает большого эффекта, но кто знает, может Вам повезет)
  4. И наконец, можно подчистить library.zip от неиспользованных модулей и кодировок. Только аккуратно.

Вывод


Ну вот, кажется, и все. Мы добились, чего хотели. Да, приложение получилось солидного размера (это вам не C++, например), зато на нашем любимом Python:)
+42
12 марта 2010, 01:36
97

комментарии (35)

НЛО прилетело и опубликовало эту надпись здесь
+4
satori #
забыли упомянуть что эта славная приблуда работает только со второй версией python. ну может и с первой, но не суть важно. главное что не с третьей, вот)
0
pawnhearts #
optimize:2 не даст большого эффекта, но вырежет docstring`и; для некоторых приложений они необходимы. это не самое удачное решение, но я иногда хранил в них какие-то важные для программы данные.
+1
lexazloy #
> msvcr90.dll и Microsoft.VC90.CRT.manifest [...] Где их взять?

Можно проще: поискать в гугле. :) Существует достаточно много сайтов с коллекциями разных DLL-файлов.

Непонятно, почему py2exe использует библиотеку Visual Studio установленной версии, а не древнюю (шестой версии, вроде) msvcr.dll, которая есть везде?
0
grep0 #
Официальная сборка Python 2.6 — с msvcr90.dll. В принципе, можно собрать его и VC6, но я бы не стал рисковать — слишком неоттестировано.
0
lexazloy #
Я не могу понять часть комментария про риск, т.к мало имел дело с компиляторами. Но разве не компилятор Visual Studio дёргает эту DLLку? Он. Следовательно, какая разница чем собран питон?

Поэтому как может быть неоттестировано?
0
grep0 #
py2exe ничего не компилирует, а создаёт стаб, который прописывает пути к питоновским модулям и вызывает настоящий интерпретатор из pythonXX.dll. Естественно, если питон собран VC9, то pythonXX.dll зависит от msvcrt90.dll
0
lexazloy #
Я и не писал, что py2exe чего-то компилирует.

По поводу комментария ниже (про риски). Суть понятна: глюков может и не быть, но мало ли чё. :)
0
grep0 #
А насчет риска — слишком мало людей используют питон, собранный VC6, так что вполне вероятны какие-нибудь грабли из-за багов компилятора, другого поведения рантайма или ещё по какой причине.
0
neyromant #
Ни разу не встречались программы написанные на Python, упакованые в ехе и распространяемые таким образом. Сам, когда изучал Python, пробовал эту фишку, но так, ради любопытства, не более… Хотя да, если программа написана для себя и планируется её запуск на машине без интерпретатора то это, наверное, выход..., но для массового распространения вариант сомнительный…
0
lexazloy #
Я такую писал. Неудобно, архив большой, приходилось рядом с exe доп. библиотеки по полметра класть. Но люди всё-равно качали и пользовались, варезники всё-равно распространяли. Размер архива был где-то 5-8 метров. Пять в начале и восемь — у последней выпущенной версии. Хотя программка сама по себе была малюсенькой.

Меня только единожды упрекнули и не в весе архива, а в языке: мол, зачем на питоне, если можно было на дельфи (кажется, его предлагали).
0
nosuchip #
На хабре публиковался анонс игры Krank, написанной на питоне и упакованной py2exe. Папка выглядит немного страшно, но кого волнует этот аспект?
+1
Mr_Floppy #
Например, Google App Engine SDK для Windows собран с помощью py2exe.
+2
bormotov #
наш софт писаный на питоне пакуется так. а еще и InnoSetup завернут. Очень удобно. Простые люди даже не догадываются, что это софт на питоне писан.
0
salvator #
bittorrent тоже py2exe пакуется для инасталляторов под win32
+7
alexey_uzhva #
А PyInstaller умеет все то же самое, но кроме того упаковывает манифесты и msvcr автоматически (с патчем на него), плюс поддерживает всякие иконки для exe файла, из коробки — UPX и не создает файлов для stdin/stdout, если отключен консольный режим (клиентов лишние файлы всегда смущают).

Жаль, что про него мало кто говорит, а по мне — так гораздо более достойный вариант.
0
free0u #
Сейчас посмотрел, согласен, pyinstaller куда проще и все получилось с первого раза. Но размер exe получился 10,5 мб против 8,6 у py2exe (для приложения использующено py2exe). Однако, похоже я все же буду использовать PyInstaller…
+1
alexey_uzhva #
Там есть тулза ArchiveViewer.py, делаете ей «ArchiveViewer.py ВашФайл.exe», и смотрите какой лишней хрени оно туда запихнуло.

Потом в файле проекта я обычно пишу:

a = Analysis(

...........

excludes = [
'win32ui',
'win32api',
'_ssl',
'bz2',
'Microsoft.VC90.CRT\\msvcm90.dll',
]
)


Без этих либ оно обычно всегда работает, размер получается около 6Мб.

Если с PyQt, то еще есть такой финт ушами, чтобы он туда не пропихнул кучу ненужных плагинов для всего подряд:

bad_files = []
for name,path,type in a.datas:
if name.startswith('qt4_plugins'):
bad_files.append((name,path,type))
a.datas -= bad_files


Сборка, включающая в себя PyQt (QtCore+QtGui) получается обычно 9-10.5 Мб.
0
free0u #
Удалось сжать до 9,5 мб. Спасибо, добрый человек)
0
free0u #
для приложения использующено py2exe
pyqt4, конечно же :-[
+1
alexey_uzhva #
С PyQt да, меньше 10мб трудно сделать. Хотел для этого перекомпилить PyQt через VS (по дефолту скачивается MinGW версия), чтобы сделать его меньше по объему и выкинуть mingw-ные либы. Помню когда на Qt писал, то VS-ные сборки были прям чуть ли не в 2 раза легче по размеру.

Но пока лень… Да и какая, впрочем, разница, ну будет 8 метров вместо 10 — при нынешних объемах жестких дисков и ширине каналов это давно уже мало имеет значения для таких продуктов. А там, где значение имеет — нечего на питоне писать, там с++ есть и даже голый си…
0
free0u #
Таааак. Не все так радужно оказалось. На другом компьютере (там, как минимум, не установлены библиотеки студии) приложение отказывается запускаться.
Error loading python DLL: path/python26.dll (error code 14001)

Собирал так:
Makespec.py -F -w -X main.py
Build.py ./main/main.spec

Не сталкивались?
0
alexey_uzhva #
Надо патч для поддержки питона 2.6 с его манифестами. Брать отсюда, там есть список, возьмите посвежей. Накатить надо поверх той ревизии для которой предназначен патч.

Один раз сделаете себе патченую версию, дальше можно пользоваться ей и горя не знать. У меня полугодовой давности вот пользуюсь постоянно — и ничего, проблем не испытываю.
0
free0u #
Слил к себе 771 ревизию PyInstaller. Накатил последний патч (pyinstaller-trunk-r768-py26-win-tweaks-20100210.patch) для 768 ревизии. Пересобрал приложение. Ошибка та же =/
+1
alexey_uzhva #
Очевидно что надо было слить 768 ревизию ;-)
+1
DoctorDemon #
Сжатие upx'ом нужно разве что для того, чтобы это дело занимало мало место на диске. Аналогичный эффект достигается при создании инсталлятора.
В памяти же, размер будет исходный.

Как вариант можно создать минимальную необходимую для нашей программы сборку питона.
0
alexey_uzhva #
PyInstaller автоматически отслеживает зависимости всех файлов (даже бинарных) и включает только их. Конечно, это делает сборку проекта не моментальной, зато результат хороший.
+1
coolmiha #
Для третьего питона конечно это не заработает?
0
free0u #
Угу :( Надо дописать в топик.
+1
vostryakov #
«Ну, далеко не у пользователей „

Наверно правильно: “Ну, далеко не у всех пользователей „
0
free0u #
Fixed.
0
deseven #
А кто такой Веся Неманого? oO
0
free0u #
Оу. Интересный вопрос.
0
Mr_Floppy #
А как указать путь для каталога build? C dist_dir все понятно, а вот мусорный build приходится сносить батником, хотел бы его куда-нибудь в %temp% засунуть.
0
alexey_uzhva #
Он не мусорный, он помогает когда много раз ребилдишь… Типа не баг, а фича;)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.