编译IronPython WPF项目到exe

时间:2010-10-22 17:43:22

标签: python wpf visual-studio-2010 ironpython

打包IronPython应用程序进行部署的最佳方法是什么?在浏览网页后,我提出的最好的事情(以及我目前正在做的事情)是使用clr.CompileModules()将我整个项目的.py文件粘合到一个.dll中,然后使用单个{{ 1}}这样做来运行dll:

run.py

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

  1. 分发3个文件(import clr clr.AddReference('compiledapp.dll') import app .dll.xaml启动器)
  2. 在主机上安装IronPython
  3. 另外,在IronPython与Visual Studio 2010进行了精彩的整合之后,感觉如此...... hacky。我完全不知道为什么没有针对IPy应用程序的集成构建系统,因为这一切都归结为IL无论如何。

    理想情况下,我希望能够以某种方式将run.py.exe内部合并(我读到C#apps将XAML编译为BAML并将其合并到可执行文件中),并且不需要要安装IronPython才能运行。这至少有一半可能吗? (我想如果exe需要一些额外的.DLL或者其他东西就可以了。重要的是它是.exe形式。)


    有些修改要澄清:我已经尝试了 pyc.py ,但似乎并不承认我的项目不只是.xaml。它产生的exe的大小表明它只是“编译”app.py而不包含任何其他文件到exe中。那么,我如何告诉它编译我的项目中的每个文件?

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


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

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

    3. 编辑III :由于通过命令行将70个文件名传递给pyc.py将是不实用的,为了解决更优雅地构建IPy项目的问题,我已经决定了增加pyc.py

      我添加了通过pyc.py参数读入.pyproj文件的代码,解析XML,并从那里获取项目中使用的py文件列表。这一直很好;但是,生成的可执行文件似乎无法访问属于我的项目的python子包(子文件夹)。我的/pyproj:版本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。那么也许它甚至可以提交给IronPython的codeplex以包含在下一个版本中......;]

5 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

使用pyc.py生成app.exe,不要忘记包含app.dll和IronPython库。

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

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

答案 2 :(得分:5)

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

答案 3 :(得分:3)

要为IronPython应用程序创建一组程序集以便分发它,您可以使用pyc.py或SharpDevelop。

使用pyc.py进行编译:

ipy.exe pyc.py /main:Program.py Form.py File1.py File2.py ... / target: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从C#更改为C#。尝试使用x:Class属性将无法工作,因为BAML阅读器无法访问任何关联的IronPython类。这是因为已编译的IronPython应用程序中生成的IL与C#或VB.NET程序集中生成的IL非常不同。

答案 4 :(得分:2)

我安装了带有PTVS的Visual Studio 2015(ironpython 2.7)。我创建了一个非常简单的WPF项目,但无法编译exe。我总是遇到异常“ImportError:没有名为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. 为CPython 2.7安装pip(不是ironpython!)

  2. 安装ipy2asm

  3.   

    python -m pip install ironpycompiler

    1. 编译应用程序,如
    2.   

      ipy2asm编译-t winexe -e -s program.py