Облегчаем использование pyinstaller для создания exe

    Недавно начал свое знакомство с языком Python с целью применения его для написания в короткие сроки приложений, выполняющих необходимую задачу здесь и сейчас. Так как планируемые приложения могли быть запущены не только на ос, в которых установлен сам Python, было решено собирать exe. Почитав пару топиков на хабре и комментарии к ним, пришел к выводу, что для этих целей прекрасно подойдет pyinstaller. Он довольно прост в использовании, но все же некоторые повторяющиеся моменты можно сократить.

    Для начала опишу используемый для этого софт:
    1. CPython 2.6.5. Спросите почему не 2.7 или 3.x? Описанная ниже версия pywin, используемая для pyinstaller, дружит только с версиями до 2.6 включительно
    2. pyinstaller 1.4 r854 (на момент начала использования это была последняя ревизия)
    3. pywin32-214.win32-py2.6 — последняя доступная на sourceforge версия. Используется pyinstaller для определения зависимостей (вообще им надо сруливать с него, т.к. последнее обновление датируется 09 годом)
    4. UPX 3.0.7 — используем для сжатия файлов


    Для того, чтобы произвести сборку exe в соответствии с мануалом необходимо:
    1. Запустить Configure.py, который проверит наличие всех необходимых для сборки компонентов (выполнять при смене конфигураций, будь-то добавление/удаление UPX, изменение библиотек и т.д.)
    2. С помощью MakeSpec.py из папки pyinstaller в соответсвии с необходимыми параметрами создать spec файл
    3. С помощью Build.py из той же папки, указав путь к spec файлу, произвести сборку exe


    В связи с тем, что pyinstaller у меня хранится в папке python (путь по умолчанию), а исходники на другом диске, то процедуру шаманства с путями в консоли и постоянным дописыванием одинаковых параметров я решил сократить используя bat файл, разбор которого сейчас и будет произведен.

    Для начала, определил цели:
    1. Отвязка от необходимости постоянно задавать путь к MakeSpec и Build файлам, а так же spec файлу
    2. Получение готового exe в той же директории, что и исходный код


    Реализация самого bat-файла (комментарии по ходу действия, готовый батник с комментариями лежит ниже):
    1. Стандартные для bat строчки — отмена вывода команд в консоль, очистка последней:
    @echo off
    cls

    2. Указываем путь к pyinstaller и путь к папке, в которой будут хранится spec и exe файлы:
    set pyinstPath=c:\python26\pyinstaller
    set buildPath=%pyinstPath%\bin

    3. Задание значений переменной проверки перемещения готового exe и проверки, введено ли имя исходного файла (по сути — флаги):
    set moveBin=0
    set fileParam=0

    4. Начинаем проверку введенных параметров. Для обработки вызываем метку с введеным ключом (3-ая строчка). После обработки каждого параметра возвращаемся на метку :ParamChk. В случае же если параметры закончились, переходим на метку сборки бинарника (2-ая строчка):
    :ParamChk
    if "%1%"=="" goto binBuild
    goto p%1

    5. Собственно сами метки ключей/параметров. Вариации ввода разнообразные, суть одна и та же — в случае, если такой ключ существует, производим необходимые манипуляции, такие как получение имени исходного файла, пути по которому будет хранится spec файл, вывод помощи и с помощью команды shift производится сдвиг параметров на 1 влево (был параметр %2, стал %1 и т.д.):
    :p-F
    :p/F
    :p/file
    :p--file
    if not "%2"=="" (
    set pyFile=%2
    if not %fileParam%==1 set fileParam=1
    )
    shift & shift & goto ParamChk
     
    :p-O
    :p/O
    :p/out
    :p--out
    if not "%2"=="" set buildPath=%2
    shift & shift & goto ParamChk
     
    :p-M
    :p/M
    :p/move
    :p--move
    set moveBin=1
    shift & goto ParamChk
     
    :p-H
    :p/H
    :p/help
    :p--help
    echo.
    echo Use: %~n0 [/F [path]filename] [/O dir] [/M]
    echo.
    echo /F, -F, /file, --file - Path to .py file 
    echo /O, -O, /out, --out - Output directory. Default directory - %buildPath%
    echo /M, -M, /move, --move - Move created binary to .py file directory
    goto :EOF

    6. После проверки и обработки всех параметров переходим к метке :binBuild и проверяем, было ли введено имя исходного файла. В случае если нет — выводим сообщение о необходимости наличия имени файла, наличии справки и завершаем работу:
    :binBuild
    if %fileParam%==0 echo No file to work with. Use /for help & goto :EOF

    7. Задаем параметры, в соответствии с которыми будет производится сборка exe. Синтаксис берем в мануале к pyinstaller. В данном случае указаны следующие параметры — сборка в один файл, сжатие с помощью UPX + смена папки для готового exe:
    set specParams=---%buildPath%

    8. Далее производим создание spec файла и создание exe на его основе, используя заданные выше пути к MakeSpec, Build и параметры для первого. Присутствует один жуткий костыль — учитывая, что я не спец по batch файлам, то способ выделить из пути к исходному файлу только его имя я нашел только с помощью цикла (2-ая строчка):
    "%pyinstPath%\MakeSpec.py" %specParams% "%pyFile%"
    for %%in (%pyFile%) do (set fileName=%%~ni)
    %pyinstPath%\Build.py "%buildPath%\%fileName%.spec"

    9. В случае если был задан параметр на перемещение бинарника в папку с исходным кодом, для ее получения используем костыль из пункта 8-м. А затем просто перемещаем файл с заменой без подтверждения:
    if %moveBin%==1 (
    for %%in (%pyFile%) do (set outDir=%%~pi)
    move /"%buildPath%\dist\%fileName%.exe" %outDir%
    )


    Готовый bat файл с комментариями лежит тут.
    Для использования достаточно отредактировать строки по пунктам 2 и 7 в соответствии с вашим расположением папки pyinstaller и требуемым параметрам.

    Disclaimer:
    Вот и все. Хотелось бы отметить, что в комментариях как здесь, так и в самом bat файле я не описывал особенности синтаксиса команд, а просто описал последовательность выполненных действий. Для справки по команде в консоли достаточно выполнить <имя_команды> /? и вам напишут больше, чем я могу тут описать и знаю. Если вы знаете, как избавится от некоторых костылей или облегчить/упростить выполнение некоторых пунктов, с радостью выслушаю. Если вы считаете, что данный топик не должен находится в блоге Python, а в каком-то другом, просьба указать в каком именно.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 16
    • +2
      Вот бы ещё осветили создание exe со скриптом из ОС Linux (=
      • +2
        К сожалению я ленив, и все никак не дойдут руки заставить себя больше сидеть в linux с целю самообучения. Пока что я просто пользователь xubuntu на виртуальной машине, изучающий основы.
        • 0
          По крайней мере с помощью PyInstaller это невозможно. Как они пишут, «теоретически это возможно, но вне наших приоритетов». Т.е. под Linux получится выполняемый файл, специфичный для того же Linux (ELF).
          • 0
            Под wine у меня получалось собирать.
          • +1
            Не могли бы вы вкратце рассказать о преимуществах pyinstaller перед py2exe? В чем разница?
            • +1
              1) Кроссплатформенный
              2) Меньше проблем при переносе собранного экзешника между различными версиями винды. В py2exe без специального хака распространены следующие проблемы: www.google.ru/search?&q=py2exe+ImportError:+DLL+load+failed

              Но мне в целом больше нравится py2exe — он ничего не распаковывает во временную директорию и возможностей кастомизации у него (насколько я понял) больше.
              • 0
                > 1) Кроссплатформенный
                Вот с этого места можно поподробней…
                .
                >В py2exe без специального хака распространены следующие проблемы:
                Если ложить pythonXX.dll рядом с exe'шником, то проблем быть не должно…

                >py2exe — он ничего не распаковывает во временную
                Эм… Еще больше не понимаю.
                Грубо говоря, на выходе py2exe создается папка, с exe запускалкой, и со всем необходимым для переноса приложения (dll ки, pydы, library.zip), и все это «слинковано». А на выходе pyinstaller что? И что в linuxе получается?
                Я не призываю использовать py2exe, просто хочу выяснить как он работает. Не хотели бы вы написать более подробную статью?
                • +2
                  > Вот с этого места можно поподробней…
                  Подробнее — на официальном сайте. Вкратце: с помощью pyinstaller'a можно собирать самораспаковывающиеся инсталляторы (я бы их так назвал) для питоновских скриптов\проектов для нескольких различных ОС (Win, MacOS, Linux, Irix), в то время как py2exe умеет «мастерить» только экзешники.

                  > Если ложить pythonXX.dll рядом с exe'шником, то проблем быть не должно…
                  Дело не в питоновской либе (без неё вообще ничего не заработает), а в скомпиленных сишных модулях, которые вы можете использовать в питоновском коде. Например у вас сложный проект и вы используете PyWin32 и wxPython, которые содержат достаточного много .pyd файлов. Собрав свое приложение под Windows 7 и попробовав запустить его на Windows XP, вы с 90% вероятностью получите что-то типа этого: stackoverflow.com/questions/1979486/py2exe-win32api-pyc-importerror-dll-load-failed. А всё потому, что при сборке py2exe подхватывает по зависимости dll-ки из 7-ки и на Windows XP пытается импортировать оттуда необходимые функции, поэтому, собственно, и обламывается. Я в своё время писал что-то типа «билдовой системы» для сборки питон-проектов в экзешники, и там пришлось изучить все известные баги и ворэраунды для py2exe. А уж сколько там напильником пришлось допиливать для того чтобы добавить поддержку питона 2.6 — это я даже пересказывать не решусь.

                  > Грубо говоря, на выходе py2exe создается папка, с exe запускалкой, и со всем необходимым для переноса приложения (dll ки, pydы, library.zip), и все это «слинковано». А на выходе pyinstaller что? И что в linuxе получается?
                  Напишу как работает вкратце:

                  Pyinstaller: собирает все используемые в проекте модули и зависящие от них модули в одну папку, туда же идут pywintypes.dll и pythonXX.dll в одну директорию и запаковывает её в архив, этот архив присоединяется к bootloader'у — это маленький бинарничек, который выполняет всю полезную работу, а именно распаковывает архив в темповую директорию и запускает оттуда нужный скрипт.

                  Py2exe: алгоритм почти такой-же за исключением того, что 1) бутлоадер не распаковывает архив, а извлекает необходимые из него модули на лету, необходимость определяется специальным хуком на импорт модулей (находится в файле zipextimporter.py), 2) если правильно настроите параметр bundle_files, то можно включить pythonXX.dll в сам бутлоадер и он будет загружать её из самого экзешника (это может привезти к ошибкам загрузки некоторых сторонних модулей)
                  • 0
                    >этот архив присоединяется к bootloader'у — это маленький бинарничек, который выполняет всю полезную работу, а именно распаковывает архив в темповую директорию и запускает оттуда нужный скрипт.
                    Вот именно это нужно было узнать. Спасибо! То есть отдавать конечное приложение можно в виде одного исполняемого файла, который не требует установки.
                    И последний вопрос: есть ли возможность «на лету» менять содержимое этого архива? То есть «запихивать» обратно измененный файл с настройками программы?
                    • +1
                      > И последний вопрос: есть ли возможность «на лету» менять содержимое этого архива? То есть «запихивать» обратно измененный файл с настройками программы?

                      Ну теоретически такая возможность есть (я имею ввиду метод add в файле archive.py), но она влечет за собой несколько сложных махинаций с экзешником, поэтому я настоятельно советую ей не пользоваться.
                      • 0
                        Полиморфный вирус на питоне? xD
                        • 0
                          Будете смеяться, из вики:
                          Некоторые антивирусы распознают Frets on Fire для Win32 как вирус. Это происходит из‑за того, что игра скомпилирована в исполняемый файл с помощью утилиты py2exe(англ.), которая так же использовалась для создания кейлоггера Backdoor.Rajump. При создании вирусного описания этого кейлоггера была допущена ошибка, что и является причиной ложной идентификации игры как вируса
              • 0
                >> Так как планируемые приложения могли быть запущены не только на ос, в которых установлен сам Python, было решено собирать exe

                У меня была похожая задача, мне нужно было сваять пару утилит для клиента. Мне по душе Java/C#/Ruby но решил что эти языки не очень подходят для быстрых клиентских утилит.

                Случайно нашел для себя язык Vala live.gnome.org/Vala/Tutorial

                Тот же C# но создает *очень* быстрый код. Быстрее/сравнимый с С++, но программы куда более читабельные чем С/С++ code.google.com/p/vala-benchmarks/wiki/BenchResults
                • 0
                  Одно дело «быстрая» утилита, другое дело «быстро написать» утилиту. У автора поста второй случай, у вас первый.

                  И да — хорошо, когда клиент на Linux, а если под Windows? Vala уже позволяет писать Win-приложения?
                  • 0
                    >> Одно дело «быстрая» утилита, другое дело «быстро написать» утилиту. У автора поста второй случай, у вас первый.

                    У меня и первый (нужно нативное приложение) и второй случай одновременно :) Плюс я пытался выучить что-нибудь новое. Вначале выбирал между Go и D в результате написал на Vala. Мне понравилось что синтакс очень близок к Java/C#

                    > И да — хорошо, когда клиент на Linux, а если под Windows?
                    На Linux/MacOSX работает отлично. К сожалению на windows не пробывал. Официально GLIB/GTK имеются под эту операционку www.gtk.org/download-windows.html но подозреваю что использование Vala под Windows не лишено подводных камней.
                • +2
                  мне больше cx_Freeze подошел (http://cx-freeze.sourceforge.net/)

                  тоже кросс платформенный, и работает сходу. более того python 3.1 поддерживает, а py2exe и pyinstaller

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