2010-10-22 171 views
22

打包IronPython应用程序以进行部署的最佳方式是什么?在浏览网页后,我想到的最好的东西(以及我目前正在做的)是使用clr.CompileModules()将我整个项目的.py文件粘贴到一个.dll文件中,然后使用一个run.py来执行此操作DLL:将IronPython WPF项目编译为exe

import clr 
clr.AddReference('compiledapp.dll') 

import app 

这仍然是最理想的,但是,因为这意味着我必须

  1. 分发3个文件(.dll.xamlrun.py发射)
  2. 上安装IronPython的主机

另外,这感觉很......哈克,精彩整合后的IronPython已经与Visual Studio 2010中,我以为什么有IPY的应用程序没有集成构建系统完全被迷惑,看到这一切无论如何,它归结为IL。

理想情况下,我希望能够有一个.exe.xaml合并内以某种方式(我读的C#应用​​程序编译XAML来BAML和可执行合并它们),并且不需要进行安装IronPython的运行。这至少有一半可能吗? (我想这是确定的,如果exe文件需要用它或东西一些额外的.DLL文件最重要的部分是它的以.exe形式。)


有些修改,以澄清:我已经试过PYC。 py,但它似乎不承认我的项目不只是app.py。它产生的exe的大小表明它只是在编译'app.py而不包含任何其他文件到exe中。那么,我该如何告诉它来编译我的项目中的每个文件?

To help visualize this, here is a screenshot of my project's solution explorer window.


编辑II:看来,不幸的是,唯一的办法就是使用pyc.py并通过每一个文件把它作为一个参数。这个方法有两个问题:

  1. 我该如何处理一个大的命令行?命令中最多有256个字符。
  2. pyc.py如何知道如何保留包/文件夹结构?如上面我的项目屏幕截图所示,我的编译程序如何知道访问子文件夹中的模块,比如访问DT \ Device?这个层次结构是否“保存”在dll中?

编辑III:由于经过70名到pyc.py通过命令行会笨重,以及解决更优雅建筑IPY项目的问题的兴趣,我决定增加pyc.py

我已经添加了通过/pyproj:参数读取.pyproj文件的代码,解析XML,并从那里获取项目中使用的py文件列表。这一直工作得很好;但是,生成的可执行文件似乎无法访问作为我的项目一部分的python子包(子文件夹)。我与我的.pyproj阅读支持补丁pyc.py版本可以在这里找到: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运行时,无法找到它。这是我在之前的编辑中第二点中所害怕的。我如何保留我的项目的包层次结构?也许需要分别编译每个软件包?

我会延长这个问题的赏金。最终,我的希望是,我们可以得到一个可读取pyproj文件的工作pyc.py,并一步完成工作。那么它可能甚至会被提交给IronPython的codeplex以包含在下一个版本中...;]

+1

命令行长度为8191个字符(http://support.microsoft.com/kb/830473)。 'clr.CompileModules'很好地处理了包 - 它通过'__init __。py'识别它们,就像通常用于Python包一样。 – 2010-10-28 15:38:12

+0

是的,您可以使用clr.CompileModules,然后生成加载.dll的存根.exe文件。我认为有一个LoadAssembly函数可以在C#中使用。 – jcao219 2010-10-28 21:04:59

+0

啊 - 我的意思是'pyc.py'使用'clr.CompileModules'来处理软件包。所以只需使用pyc.py,它应该可以工作;-) – 2010-10-29 00:30:29

回答

5

它“归结为IL”,但它与C#代码生成的IL不兼容,所以它不能直接编译为独立的.exe文件。 您需要使用pyc.py将代码编译为带有CompileModules创建的DLL的存根EXE。 然后分配这些文件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

+0

非常有趣。我会再次尝试pyc.py。 – Aphex 2010-10-22 20:07:16

+0

'ipy.exe pyc.py/main:app.py/target:winexe'产生一个小小的3kb App.exe,它什么都不做。我还需要在这里做些什么吗? – Aphex 2010-10-22 20:09:26

+0

它也生产app.dll。用前面提到的那些dll和你的XAML文件分发它。 – jcao219 2010-10-22 22:29:48

5

使用pyc.py生产app.exe,不要忘了,包括app.dll和IronPython库。

至于XAML - 我创建的项目仅适用于在VS中编译的.xaml文件,然后在IronPython中使用它们。例如:

<ResourceDictionary.MergedDictionaries> 
    <ResourceDictionary Source="/CompiledStyle;component/Style.xaml" /> 
</ResourceDictionary.MergedDictionaries> 
+0

好吧,我已经与pyc.py而且我还不知道如何使它使用我需要的所有文件。我的项目包含5个文件夹中的78个文件,并通过运行app.py启动;然而,正如我在jcao219中对运行'ipy.exe pyc.py /main:app.py/target:quotexe'的注释中提到的那样,产生了一个无用的app.exe,它在启动时不会执行任何操作。 – Aphex 2010-10-26 19:29:07

+0

我建议你从简单的Hello World应用开始。试图使78个文件工作太多。从一个文件开始,添加另一个文件,然后添加子文件夹等。当您通过简单启动时,您的应用程序也会运行:'ipy.exe app.py'? – 2010-10-27 19:32:23

+0

是的,'ipy.exe app.py'运行良好。顺便说一下,我在第一篇文章中添加了当前项目结构的屏幕截图...我开始认为我需要将所有文件作为命令行参数提供给pyc.py。这真的**是我应该构建和发布我的IPy应用程序的方式吗?在这里输入'ipy.exe pyc.py app.py <78 .py文件> /main:app.py/target:winexe'? – Aphex 2010-10-27 20:47:28

3

要创建一套为您的IronPython的应用程序组件,让您可以分发您可以使用pyc.py或SharpDevelop的。

编译使用pyc.py:

ipy.exe pyc.py /main:Program.py Form.py File1.py File2.py ... /目标:winexe

鉴于量您可以尝试使用SharpDevelop而不是维护pyc.py的长命令行。您需要在SharpDevelop中创建一个新的IronPython项目并将您的文件导入到项目中。您可能需要一次导入一个文件,因为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。

虽然C#编译器可以将XAML编译为BAML资源,但与IronPython一样,它有一些问题。如果您不通过x:Class属性将XAML链接到类,则可以将XAML编译为BAML资源并将其嵌入到程序集中。但是,您不会得到任何自动生成的代码,因此您需要自己创建该代码。另一个问题是,这不会使用SharpDevelop。您需要编辑SharpDevelop.Build.Python.targets文件并将Python从Python更改为C#。尝试使用x:Class属性将不起作用,因为BAML阅读器无法访问任何关联的IronPython类。这是因为编译的IronPython应用程序中生成的IL与C#或VB.NET程序集中的生成的IL非常不同。

+0

感谢您对SharpDevelop的评论。尽管我很讨厌从Visual Studio 2010移植到不同的IDE,但这可能是一些尝试。查看我最近编辑的一些信息,了解我一直在做什么来让pyc阅读我所有的文件;我真的很接近它的工作。 – Aphex 2010-11-01 20:41:36

5

我发布了一个Python脚本,它可以接收一个IronPython文件,找出它的依赖关系,并将它编译成一个独立的二进制文件Ironpython 2.6 .py -> .exe。希望你觉得它有用。它也应该为WPF工作,因为它捆绑了WPF支持。

2

我用PTVS(ironpython 2.7)安装了Visual Studio 2015。我创建了一个非常简单的WPF项目,但无法编译exe文件。我总是得到异常“ImportError:No module named 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之前。步骤来编译:

  1. 安装pip为CPython的2.7(不IronPython的!)

  2. 安装ipy2asm

python -m pip install ironpycompiler

  • 编译应用如
  • ipy2asm compile -t winexe -e -s program.py