2011-09-23 18 views
20

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. Tome este primer ejemplo:MSBuild Propiedad Scope

<?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 comandos: 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í es una versión ligeramente diferente estableciendo la variable de 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 llamar a la tarea MSBuild desde el archivo del proyecto MSBuild. Todo lo que quiero hacer es actualizar la ruta y tenerla disponible en todas partes del proyecto. ¿Algunas ideas?

Respuesta

23

Sobre la base de la respuesta de SLL, haciendo que el objetivo que establece el nuevo camino de una dependencia en lugar de utilizar CallTarget rendirá 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> 

Construir salida:

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

Haciendo SetMyPathProperty una dependencia de Tarea1 en lugar de principal dará lugar a un comportamiento idéntico a su PropertyScopeTest1.proj.

+0

Esta solución tiene mucho más sentido para mí. Planeo probar esto mañana y ver si funcionará para mi caso de uso. – dprice

+0

Acabo de probar esta solución y es exactamente lo que quería. ¡Muchas gracias! – dprice

16

Ésta es una pregunta muy interesante que se investigó profundamente con ejemplos en el siguiente artículo: Scope of properties and item in an MSBuild script

Básicamente hay trucos con un contexto local y global switches en toda ejecuciones objetivo:

  • Uno instancia de la clase Proyecto se crea para el script y contiene todos los valores de las propiedades y elementos en un contexto global .
  • Cuando se ejecuta un destino, el contexto global se copia en un contexto local que será utilizado por el destino.
  • A al final de la ejecución del objetivo, las actualizaciones del contexto local se fusionan de vuelta al contexto global.
  • Hasta una ejecución de destino ha terminado las actualizaciones locales no son accesibles a los objetivos llamadas usando CallTarget o MSBuild tareas