将IronPython WPF项目编译为exe
如何将一个IronPython应用程序打包以便部署呢?我在网上查找了很多资料,目前我采用的最佳方法是使用clr.CompileModules()
将我整个项目的.py文件合并成一个.dll文件,然后通过一个单独的run.py
来运行这个dll:
import clr
clr.AddReference('compiledapp.dll')
import app
不过,这种方法还是不太理想,因为我需要:
- 分发三个文件(
.dll
、.xaml
和run.py
启动器) - 在主机上安装IronPython
而且,这种做法感觉有点... 不太正规,毕竟IronPython已经和Visual Studio 2010有了很好的集成。我完全不明白为什么没有为IPy应用程序提供一个集成的构建系统,毕竟最终都是编译成IL的。
理想情况下,我希望能有一个单独的.exe
文件,里面能合并.xaml
(我听说C#应用程序会将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点中担心的。如何保留我项目的包层级结构?也许需要单独编译每个包?
我会延长这个问题的悬赏。最终我的希望是能得到一个可以读取pyproj文件并在一步中生成可用exe的pyc.py。然后也许它可以提交到IronPython的codeplex,纳入下一个版本... ;]
5 个回答
我发布了一个Python脚本,这个脚本可以处理IronPython文件,找出它所依赖的内容,然后把所有东西打包成一个独立的可执行文件,具体可以参考这个链接:Ironpython 2.6 .py -> .exe。希望你觉得这个工具有用。它应该也适用于WPF,因为它包含了WPF的支持。
使用 pyc.py
来生成 app.exe
,别忘了把 app.dll
和 IronPython 的库也包含进去。
至于 XAML 文件,我专门创建了一个项目来处理 .xaml
文件,我在 Visual Studio 中编译这些文件,然后再从 IronPython 中使用它们。例如:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/CompiledStyle;component/Style.xaml" />
</ResourceDictionary.MergedDictionaries>
这段话的意思是,虽然最终的结果是要变成IL(中间语言),但是它和C#代码生成的IL不兼容,所以不能直接编译成一个独立的.exe文件。
你需要用pyc.py
这个工具,把你的代码编译成一个带有DLL的“空壳”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