2010-10-22 34 views
22

¿Cuál es la mejor manera de empaquetar una aplicación IronPython para su implementación? Después de recorrer la Web, lo mejor que he encontrado (y lo que estoy haciendo actualmente) es usar clr.CompileModules() para unir todos los archivos .py de todo el proyecto en un .dll, y luego tener un solo run.py hacer esto para ejecutar el DLL:Compilación de un proyecto IronPython WPF a exe

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

import app 

Esto sigue siendo subóptima, sin embargo, porque significa que tengo que

  1. distribuir 3 archivos (el .dll, la .xaml, y el run.py lanzador)
  2. Instalar IronPython en el máquina host

Además, esto se siente tan ... hacky, después de la maravillosa integración IronPython ya con Visual Studio 2010. Estoy completamente desconcertado por qué no hay un sistema de construcción integrado para aplicaciones API, ya que todo se reduce a IL de todos modos.

Idealmente, quiero ser capaz de tener una sola .exe con el .xaml fusionaron en el interior de alguna manera (leí que C# aplicaciones compilan XAML a BAML y se funden en el ejecutable), y sin necesidad de IronPython para ser instalado para funcionar. ¿Es esto al menos a medio camino posible? (Supongo que está bien si el exe necesita algunas .DLLs adicionales con ella o algo La parte importante es que es en .exe formulario..)


Algunas modificaciones para aclarar: He tratado pyc. py, pero parece no reconocer el hecho de que mi proyecto no es solo app.py. El tamaño del exe que produce sugiere que simplemente 'compila' app.py sin incluir ninguno de los otros archivos en el exe. Entonces, ¿cómo le digo que compile todos los archivos de mi proyecto?

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


Editar II: Parece que, lamentablemente, la única manera es utilizar pyc.py y pasar cada archivo a ella como un parámetro. Hay dos preguntas que tengo para este enfoque:

  1. ¿Cómo puedo procesar una línea de comando tan grande? Hay un máximo de 256 caracteres en un comando.
  2. ¿Cómo sabe pyc.py preservar la estructura del paquete/carpeta? Como se muestra en la captura de pantalla de mi proyecto anterior, ¿cómo sabrá mi programa compilado acceder a los módulos que están en subcarpetas, como el acceso a DT \ Dispositivo? Es la jerarquía de alguna manera "conservada" en el dll?

Editar III: Desde 70 nombres de archivo que pasa a través de pyc.py la línea de comandos será difícil de manejar, y con el fin de resolver el problema de la construcción de los proyectos del API más elegante, he decidido aumentar pyc.py .

He agregado el código que se lee en un archivo .pyproj a través del parámetro /pyproj:, analiza el XML y toma de allí la lista de archivos py utilizados en el proyecto. Esto ha estado funcionando bastante bien; sin embargo, parece que el ejecutable producido no puede acceder a los subpaquetes de python (subcarpetas) que forman parte de mi proyecto. Mi versión de pyc.py con mi parche de apoyo .pyproj lectura se puede encontrar aquí: http://pastebin.com/FgXbZY29

Cuando esta nueva pyc.py se ejecuta en mi proyecto, esta es la salida:

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 

Por lo tanto, leer correctamente en la lista de archivos en el .pyproj ... ¡Genial! Pero correr el exe me da esto:

Unhandled Exception: IronPython.Runtime.Exceptions.ImportException: 
No module named Cu64.ui 

Así que, aunque Cu64\ui.py es, obviamente, incluido en la compilación, el exe, cuando se ejecuta, no puede encontrarlo. Esto es a lo que le tenía miedo en el punto n. ° 2 de la edición anterior. ¿Cómo conservo la jerarquía de paquetes de mi proyecto? ¿Quizás compilar cada paquete por separado puede ser necesario?

Extenderé la recompensa por esta pregunta. En última instancia, mi esperanza es que podamos obtener un pyc.py que funcione y que se lea en archivos pyproj y produzca archivos en un solo paso. Entonces tal vez incluso podría enviarse al codeplex de IronPython para ser incluido en la próxima versión ...;]

+1

La longitud de la línea de comando es de 8191 caracteres (http://support.microsoft.com/kb/830473). 'clr.CompileModules' maneja bien los paquetes - los reconoce a través de' __init __. py' como es usual para los paquetes de Python. –

+0

Sí, puede usar clr.CompileModules y luego crear un stub .exe que cargue el .dll. Creo que hay una función LoadAssembly en algún lugar que se puede usar en C#. – jcao219

+0

Ah, quise decir que 'pyc.py' usa' clr.CompileModules', que maneja bien los paquetes.Así que solo use pyc.py y debería funcionar ;-) –

Respuesta

5

"se reduce a IL", pero no es compatible con la IL que produce el código C#, por lo no se puede compilar directamente en un archivo .exe independiente. Tendrá que usar pyc.py para compilar su código en un stub EXE con la DLL que crea CompileModules. Luego distribuya esos archivos con IronPython.dll, IronPython.Modules.dll, Microsoft.Dynamic.dll, Microsoft.Scripting.Debugging.dll, Microsoft.Scripting.dll y, por supuesto, el archivo XAML.

para compilar otros archivos, hay que añadirlas como argumentos: ipy.exe pyc.py /main:app.py /target:winexe another.py another2.py additional.py

+0

Muy interesante. Le daré pyc.py otra oportunidad. – Aphex

+0

'ipy.exe pyc.py /main:app.py/target: winexe' produce un pequeño app.exe de 3kb que no hace nada. ¿Hay algo más que deba hacer aquí? – Aphex

+0

También produce app.dll. Distribuya eso con los dlls mencionados anteriormente y su archivo XAML. – jcao219

5

Uso pyc.py para producir app.exe y no se olvide de incluir app.dll y IronPython bibliotecas.

En cuanto a XAML - He creado un proyecto solo para archivos .xaml que compilo en VS y luego los uso de IronPython. Por ejemplo:

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

De acuerdo, he luchado con pyc.py y todavía no entiendo cómo hacer que use todos los archivos que necesito. Mi proyecto consiste en 78 archivos en 5 carpetas y se ejecuta ejecutando app.py; sin embargo, como mencioné en mi comentario a jcao219 ejecutando 'ipy.exe pyc.py/main: aap.py/target: winexe' produce un app.exe inútil que no hace nada cuando se inicia. – Aphex

+0

Te recomiendo que comiences con la aplicación hola mundo simple. Intentar hacer que trabajar 78 archivos sea demasiado. Comience con un archivo, que agregue otro, luego subcarpeta, etc. También se ejecuta su aplicación cuando la inicia de forma simple: 'ipy.exe app.py'? –

+0

Sí, 'ipy.exe app.py' funciona muy bien. Por cierto, agregué una captura de pantalla de mi estructura de proyecto actual a la primera publicación ... Estoy empezando a pensar que necesito dar TODOS mis archivos a pyc.py como parámetros de línea de comandos. ¿Es esto ** realmente ** la forma en que debo construir y distribuir mis aplicaciones IPy? Escriba 'ipy.exe pyc.py app.py <78 .py archivos aquí> /main:app.py/target: winexe'? – Aphex

3

Para crear un conjunto de ensamblajes para su aplicación IronPython para que pueda distribuirlo se puede utilizar pyc.py o SharpDevelop.

Para compilar usando pyc.py:

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

Dada la cantidad de archivos en su proyecto podría intentar usar SharpDevelop en lugar de mantener una larga línea de comando para pyc.py. Tendrá que crear un nuevo proyecto IronPython en SharpDevelop e importar sus archivos al proyecto. Probablemente necesite importar los archivos de uno en uno, ya que SharpDevelop no tiene una forma de importar varios archivos a menos que estén en una subcarpeta.

A continuación, puede utilizar SharpDevelop para compilar su aplicación en un archivo ejecutable y un dll. Todos los demás archivos necesarios, como IronPython.dll, Microsoft.Scripting.dll, estarán en la carpeta bin/debug o bin/release. SharpDevelop utiliza clr.CompileModules y una tarea personalizada de MSBuild detrás de escena para generar los binarios.

Cualquier paquete de IronPython definido en su proyecto debe poder utilizarse desde su aplicación después de la compilación.

El empaquetado del XAML se puede realizar mediante la incrustación del xaml como recurso. Luego, utilizando un código similar al siguiente:

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 no incrusta archivos de recursos correctamente por lo que tendrá que utilizar SharpDevelop 4.

Si está utilizando IronPython 2.7 puede utilizar la nueva clr.LoadComponent método que toma un objeto y un nombre de archivo XAML o secuencia y conecta ese objeto al XAML.

Mientras que el compilador de C# puede compilar su XAML en un recurso BAML haciendo lo mismo con IronPython tiene algunos problemas. Si no vincula el XAML a una clase a través del atributo x: Clase, entonces es posible compilar el XAML en un recurso BAML y tenerlo incrustado en su ensamblaje. Sin embargo, no obtendrá ningún código autogenerado, por lo que deberá crearlo usted mismo. Otro problema es que esto no funcionará de manera inmediata con SharpDevelop. Deberá editar el archivo SharpDevelop.Build.Python.targets y cambiar el de Python a C#. Intentar utilizar el atributo x: Class no funcionará, ya que el lector BAML no puede acceder a ninguna clase asociada de IronPython. Esto se debe a que el IL generado en la aplicación IronPython compilada es muy diferente al de un ensamblado C# o VB.NET.

+0

Gracias por la descripción sobre SharpDevelop. Podría ser algo para probar, aunque estoy reacio a pasar de Visual Studio 2010 a un IDE diferente. Consulte mi edición reciente para obtener información sobre lo que he estado haciendo para que pyc lea todos mis archivos; Estoy muy cerca de hacer que funcione. – Aphex

5

Publiqué una secuencia de comandos de Python que puede tomar un archivo de IronPython, descubrir sus dependencias y compilar el lote en un archivo binario independiente en Ironpython 2.6 .py -> .exe. Esperamos que te sea útil. Debería funcionar también para WPF, ya que agrupa el soporte de WPF.

2

Instalé Visual Studio 2015 con PTVS (ironpython 2.7). Creé un proyecto WPF muy simple y no pude compilar un exe. Siempre obtuve la excepción "ImportError: ningún módulo llamado 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()) 

La falla que obtuve fue porque la cláusula clr debe estar antes de la importación wpf. Pasos para compilarlo:

  1. instalación pip para CPython 2.7 (no IronPython!)

  2. instalar ipy2asm

python -m pip install ironpycompiler

  1. compilar el aplicación como

ipy2asm compile -t winexe -e -s program.py

Cuestiones relacionadas