2011-09-23 11 views
20

Ancora una volta sto combattendo contro MSBuild. Voglio avere un valore di proprietà definito con un percorso di root. Come parte della build, il percorso verrà aggiornato con le informazioni sulla versione. Tuttavia, MSBuild sembra avere le proprie regole di scoping che sembrano completamente all'indietro. Prendete questo primo esempio:Ambito proprietà MSBuild

<?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> 

Ecco l'uscita con questa riga di 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)). 

Ora, ecco una versione leggermente diversa impostando la variabile MyPath nel target principale:

<?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> 

Ecco l'output con questa riga di 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)). 

Ho visto altri collegamenti su questo sito che sono simili, ma tutti sembrano chiamare l'attività MSBuild dal file di progetto MSBuild. Tutto quello che voglio fare è aggiornare il percorso e averlo a disposizione ovunque nel progetto. Qualche idea?

risposta

23

Sulla risposta di SLL, rendendo l'obiettivo che imposta il nuovo percorso una dipendenza invece di utilizzare CallTarget si produrrà il comportamento previsto:

<?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> 

Costruire in uscita:

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

Fare SetMyPathProperty una dipendenza di Task1 invece di principale porterebbe ad un comportamento identico al tuo PropertyScopeTest1.proj.

+0

Questa soluzione ha molto più senso per me. Ho intenzione di provare questo domani e vedere se funzionerà per il mio caso d'uso. – dprice

+0

Ho appena provato questa soluzione ed è esattamente quello che volevo. Grazie mille! – dprice

16

Questa è una domanda molto interessante, che è indagato a fondo con esempi nel seguente articolo: Scope of properties and item in an MSBuild script

Fondamentalmente ci sono trucchi con un contesto locale e globale passa attraverso un esecuzioni di destinazione:

  • One l'istanza della classe Project viene creata per lo script e contiene tutti i valori delle proprietà e degli elementi in un contesto globale .
  • Quando viene eseguito un target, il contesto globale viene copiato in un contesto locale che verrà utilizzato dalla destinazione.
  • A fine esecuzione obiettivo, gli aggiornamenti del contesto locale vengono uniti nel contesto globale.
  • Fino un'esecuzione bersaglio è finito gli aggiornamenti locali non sono accessibili ai bersagli chiamate usando CallTarget o MSBuild compiti