msbuild msbuild-propertygroup

MSBuild Property Scope



msbuild-propertygroup (2)

Una vez más estoy luchando contra MSBuild. Quiero tener un valor de propiedad definido con una ruta raíz. Como parte de la compilación, la ruta se actualizará con la información de la versión. Sin embargo, MSBuild parece tener sus propias reglas de alcance que parecen completamente al revés. Tomemos este primer ejemplo:

<?xml version="1.0" encoding="utf-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> <PropertyGroup> <MyPath>//server/folder</MyPath> </PropertyGroup> <Target Name="Main"> <Message Text="In Main Before - MyPath = $(MyPath)"/> <CallTarget Targets="Task1" /> <CallTarget Targets="Task2" /> <CallTarget Targets="Task3" /> <Message Text="In Main After - MyPath = $(MyPath)"/> </Target> <Target Name="Task1"> <PropertyGroup> <MyPath>$(MyPath)/version5</MyPath> </PropertyGroup> <Message Text="In Task1 - MyPath = $(MyPath)"/> </Target> <Target Name="Task2"> <Message Text="In Task2 - MyPath = $(MyPath)"/> </Target> <Target Name="Task3"> <Message Text="In Task3 - MyPath = $(MyPath)"/> </Target> </Project>

Aquí está la salida con esta línea de comando: msbuild PropertyScopeTest1.proj /target:Main

Project "C:/Temp/PropertyScopeTest1.proj" on node 1 (Main target(s)). Main: In Main Before - MyPath = //server/folder Task1: In Task1 - MyPath = //server/folder/version5 Task2: In Task2 - MyPath = //server/folder/version5 Task3: In Task3 - MyPath = //server/folder/version5 Main: In Main After - MyPath = //server/folder Done Building Project "C:/Temp/PropertyScopeTest1.proj" (Main target(s)).

Ahora, aquí hay una versión ligeramente diferente que configura la variable MyPath en el objetivo principal:

<?xml version="1.0" encoding="utf-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> <PropertyGroup> <MyPath>//server/path</MyPath> </PropertyGroup> <Target Name="Main"> <Message Text="In Main Before - MyPath = $(MyPath)"/> <PropertyGroup> <MyPath>$(MyPath)/version5</MyPath> </PropertyGroup> <Message Text="In Main After PropertyGroup - MyPath = $(MyPath)"/> <CallTarget Targets="Task1" /> <CallTarget Targets="Task2" /> <CallTarget Targets="Task3" /> <Message Text="In Main After - MyPath = $(MyPath)"/> </Target> <Target Name="Task1"> <Message Text="In Task1 - MyPath = $(MyPath)"/> </Target> <Target Name="Task2"> <Message Text="In Task2 - MyPath = $(MyPath)"/> </Target> <Target Name="Task3"> <Message Text="In Task3 - MyPath = $(MyPath)"/> </Target> </Project>

Aquí está la salida con esta línea de comando: msbuild PropertyScopeTest2.proj /target:Main

Project "C:/Temp/PropertyScopeTest2.proj" on node 1 (Main target(s)). Main: In Main Before - MyPath = //server/path In Main After PropertyGroup - MyPath = //server/path/version5 Task1: In Task1 - MyPath = //server/path Task2: In Task2 - MyPath = //server/path Task3: In Task3 - MyPath = //server/path Main: In Main After - MyPath = //server/path/version5 Done Building Project "C:/Temp/PropertyScopeTest2.proj" (Main target(s)).

He visto otros enlaces en este sitio que son similares, pero todos parecen estar llamando a la tarea de MSBuild desde el archivo de proyecto de MSBuild. Todo lo que quiero hacer es actualizar la ruta y tenerla disponible en todas partes del proyecto. ¿Algunas ideas?


Esta es una pregunta muy interesante que se investiga a fondo con ejemplos en el siguiente artículo: Ámbito de propiedades y elementos en un script de MSBuild

Básicamente, hay trucos con un contexto local y global que cambia a través de las ejecuciones de destino:

  • Se crea una instancia de la clase Project para la secuencia de comandos y contiene todos los valores de las propiedades y los elementos en un contexto global.
  • Cuando se ejecuta un objetivo, el contexto global se copia en un contexto local que será utilizado por el objetivo.
  • Al final de la ejecución de destino, las actualizaciones del contexto local se fusionan de nuevo al contexto global.
  • Hasta que finaliza una ejecución de destino, las actualizaciones locales no son accesibles para los destinos llamados usando CallTarget o tareas de MSBuild

Sobre la base de la respuesta de sll, hacer que el objetivo que establece la nueva ruta sea una dependencia en lugar de usar CallTarget producirá el comportamiento esperado:

<?xml version="1.0" encoding="utf-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> <PropertyGroup> <MyPath>//server/folder</MyPath> </PropertyGroup> <Target Name="Main" DependsOnTargets="SetMyPathProperty"> <Message Text="In Main Before - MyPath = $(MyPath)"/> <CallTarget Targets="Task1" /> <Message Text="In Main After - MyPath = $(MyPath)"/> </Target> <Target Name="SetMyPathProperty"> <PropertyGroup> <MyPath>$(MyPath)/version5</MyPath> </PropertyGroup> </Target> <Target Name="Task1"> <Message Text="In Task1 - MyPath = $(MyPath)"/> </Target> </Project>

Salida de construcción:

Main: In Main Before - MyPath = //server/folder/version5 Task1: In Task1 - MyPath = //server/folder/version5 Main: In Main After - MyPath = //server/folder/version5

Hacer que SetMyPathProperty sea una dependencia de Task1 en lugar de Main resultará en un comportamiento idéntico a su PropertyScopeTest1.proj.