Компиляция проекта WPF IronPython для exe
Как лучше всего упаковать приложение IronPython для развертывания? После очистки веб-страницы лучшая вещь, которую я придумал (и то, что я сейчас делаю), использует clr.CompileModules()
для склеивания всех моих файлов проекта .py в одну .dll, а затем с одним run.py
do это для запуска dll:
import clr
clr.AddReference('compiledapp.dll')
import app
Это все еще субоптимально, потому что это означает, что я должен
- распределите 3 файла (пуск
.dll
, .xaml
и run.py
)
- установить IronPython на хост-машине
Плюс, это так... хакки, после замечательной интеграции IronPython уже с Visual Studio 2010. Я полностью озадачен тем, почему нет интегрированной системы сборки для IPy-приложений, поскольку все это сводится к IL в любом случае.
В идеале я хочу иметь один .exe
с .xaml
, объединенный внутри каким-то образом (я читал, что приложения С# компилируют XAML в BAML и объединяют их в исполняемый файл), и без необходимости установки IronPython бежать. Это, по крайней мере, на полпути? (Я полагаю, это нормально, если exe нуждается в некоторых дополнительных DLL с ним или что-то в этом роде. Важная часть состоит в том, что он в .exe-форме.)
Некоторые изменения для уточнения: Я пробовал pyc.py, но, похоже, не признает тот факт, что мой проект не просто app.py
. Размер exe, который он производит, предполагает, что он просто "компилирует" app.py
без включения каких-либо других файлов в exe. Итак, как мне сказать, чтобы скомпилировать каждый файл в моем проекте?
Чтобы визуализировать это, вот скриншот окна моего проекта для проектного решения.
Изменить II: Кажется, что, к сожалению, единственный способ - использовать pyc.py
и передать в него каждый файл в качестве параметра. Для этого подхода есть два вопроса:
- Как я могу обработать большую командную строку? В команде должно быть не более 256 символов.
- Как pyc.py знает, как сохранить структуру пакета/папки? Как показано в скриншоте моего проекта выше, как моя скомпилированная программа знает, чтобы получить доступ к модулям, находящимся во вложенных папках, например, к доступу к DT\Device? Является ли иерархия каким-то образом "сохраненным" в dll?
Изменить III. Поскольку прохождение 70 имен файлов в pyc.py
через командную строку будет громоздким, и в интересах решения проблемы построения проектов IPy более элегантно, я решил увеличить pyc.py
.
Я добавил код, который читается в файле .pyproj
с помощью параметра /pyproj:
, анализирует XML и захватывает список файлов py, используемых в проекте. Это работает очень хорошо; однако исполняемый файл, похоже, не может получить доступ к подпакетам python (подпапкам), которые являются частью моего проекта. Моя версия pyc.py
с моим патчем поддержки поддержки .pyproj
можно найти здесь: http://pastebin.com/FgXbZY29
Когда этот новый pyc.py
запускается в моем проекте, это вывод:
c:\Projects\GenScheme\GenScheme>"c:\Program Files (x86)\IronPython 2.7\ipy.exe"
pyc.py /pyproj:GenScheme.pyproj /out:App /main:app.py /target:exe
Input Files:
c:\Projects\GenScheme\GenScheme\__init__.py
c:\Projects\GenScheme\GenScheme\Agent.py
c:\Projects\GenScheme\GenScheme\AIDisplay.py
c:\Projects\GenScheme\GenScheme\app.py
c:\Projects\GenScheme\GenScheme\BaseDevice.py
c:\Projects\GenScheme\GenScheme\BaseManager.py
c:\Projects\GenScheme\GenScheme\BaseSubSystem.py
c:\Projects\GenScheme\GenScheme\ControlSchemes.py
c:\Projects\GenScheme\GenScheme\Cu64\__init__.py
c:\Projects\GenScheme\GenScheme\Cu64\agent.py
c:\Projects\GenScheme\GenScheme\Cu64\aidisplays.py
c:\Projects\GenScheme\GenScheme\Cu64\devmapper.py
c:\Projects\GenScheme\GenScheme\Cu64\timedprocess.py
c:\Projects\GenScheme\GenScheme\Cu64\ui.py
c:\Projects\GenScheme\GenScheme\decorators.py
c:\Projects\GenScheme\GenScheme\DeviceMapper.py
c:\Projects\GenScheme\GenScheme\DT\__init__.py
c:\Projects\GenScheme\GenScheme\DT\Device.py
c:\Projects\GenScheme\GenScheme\DT\Manager.py
c:\Projects\GenScheme\GenScheme\DT\SubSystem.py
c:\Projects\GenScheme\GenScheme\excepts.py
c:\Projects\GenScheme\GenScheme\FindName.py
c:\Projects\GenScheme\GenScheme\GenScheme.py
c:\Projects\GenScheme\GenScheme\PMX\__init__.py
c:\Projects\GenScheme\GenScheme\PMX\Device.py
c:\Projects\GenScheme\GenScheme\PMX\Manager.py
c:\Projects\GenScheme\GenScheme\PMX\SubSystem.py
c:\Projects\GenScheme\GenScheme\pyevent.py
c:\Projects\GenScheme\GenScheme\Scheme.py
c:\Projects\GenScheme\GenScheme\Simulated\__init__.py
c:\Projects\GenScheme\GenScheme\Simulated\Device.py
c:\Projects\GenScheme\GenScheme\Simulated\SubSystem.py
c:\Projects\GenScheme\GenScheme\speech.py
c:\Projects\GenScheme\GenScheme\stdoutWriter.py
c:\Projects\GenScheme\GenScheme\Step.py
c:\Projects\GenScheme\GenScheme\TimedProcess.py
c:\Projects\GenScheme\GenScheme\UI.py
c:\Projects\GenScheme\GenScheme\VirtualSubSystem.py
c:\Projects\GenScheme\GenScheme\Waddle.py
Output:
App
Target:
ConsoleApplication
Platform:
ILOnly
Machine:
I386
Compiling...
Saved to App
Так что он правильно читается в списке файлов в .pyproj
... Отлично! Но запуск exe дает мне это:
Unhandled Exception: IronPython.Runtime.Exceptions.ImportException:
No module named Cu64.ui
Итак, хотя Cu64\ui.py
, очевидно, включен в компиляцию, exe при запуске не может его найти. Это то, чего я боялся в пункте № 2 в предыдущем редактировании. Как сохранить иерархию пакетов моего проекта? Возможно, может понадобиться компиляция каждого пакета?
Я увеличу щедрость за этот вопрос. В конце концов, я надеюсь, что мы сможем получить рабочую pyc.py, которая читает файлы pyproj и создает рабочие exes за один шаг. Тогда, возможно, его даже можно было бы отправить в CodePlex IronPython для включения в следующую версию...;]
Ответы
Ответ 1
Он "сводится к IL", но он несовместим с IL, который производит код С#, поэтому его нельзя напрямую скомпилировать в автономный .exe файл.
Вам нужно будет использовать pyc.py
для компиляции вашего кода в заглушку EXE с DLL, которую создает CompileModules.
Затем распределите эти файлы с IronPython.dll
, IronPython.Modules.dll
, Microsoft.Dynamic.dll
, Microsoft.Scripting.Debugging.dll
, Microsoft.Scripting.dll
и, конечно, файл XAML.
Чтобы скомпилировать другие файлы, просто добавьте их в качестве аргументов:
ipy.exe pyc.py /main:app.py /target:winexe another.py another2.py additional.py
Ответ 2
Используйте pyc.py
для создания app.exe
и не забудьте включить библиотеки app.dll
и IronPython.
Что касается XAML - я создал проект только для файлов .xaml
, которые я компилирую в VS, а затем использую их из IronPython. Например:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/CompiledStyle;component/Style.xaml" />
</ResourceDictionary.MergedDictionaries>
Ответ 3
Я разместил Python script, который может взять файл IronPython, выяснить его зависимости и скомпилировать лот в автономный двоичный файл Ironpython 2.6.py → .exe. Надеюсь, вы найдете ее полезной. Он также должен работать для WPF, поскольку он объединяет поддержку WPF.
Ответ 4
Чтобы создать набор сборок для приложения IronPython, чтобы вы могли его распространять, вы можете использовать pyc.py или SharpDevelop.
Скомпилировать с помощью pyc.py:
ipy.exe pyc.py/main:Program.py Form.py File1.py File2.py.../target: winexe
Учитывая количество файлов в вашем проекте, вы можете попробовать использовать SharpDevelop вместо поддержки длинной командной строки для pyc.py. Вам нужно будет создать новый проект IronPython в SharpDevelop и импортировать ваши файлы в проект. Вам, вероятно, придется импортировать файлы по одному за раз, поскольку у SharpDevelop отсутствует способ импортировать несколько файлов, если они не находятся в подпапке.
Затем вы можете использовать SharpDevelop для компиляции приложения в исполняемый файл и dll. Все остальные необходимые файлы, такие как IronPython.dll, Microsoft.Scripting.dll, будут находиться в папке bin/debug или bin/release. SharpDevelop использует clr.CompileModules и пользовательскую задачу MSBuild за кулисами для генерации двоичных файлов.
Любые пакеты IronPython, определенные в вашем проекте, должны быть доступны из вашего приложения после компиляции.
Упаковка XAML может быть выполнена путем встраивания xaml в качестве ресурса. Затем используйте код, похожий на следующий:
import clr
clr.AddReference('PresentationFramework')
clr.AddReference('System')
from System.IO import FileMode, FileStream, Path
from System.Reflection import Assembly
from System.Windows import Application
from System.Windows.Markup import XamlReader
executingAssemblyFileName = Assembly.GetEntryAssembly().Location
directory = Path.GetDirectoryName(executingAssemblyFileName)
xamlFileName = Path.Combine(directory, "Window1.xaml")
stream = FileStream(xamlFileName, FileMode.Open)
window = XamlReader.Load(stream)
app = Application()
app.Run(window)
SharpDevelop 3.2 не вставляет файлы ресурсов правильно, поэтому вам нужно будет использовать SharpDevelop 4.
Если вы используете IronPython 2.7, вы можете использовать новый метод clr.LoadComponent, который принимает объект и либо имя файла XAML, либо поток и прокладывает этот объект в XAML.
В то время как компилятор С# может скомпилировать ваш XAML в ресурс BAML, делая то же самое с IronPython, есть несколько проблем. Если вы не связываете XAML с классом через атрибут x: Class, тогда можно скомпилировать XAML в ресурс BAML и внедрить его в свою сборку. Однако вы не получите никакого автогенерированного кода, поэтому вам нужно будет создать этот код самостоятельно. Другая проблема заключается в том, что это не будет работать из коробки с SharpDevelop. Вам нужно будет отредактировать файл SharpDevelop.Build.Python.targets и изменить его с Python на С#. Попытка использовать атрибут x: Class не будет работать, поскольку читатель BAML не сможет получить доступ к любому связанному классу IronPython. Это связано с тем, что сгенерированный ИЛ в скомпилированном приложении IronPython сильно отличается от того, что в сборке С# или VB.NET.
Ответ 5
Я установил Visual Studio 2015 с PTVS (ironpython 2.7). Я создал очень простой проект WPF и не смог скомпилировать exe. Я всегда получал исключение "ImportError: No module wpf".
import clr
clr.AddReferenceToFileAndPath("c:\\path\\to\\IronPython.Wpf.dll")
clr.AddReferenceToFileAndPath('c:\\path\\to\\PresentationCore.dll')
clr.AddReferenceToFileAndPath('c:\\path\\to\\PresentationFramework.dll')
clr.AddReferenceToFileAndPath('c:\\path\\to\\WindowsBase.dll')
from System.Windows import Application, Window
import wpf
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'RegExTester.xaml')
def OnSearch(self, sender, e):
self.tbOut.Text = "hello world"
if __name__ == '__main__':
Application().Run(MyWindow())
Я получил ошибку, потому что предложение clr должно быть до импорта wpf. Шаги для его компиляции:
python -m pip install ironpycompiler
- скомпилируйте приложение, например
ipy2asm компилировать -t winexe -e -s program.py