2011-01-26 15 views
6

No me importa una repetición ocasional de algo cuando es necesario, pero en MSBuild realmente no sé cómo alguna vez evitar la repetición. No ofrece "funciones" en el sentido habitual; un objetivo solo puede recibir una llamada una vez, incluso a través de CallTarget, y <Import> solo funciona en el nivel Project.¿Cómo evitar la repetición en MSBuild?

Aquí está un ejemplo específico que estoy tratando de- "repetize":

<Target Name="Tgt1"> 
    <PropertyGroup><Conf1>Twiddle</Conf1><Conf2>Thing</Conf2></PropertyGroup> 

    <PropertyGroup><xxxxxxxxxxExePath>$(xxxxxxxBuildRoot)\$(Conf1)Console-xxxxxxxxed</xxxxxxxxorExePath></PropertyGroup> 
    <MSBuild Projects="$(BuildSingleProj)" Targets="Build;Merge" 
      Properties="Configuration=$(Conf1)$(Conf2);Platform=$(Platform);CompiledFileName=$(CompiledFileName);ProjectName=$(ProjectName);SolutionFile=$(SolutionFile);Root=$(Root);Caller=$(MSBuildProjectFullPath)"/> 
    <MakeDir Directories="$(xxxxxxxxorExePath)" /> 
    <WriteLinesToFile File="$(xxxxxxxxorExePath)\xxxxxxx.IsPortable.txt" /> 
    <WriteLinesToFile File="$(xxxxxxxxorExePath)\xxxxxxx.Global.Settings.xml" Lines="@(xxxxxxxLicense)" Overwrite="true" /> 
    <Exec Command='$(xxxxxxxxorExePath)\xxxxxxx.exe -a "$(xxxxxxxBuildRoot)\$(Conf1)$(Conf2)-Merged\xxxxxxx.exe" "$(xxxxxxxBuildRoot)\$(Conf1)$(Conf2)-xxxxxxxxed\xxxxxxx.exe"'/> 
</Target> 

Tengo cuatro de estos objetivos, Tgt1, Tgt2, Tgt3, Tgt4. El único que difiere entre estos cuatro objetivos es la primera línea, la que define Conf1 y Conf2.

La única idea de deduplicación más o menos viable de la que soy consciente es moviendo el código compartido a un nuevo objetivo y llamándolo a través de la tarea MSBuild. Desafortunadamente, esto requiere una cadena de propiedades loooooong para pasarlas manualmente, y esta tarea usa algunas (conté 11 propiedades y 1 grupo de elementos).

Un requisito adicional es que puedo invocar el script con un arbitrario subconjunto de estos objetivos, p. \t:Tgt2,Tgt3.

¿Existe alguna alternativa sensata a la simple copia/pegado de este trozo de código, que no implique copiar enormes listas de propiedades en su lugar?

Respuesta

8

Este es un escenario perfecto para usar Batching.

Tendrá que crear Items personalizado con los metadatos apropiados y luego crear un único objetivo para hacer referencia a los nuevos elementos.

Puede envolver cada artículo en su propio destino, así:

<Target Name="Tgt1"> 
    <ItemGroup> 
    <BuildConfig Include="Tgt1"> 
     <Conf1>Twiddle</Conf1> 
     <Conf2>Thing</Conf2> 
    </BuildConfig> 
    </ItemGroup> 
</Target> 

<Target Name="Tgt2"> 
    <ItemGroup> 
    <BuildConfig Include="Tgt2"> 
     <Conf1>Twaddle</Conf1> 
     <Conf2>Thing 1</Conf2> 
    </BuildConfig> 
    </ItemGroup> 
</Target> 

<Target Name="Tgt3"> 
    <ItemGroup> 
    <BuildConfig Include="Tgt3"> 
     <Conf1>Tulip</Conf1> 
     <Conf2>Thing 2</Conf2> 
    </BuildConfig> 
    </ItemGroup> 
</Target> 

A continuación, tendrá un objetivo básico para llamar que llevará a cabo todo el trabajo de esta manera:

<Target Name="CoreBuild" Outputs="%(BuildConfig.Identity)"> 
    <Message Text="Name : %(BuildConfig.Identity)" /> 
    <Message Text="Conf1 : %(BuildConfig.Conf1)" /> 
    <Message Text="Conf2 : %(BuildConfig.Conf2)" /> 
</Target> 

Si agrega Outputs="%(BuildConfig.Identity)" al objetivo, se asegurará de que realice el lote en el nivel objetivo en lugar de en el nivel de la tarea.

Puede ejecutar esto desde msbuild con pasar combinaciones arbitrarias de los objetivos, siempre que el último objetivo sea su objetivo central. Por ejemplo la ejecución de este comando MSBuild.exe test.msbulid /t:Tgt1,Tgt3,CoreBuild le dará el siguiente resultado:

Name : Tgt1 
Conf1 : Twiddle 
Conf2 : Thing 

Name : Tgt3 
Conf1 : Tulip 
Conf2 : Thing 2 
+0

Pero esto significa que ya no puedo construir solo uno o solo dos de ellos, ¿correcto? Cualquier forma de preservar esa habilidad? –

+0

Puede poner condiciones en los artículos. Actualizaré la respuesta con un ejemplo. –

+0

Gracias, aunque puedo ver que las condiciones se vuelven bastante complicadas si quiero incluir cualquier _dos_ compilaciones. Actualmente, me inclino por mantener la repetición porque me gustaría mantener la capacidad de especificar '/ t: Tgt1, Tgt2'; el guión real en realidad tiene algunos objetivos más, y confiamos en la capacidad de seleccionar subconjuntos arbitrarios. Me gusta esto. –

5

seco no es un dogma de MSBuild. Dicho esto, no es bueno repetirlo en cualquier caso, cuando es razonablemente evitable. La respuesta que Aarón dio sobre el procesamiento por lotes es buena. Este es un medio para evitar la duplicación.

Una cosa que me gustaría señalar es que en un nivel superior parece que estás pensando en MSBuild como un lenguaje de procedimiento (es decir, que tienes funciones que puedes llamar y otras). MSBuild es mucho más declarativo que procesal.Si está creando scripts de MSBuild y tiene la mentalidad 'Crear función X para que pueda llamarlo en el punto Y', entonces está entrando en un mundo de dolor. En su lugar, debería pensar en MSBuild como fases. Por ejemplo; recopilar archivos, compilar, publicar, etc. Cuando lo piense de esta manera, tiene sentido que los objetivos se salten después de haberlos ejecutado una sola vez (, que obviamente ha observado durante las pruebas).

También después de haber trabajado con MSBuild durante el tiempo que he entendido que realmente puede ser un PITA hacer las cosas de forma genérica/súper reutilizable. Se puede hacer, pero me gustaría reservar ese tipo de esfuerzo para los archivos .targets que seguro se volverán a usar muchas veces veces. Ahora, en lugar de pasar por eso, soy mucho más pragmático y aterrizo en algún lugar entre las secuencias de comandos de hacking total & haciendo las cosas de la forma en que solía hacerlo. Tengo un conjunto de scripts que reutilizo, pero además de esos, intento mantener las cosas simples. Una gran razón para esto es que hay mucha gente que conoce los conceptos básicos de MSBuild, pero muy pocos que tienen un conocimiento muy profundo de esto. Crear buenos guiones genéricos requiere un profundo conocimiento de MSBuild, por lo que cuando abandones un proyecto, la persona que venga detrás de ti no tendrá idea de lo que estabas haciendo (quizás sea bueno si eres un contratista? Lol).

En cualquier caso, tengo un montón de recursos sobre procesamiento por lotes en: http://sedotech.com/Resources#Batching.

+0

Gracias por esta idea; con suerte me salvará intentando demasiado. He estado tratando de ver MSBuild como declarativo, pero seguramente incluso los lenguajes declarativos necesitan un mecanismo para crear abstracciones. Perdónenme por sugerir el nombre "funciones", ese es ciertamente el término equivocado. –

+0

Esperaba en secreto que hubiera algún mecanismo genial que yo desconocía. ¿Tal vez alguna forma de aliviar el dolor de pasar el _juego_ de más de 10 propiedades a varias tareas de MSBuild? Casi llegué allí, solo las propiedades se evaluaron demasiado pronto, y no pude encontrar nada como "eval" para evaluarlas justo cuando se pasan a MSBuild ... –

+0

Si quieres "evaluar" elementos, entonces necesita colocar el ItemGroup dentro de un objetivo que ejecutará. Los elmenets de ItemGroup fuera de los objetivos se evalúan antes de los ejercicios de destino, pero los elementos de ItemGroup dentro de los objetivos se evalúan en el momento en que se ejecuta el destino. –

Cuestiones relacionadas