Ironpython 2.6 .py -> .exe
Я уже пытался использовать py2exe (не совместимый с ipy) и PYC (устарел). Кто-нибудь может указать мне в направлении хорошего компилятора?
5 ответов
Ты можешь использовать pyc.py
компилятор командной строки Python, который включен в IronPython начиная с версии 2.6 для компиляции скрипта Python в исполняемый файл. Вы найдете это в %IRONPYTONINSTALLDIR%\Tools\Scripts\pyc.py
на вашем жестком диске.
пример
Давайте предположим, что у вас есть простой скрипт test.py
это просто выводит что-то на консоль. Вы можете превратить его в исполняемый файл с помощью следующей командной строки (при условии, что каталог IronPython является текущим каталогом и что test.py
там тоже)
ipy.exe Tools\Scripts\pyc.py /main:test.py /target:exe
Примечание: если вы используете формы и не хотите открывать окно консоли, вы хотите использовать /target:winexe
вместо /target:exe
,
Результатом будут два файла, test.dll
а также test.exe
, test.dll
будет содержать ваш реальный код скрипта, в то время как test.exe
это просто пусковая установка для test.dll
, Вы можете распространять этот EXE и DLL на другие компьютеры, на которых не установлен IronPython, если вы включаете файлы
IronPython.dll
,Microsoft.Dynamic.dll
,Microsoft.Scripting.Core.dll
,Microsoft.Scripting.Debugging.dll
,Microsoft.Scripting.dll
,Microsoft.Scripting.ExtensionAttribute.dll
а такжеIronPython.Modules.dll
(иногда нужно).
Также смотрите запись в блоге IronPython - как скомпилировать exe.
Это давний вопрос, о котором в Интернете очень мало информации. Единственное известное решение, которое я могу найти, находится по адресу http://community.sharpdevelop.net/blogs/mattward/archive/2010/03/16/CompilingPythonPackagesWithIronPython.aspx котором используется SharpDevelop. Однако это решение нецелесообразно, поскольку любой полусложный проект на Python будет выполнять МНОЖЕЕ импорта модулей, а решение SharpDevelop требует создания проекта для каждого импорта. Я начал с этого и сдался после тридцати новых проектов, лучше написать автоматизированное решение!
Итак, вот мое решение, и я предупрежу вас прямо сейчас, что оно не выпущено как правильный проект по уважительной причине:
#!/usr/bin/env python
# CompileToStandalone, a Python to .NET ILR compiler which produces standalone binaries
# (C) 2012 Niall Douglas http://www.nedproductions.biz/
# Created: March 2012
import modulefinder, sys, os, subprocess, _winreg
if len(sys.argv)<2:
print("Usage: CompileEverythingToILR.py <source py> [-outdir=<dest dir>]")
sys.exit(0)
if sys.platform=="cli":
print("ERROR: IronPython's ModuleFinder currently doesn't work, so run me under CPython please")
sys.exit(1)
sourcepath=sys.argv[1]
destpath=sys.argv[2][8:] if len(sys.argv)==3 else os.path.dirname(sys.argv[0])
ironpythonpath=None
try:
try:
keyh=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\IronPython\\2.7\\InstallPath")
ironpythonpath=_winreg.QueryValue(keyh, None)
except Exception as e:
try:
keyh=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\IronPython\\2.7\\InstallPath")
ironpythonpath=_winreg.QueryValue(keyh, "")
except Exception as e:
pass
finally:
if ironpythonpath is not None:
_winreg.CloseKey(keyh)
print("IronPython found at "+ironpythonpath)
else:
raise Exception("Cannot find IronPython in the registry")
# What we do now is to load the python source but against the customised IronPython runtime
# library which has been hacked to work with IronPython. This spits out the right set of
# modules mostly, but we include the main python's site-packages in order to resolve any
# third party packages
print("Scanning '"+sourcepath+"' for dependencies and outputting into '"+destpath+"' ...")
searchpaths=[".", ironpythonpath+os.sep+"Lib"]
searchpaths+=[x for x in sys.path if 'site-packages' in x]
finder=modulefinder.ModuleFinder(searchpaths)
finder.run_script(sourcepath)
print(finder.report())
modules=[]
badmodules=finder.badmodules.keys()
for name, mod in finder.modules.iteritems():
path=mod.__file__
# Ignore internal modules
if path is None: continue
# Ignore DLL internal modules
#if '\\DLLs\\' in path: continue
# Watch out for C modules
if os.path.splitext(path)[1]=='.pyd':
print("WARNING: I don't support handling C modules at '"+path+"'")
badmodules.append(name)
continue
modules.append((name, os.path.abspath(path)))
modules.sort()
print("Modules not imported due to not found, error or being a C module:")
print("\n".join(badmodules))
raw_input("\nPress Return if you are happy with these missing modules ...")
with open(destpath+os.sep+"files.txt", "w") as oh:
oh.writelines([x[1]+'\n' for x in modules])
cmd='ipy64 '+destpath+os.sep+'pyc.py /main:"'+os.path.abspath(sourcepath)+'" /out:'+os.path.splitext(os.path.basename(sourcepath))[0]+' /target:exe /standalone /platform:x86 /files:'+destpath+os.sep+'files.txt'
print(cmd)
cwd=os.getcwd()
try:
os.chdir(destpath)
retcode=subprocess.call(cmd, shell=True)
finally:
os.chdir(cwd)
sys.exit(retcode)
Это было написано для IronPython v2.7.2 RC1 с использованием его новой автономной двоичной функции, и это действительно работает. Вы получаете автономный файл.exe, который полностью автономен - ему больше ничего не нужно устанавливать. Сценарий работает путем анализа импорта для предоставленного сценария и отправки всего лота в pyc.py. Это хорошие новости.
Плохие новости заключаются в следующем:
- ModuleFinder в IronPython v2.7.2 RC1 не работает, поэтому приведенный выше сценарий необходимо запустить с использованием CPython. Затем он использует CPython ModuleFinder, но против настроенной библиотеки времени выполнения IronPython. Да, я поражен, что это работает так же хорошо...
- Выходные данные бинарных файлов начинаются с 8 МБ. Простой модульный тест весил 16 Мб. Есть много вещей, которые не должны быть там, например, он добавляет поддержку Wpf и немного больше, но все же они не малы.
- Время загрузки намного медленнее, чем в автономном режиме. Подумайте о сорока секундах для автономного модульного теста на быстром Intel Core 2 и о трех секундах для автономного. Если скомпилировано только для x86, то оно падает до десяти секунд.
- Производительность во время выполнения ниже, чем в автономном режиме, примерно на 40%. Если скомпилировано только для x86, производительность примерно удваивается. Вот почему я оставил в /platform:x86 выше.
- Существует хорошо известная ошибка в поддержке кодировок и кодеков CPython, когда ModuleFinder вообще не включает никакой поддержки кодеков, если вы не укажете ее вручную. Так, например, если вы используете UTF-8 с codecs.open(), тогда вам НУЖНО "импортировать из кодировок utf_8 как some_unique_identifier", чтобы вызвать зависимость.
- Выше предполагается, что модифицированный pyc.py может принимать параметр / files, так как ограничение длины командной строки легко превышается. Вы можете изменить свой собственный pyc.py тривиально, если нет, я представил улучшение для включения в следующий IronPython.
Итак, поехали. Это работает, но решение все еще нуждается в более зрелом подходе. Удачи!
Проверьте страницу образцов IronPython
Примерно на полпути вниз по странице:
Pyc - компилятор командной строки Python В этом примере показано, как создавать исполняемые файлы.NET непосредственно из сценариев IronPython. Readme.htm в загрузке поможет вам начать.
Хостинговые API IronPython могут использоваться для компиляции скриптов Python в библиотеки DLL, исполняемые файлы консоли или исполняемые файлы Windows. Сценарий pyc.py, включенный в это руководство, использует эти API-интерфейсы хостинга и может использоваться для компиляции других скриптов Python. Он предоставляет различные флаги, такие как возможность указать целевую платформу сборки.NET (например, x64).
Хотя сборки, создаваемые API-интерфейсами IronPython Hosting, являются настоящими.NET-сборками, динамическая природа языка Python затрудняет использование их из других языков.NET. Короче говоря, это означает, что не рекомендуется пытаться импортировать типы Python в другие языки.NET, такие как C#.
Изменить: Только что заметил, что вы упомянули PYC устарел. Что делает это так? Команда IronPython, похоже, все еще продвигает его, поэтому я думаю, что это не так уж далеко.
У меня была небольшая проблема, пытаясь реализовать это решение. Вот что я сделал:
- Загрузите pyc отсюда. Это заняло у меня больше поисков, чем следовало бы, потому что кажется, что Pyc трудно найти (и я думаю, немного устарели)
- Я извлек папку pyc из zip-файла и добавил ее в свою папку IronPython в
C:\Program Files
- Теперь я попытался запустить эту команду на консоли Windows, как указано в readme в загрузке pyc:
ipy.exe pyc.py other_hw.py /main:console_hw.py
Это дало мне эту ошибку:
Traceback (most recent call last):
File "pyc\pyc.py", line 35, in pyc\pyc.py
AttributeError: attribute 'CompilerSink' of 'namespace#' object is read-only
Я сделал следующее изменение в строке 35:
До: class PycSink(Hosting.CompilerSink):
После: class PycSink():
Сохранение файла оказалось проблемой из-за разрешений, поэтому я скопировал содержимое pyc.py в новое окно IDLE (для создания копии), удалил существующую копию pyc.py
и сохранил копию как pyc.py
в том же месте. Это решает проблемы с разрешениями и позволяет вносить изменения.
После внесения этого изменения я попытался снова запустить команду:
ipy.exe pyc.py other_hw.py /main:console_hw.py
Однако на этот раз я получил следующую ошибку:
Traceback (most recent call last):
File "pyc\pyc.py", line 170, in pyc\pyc.py
File "pyc\pyc.py", line 56, in Main
AttributeError: attribute 'ResourceFile' of 'namespace#' object is read-only
В этот момент я подвел итоги того факта, что сейчас 1 час ночи, и у меня завтра среднесрочный период, поэтому я отменил изменения и закрыл их.
Пожалуйста, дайте мне знать, если у вас есть решение или какие-либо улучшения по моему.
Да, мне было слишком сложно скомпилировать исполняемый файл, поэтому я вернулся к использованию стандартного Python. Они должны дать хороший учебник по этому на сайте IronPython