Делаем standalone exe на IronPython

    Иногда требуется написать маленькую программу, которая будет распространяться в виде исполняемого файла, и при этом не хочется, чтобы с программой ещё было море файлов. Один exe-шник и всё, да при этом хочется, чтобы его написание не занимало много времени (какой-нибудь лёгкий язык).
    CPython в комплекте с py2exe или cx_Freeze не даёт требуемого результата: много файлов и большой размер программы, хотя и работает очень быстро. Хорошее решение смог получить в IronPython с помощью встроенного компилятора pyc. Даже IDE не потребовалась. Подробности под катом.

    Всё оказалось просто


    Допустим у вас уже установлен IronPython (замечание: приём работает в версии 2.7.2 и выше, спасибо Juralis). И у вас есть следующий исходный код:
    import clr
    clr.AddReference("System.Windows.Forms")
    
    from System.Windows.Forms import Application, Form
    
    class HabrForm(Form):
    
         def __init__(self):
             self.Text = 'Habr!'
             self.Name = 'Habr!'
    
    form = HabrForm()
    Application.Run(form)
    

    Сохраните его в файл mini.py. Зайдите в папку с программой из консоли и наберите следующую команду:
    ipy.exe C:\IronPython\Tools\Scripts\pyc.py /target:winexe /main:mini.py /standalone
    
    Если установить target в exe получите консольную программу, что удобно для отладки. Также можно сделать dll.

    Компилятор выдаст примерно что-то такое:
    Input Files:
    Output:
            mini
    Target:
            WindowApplication
    Platform:
            ILOnly
    Machine:
            I386
    Threading:
            STA
    
    Compiling...
    Generating stand alone executable
            Embedding Microsoft.Dynamic 1.1.0.20
            Embedding Microsoft.Scripting 1.1.0.20
            Embedding IronPython 2.7.0.40
            Embedding IronPython.Modules 2.7.0.40
            Embedding IronPython.SQLite 2.7.0.40
            Embedding IronPython.Wpf 2.7.0.40
    Saved to mini
    

    Exe-шник готов! Только учтите, что стандартной библиотеки в этой сборке нет. И это хорошо. Можно построить программу используя только clr модуль на быстрых .NET библиотеках.

    Подключение стандартной библиотеки


    Если нужна стандартная библиотека, то есть 2 способа подключения. Первый — скомпилировать всю папку Lib в одну dll и сделать AddReference. Есть готовое решение, но так программа работает слишком медленно!

    Я пошёл по другому пути. Учитывая, что IronPython имеет в составе встроенный модуль sys, а загрузчик модулей умеет читать модули из zip, то решение стало очевидным: запаковать содержимое папки Lib (из папки IronPython) и поместить рядом с exe файлом, при этом добавив следующий код:
    import sys
    sys.path.append(r'.\Lib.zip')
    

    Теперь можно импортировать другие модули, вроде json или urllib.
    Вот и всё, посмотрите как здорово это выглядит:
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 10

      +2
      Технология хорошая, но получившийся .exe весит 4 мегабайта и запускается больше 5 секунд на довольно быстром современном десктопе :(. Огорчает, что Iron- и J- версии python и ruby всего лишь портировали интерпритатор вместо того чтобы компилировать код питона в байткод соответствующей виртуальной машины.

      BTW, может знаете — какие такие у всех фатальные трудности скомпилировать исходник на питоне/руби в байткод CLR? Понятно что reflection и eval() потребуют дополнительной машинерии — но что там фатально сложного что никто даже не пытается и тянут с собой интерпретатор?
        +1
        Могу предположить, что всё дело в философии: Python компилируется только в Python bytecode, который можно прогнать через dis. А если поддерживать технологию компиляции напрямую в байткод виртуальной машины, это усложнит сам проект.

        Python, наверное, потому и получил популярность, что развивать его код было просто. Хотя, согласен, компиляция в другой байткод/naive была бы полезна.
          0
          Перестал таскать интерпретатор пару месяцев назад. Компиляция исходников в родные системе либы с помощью CPython и мелкий загрузчик в 3 строчки на чем угодно (лично я использую C#)
            0
            Отличное решение! Делитесь практической частью! )
              0
              Ну насчет компиляции в либы тут: habrahabr.ru/post/138537/, много граблей но лучшего решения для себя не нашел.
              Насчет загрузчика для C# — подключаем скомпилированную либу (dll/so) в проект, выполняем фунцкию из подключенной либы (есть небольшая зависимость кода от того что выполняем, но почти всегда это 1-2 строчки) :)
                0
                Ставлю в избранное ;)
            0
            Стандартом требуется reflection не только на модули-функции, а еще и на stack frame например. Не представляю, как сделать питоновский frame напрямую из clr frame.
            Встроенный интепретатор решает вопрос.
            JIT позволяет не слишком при этом тормозить.
            0
            py2exe/cx_Freeze так же умеют делать на выходе 2 файла (да и вообще по умолчанию именно так и делают)
            Ну а при чем тут CPython вообще непонятно.
              0
              Кстати, стоит оговориться, что ключ /standalone появился только в версии pyc.py поставляемой с IronPython 2.7.2. В этой же версии появился zipimport. Версии ниже не поддерживают sys.path.append(r'.\Lib.zip') Пруф
                0
                Добавил в текст. Спасибо!

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

              Самое читаемое