将IronPython WPF项目编译为exe

23 投票
5 回答
9628 浏览
提问于 2025-04-16 05:55

如何将一个IronPython应用程序打包以便部署呢?我在网上查找了很多资料,目前我采用的最佳方法是使用clr.CompileModules()将我整个项目的.py文件合并成一个.dll文件,然后通过一个单独的run.py来运行这个dll:

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

import app

不过,这种方法还是不太理想,因为我需要:

  1. 分发三个文件(.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里。那么,我该如何告诉它编译我项目中的每一个文件呢?

为了帮助理解,这里有一个我项目的解决方案资源管理器窗口的截图。


编辑 II:不幸的是,似乎唯一的办法就是使用pyc.py,并将每一个文件作为参数传递给它。我对此方法有两个问题:

  1. 我该如何处理这么长的命令行?命令的最大字符数是256。
  2. 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 个回答

5

我发布了一个Python脚本,这个脚本可以处理IronPython文件,找出它所依赖的内容,然后把所有东西打包成一个独立的可执行文件,具体可以参考这个链接:Ironpython 2.6 .py -> .exe。希望你觉得这个工具有用。它应该也适用于WPF,因为它包含了WPF的支持。

5

使用 pyc.py 来生成 app.exe,别忘了把 app.dll 和 IronPython 的库也包含进去。

至于 XAML 文件,我专门创建了一个项目来处理 .xaml 文件,我在 Visual Studio 中编译这些文件,然后再从 IronPython 中使用它们。例如:

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

这段话的意思是,虽然最终的结果是要变成IL(中间语言),但是它和C#代码生成的IL不兼容,所以不能直接编译成一个独立的.exe文件。

你需要用pyc.py这个工具,把你的代码编译成一个带有DLL的“空壳”EXE文件,这个DLL是CompileModules创建的。

然后,你需要把这些文件一起分发,包括IronPython.dllIronPython.Modules.dllMicrosoft.Dynamic.dllMicrosoft.Scripting.Debugging.dllMicrosoft.Scripting.dll,当然还有XAML文件。

如果你想编译其他文件,只需要把它们作为参数添加进去就可以了,像这样:ipy.exe pyc.py /main:app.py /target:winexe another.py another2.py additional.py

撰写回答