2009-01-23 25 views
10

Estoy considerando correr MSBuild desde un script Powershell tocando directamente a las asambleas de MSBuild (en lugar de mirar hacia arriba MSBuild ruta de instalación y msbuild.exe comenzando como un proceso hijo).¿Cómo ejecutar MSBuild desde Powershell sin generar el proceso msbuild.exe?

¿Alguien ha hecho esto? ¿Cuál sería la forma más simple y directa de ejecutar la compilación? ¿Hay algún pros/contra para cualquiera de las técnicas que te gustaría señalar? (Estoy especialmente interesado en cualquier problema que pueda surgir al ejecutar msbuild en el mismo proceso/appdomain que el resto del script).

Actualmente mi pensamiento es algo a lo largo de estas líneas:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') 
[void][Microsoft.Build.BuildEngine.Engine]::GlobalEngine.BuildProjectFile("path/main.proj") 

Respuesta

14

La invocación de construcción integrada más simple que funcionó y produjo la salida fue:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') 
$engine = New-Object Microsoft.Build.BuildEngine.Engine 
$engine.RegisterLogger((New-Object Microsoft.Build.BuildEngine.ConsoleLogger)) 
$engine.BuildProjectFile('fullPath\some.proj') 

Sin embargo, resulta que la incorporación de MSBuild directamente en Powershell (V1) es problemática:

'MSBUILD : warning MSB4056: The MSBuild engine must be called on 
a single-threaded-apartment. Current threading model is "MTA". 
Proceeding, but some tasks may not function correctly.' 

Por qué oh ¿por qué seguimos pagando impuestos COM en 2009 mientras se trabaja en un entorno administrado?

Mi conclusión es que la incorporación de MSBuild en Powershell (V1) no es una buena idea.Como referencia, también estoy incluyendo el enfoque basado en procesos que terminé usando:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') 
$msbuild = [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkFile("msbuild.exe", "VersionLatest") 
&$msbuild fullPath\some.proj 
3

Un enfoque diferente y potencialmente más útil sería hacer un cmdlet msbuild. MsBuild tiene una buena API y hay muchas muestras sobre cómo usarlo desde un lenguaje compilado como C#/VB. Sería muy fácil crear un cmdlet que proporcione una sintaxis mucho más agradable a sus scripts de PowerShell.

+3

Bueno, esa es mi pregunta: ¿tiene algún vínculo a "las muchas muestras sobre cómo usarlo" o proporcione el suyo? –

5

yo muy sugeriría mirar PSake.

Vamos a citar una parte de esa página:

Recuerde que psake es el azúcar sintáctica alrededor de PowerShell. Entonces, cualquier cosa que pueda hacer en PowerShell, puede hacerlo en psake. Eso significa que puede ejecutar MSBuild, NAnt u otros scripts. No hay necesidad de reemplazar completamente su sistema de compilación actual. ¡Puedes usar psake para automatizarlo y ampliarlo!

psake añade automáticamente la versión adecuada de .NET Framework a su paso. De modo que puede acceder a MSBuild, csc.exe, vbc.exe o cualquier otra herramienta instalada en $ env: windir \ Microsoft.NET \ Framework \ $ version \ sin la ruta completa.

+2

Por favor, no entremos en el debate filosófico sobre 'msbuild sucks, use build basado en powershell', ya que esa no era mi pregunta, realmente. –

+0

¿De qué debate filosófico estás hablando? ¿Leíste la página? Proporciona una forma simple de envolver MSBuild. – EBGreen

+0

Sí, leí la página. Y está describiendo esta herramienta de compilación "sin impuestos de paréntesis XML". Utilicé rake antes de cambiar a msbuild y no voy a volver :-). El mecanismo que utiliza psake para invocar msbuild es que lo agrega a 'path', es decir, proceso externo. Eso es exactamente lo que no quiero. –

3

que estaba buscando esta misma cosa. Siguiendo el ejemplo de JaredPar encontré la siguiente:

Esta es una guía sobre cómo hacer un cmdlet.

http://bartdesmet.net/blogs/bart/archive/2008/02/03/easy-windows-powershell-cmdlet-development-and-debugging.aspx

La API de MSBuild es parte de estos espacios de nombres:

Microsoft.Build.Framework 

Microsoft.Build.BuildEngine 

Y la documentación MSBuild se puede encontrar aquí (esto es más de lo completo que en respuesta a su pregunta):

http://msdn.microsoft.com/en-us/library/wea2sca5.aspx

+0

Gracias Anthony, pero mover el código de PowerShell puro a cmdlet es realmente solo optimización de rendimiento/conveniencia. Estoy interesado en los pasos/códigos, así como también en los errores para usar Microsoft.Build.BuildEngine directamente. Puedo mover la impl real entre ps1 y cmdlet con bastante facilidad. –

+0

Tengo secuencias de comandos msbuild en muchos lugares diferentes, y quería poder ejecutar algo desde un lugar central. Si terminas con una respuesta funcional, me encantaría ver una publicación en el blog o algo así. –

+0

Véase también http://stackoverflow.com/questions/78069/any-good-powershell-msbuild-tasks –

0

Hubo un tiempo en que he estado jugando con el correr aumentada MSBuild procesos (como, omitir algunas partes de la construcción más agresivamente).

Había dos opciones:

  1. anfitrión MSBuild en su propio proceso de cargar sus archivos DLL.
  2. Spawn MSBuild.exe de la manera habitual y luego inyéctelo (por ejemplo, los registradores proporcionan una manera decente).

Implementé ambos y tuve que abandonar el # 1 porque no era lo suficientemente flexible.

Por ejemplo, MSBuild tiene una carga de redireccionamientos de enlace de ensamblaje en su archivo .config.

El proceso de Visual Studio (devenv.exe) que también aloja MSBuild con su API termina copiándolos en su devenv.exe.config. La mina .exe.config también tenía que tener esto, pero te adhiere a una versión específica de MSBuild. Y, por supuesto, tienes que modificar la configuración. Lo cual no es una opción con la PS en realidad, así que dudo que pueda obtener una solución realmente estable.

Cuestiones relacionadas