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.