IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Intégration Continue avec Visual Studio et Team Foundation Server - Partie II, Présentation de MsBuild et de TfsBuild

Intégration Continue avec Visual Studio et Team Foundation Server - Partie II, Présentation de MsBuild et de TfsBuild


précédentsommairesuivant

4. Aller plus loin avec MsBuild

Nous avons exposé jusque là le cas le plus basique d'un fichier de build. Nous allons maintenant aller beaucoup plus loin pour présenter les outils qui seront réellement nécessaires pour automatiser nos tâches quotidiennes.

4-1. S'assurer de la validité du fichier de build

 

Le fichier de build est un fichier XML et doit donc être valide par rapport aux spécifications XML. Il faut donc faire attention aux valeurs que l'on veut spécifier dans les éléments et dans les attributs.

Prenons deux exemples classiques d'erreurs dans un fichier XML :

Exemple d'erreurs dans un fichier de build et leurs corrections
Sélectionnez
<!-- Erreur car présence de "&" dans une balise -->
<ElementInvalide>Valeur 1 & Valeur 2</ElementInvalide>
<!-- Correction ici par un bloc CDATA -->
<ElementValide><![CDATA[Valeur1 & Valeur2]]></ElementValide>

<!-- Erreur car l'attribut possède un guillemet -->
<ElementAvecAttributInvalide Attribut="Je possede une (")"/>
<!-- Correction en utilisant le code ASCII -->
<ElementAvecAttributValide Attribut="Je possede une (%22)"/>

Pour corriger les erreurs tout en possédant un fichier cohérent, il faudra parfois avoir recours à des astuces, d'autant que certains caractères sont réservés par MsBuild et ne peuvent donc pas être utilisés tels quels. On pourra noter les astuces suivantes :

  • Utilisation de blocs CDATA pour protéger un élément
  • Utilisation de codes ASCII pour remplacer les caractères réservés par MsBuild
  • Utilisation de propriétés lorsque l'on n'est pas capable de protéger correctement ce que l'on veut mettre dans un attribut (dans la source ci-dessus, plutôt que d'utiliser « %22 », on aurait ainsi pu déplacer la valeur dans une propriété, et référencer la propriété. Nous verrons ici comment utiliser les propriétés)
  • Utilisation des correspondances HTML de certains caractères
Quelques caractères réservés et leurs équivalents protégés
Caractère réservé Caractère protégé
& &amp;
< &lt;
> &gt;
Caractère réservé Caractère ASCII
" %22
; %3B
* %2A


Pour voir la liste des codes ASCII, on peut aller voir sur www.asciitable.com ou dans la MSDN. Plus d'informations dans les annexes : « Table des codes ASCII ».

4-2. Propriétés d'un fichier de build : les Properties et PropertyGroup

 

4-2-1. Définition

On peut définir des Properties que l'on pourra utiliser dans notre fichier de projet.

Une property dans un fichier de build est très similaire à une propriété en .NET ou à une variable contenant une valeur simple (string, int, double, ...).

Ces propriétés pourront être créées statiquement - par simple déclaration dans le fichier - ou bien dynamiquement - lors de l'exécution du fichier de build.

4-2-2. Création statique de propriétés

 

Pour créer une property, on peut ajouter dans notre fichier un élément « PropertyGroup » qui peut regrouper plusieurs éléments, chacun d'entre eux étant une nouvelle property. Notez que l'on peut retrouver plusieurs éléments « PropertyGroup » dans un même fichier de projet.

Création de deux propriétés
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <PropertyGroup>
      <MaPropriete1>Test1</MaPropriete1>
      <MaPropriete2>Test2</MaPropriete2>
   </PropertyGroup>
   
</Project>

Dans le source ci-dessus, nous avons créé

  • Une propriété « MaPropriete1 » de valeur « Test1 »
  • Une propriété « MaPropriete2 » de valeur « Test2 »

4-2-3. Utilisation de Properties

Utiliser une propriété est très simple. Il suffit d'utiliser la syntaxe « $(NomPropriete) ».

Création de la propriété « FileNameWithExt » en utilisant deux propriétés
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <PropertyGroup>
      <FileName>Mastering Regular Expressions</FileName>
      <Extension>pdf</Extension>
      <FileNameWithExt>$(FileName).$(Extension)</FileNameWithExt>
   </PropertyGroup>
   
</Project>

Notez cependant qu'il est important que les propriétés soient définies avant leur appel. Pour cela, il est important de prendre en compte les différences signalées entre « PropertyGroup » et « CreateProperty » détaillées dans le point lié à la « Création dynamique des propriétés ».

4-2-4. Précaution d'emploi : Ordre de déclaration

 

Il faut être vigilant à l'ordre de création des propriétés. En effet la création des propriétés (définies via PropertyGroup) se fait lors de l'initialisation du fichier, mais ce, de haut en bas.

L'ordre de définition des propriétés est important
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <Message Text="Dans Target 1" />
      <Message Text="$(Prop1)" />
      <Message Text="$(Prop2)" />
   </Target>

   <PropertyGroup>
      <Prop1>Prop1 : $(PropBase)</Prop1>
      <PropBase>test</PropBase>
      <Prop2>Prop2 : $(PropBase)</Prop2>
   </PropertyGroup>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:16:51.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Dans Target 1
  Prop1 :
  Prop2 : test
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

Dans l'exemple ci-dessus, on se rend compte que l'affichage de la propriété Prop1 ne donne pas le résultat escompté, puisque l'on utilise PropBase qui est déclaré après Prop1. L'affichage de Prop2 quand à lui est bien correct.

On se rend compte alors que les propriétés on bien été initialisées avant l'exécution du Target, mais en respectant leur ordre de déclaration, du haut vers le bas.

4-2-5. Création dynamique de Properties

 

4-2-5-1. Définition

Il est également possible d'utiliser une tâche CreateProperty pour créer dynamiquement une propriété. Cela permet par exemple d'utiliser des variables qui sont retournées par une autre tâche.

4-2-5-2. Différence entre création statique et dynamique

Il faut cependant être très conscient des différences entre création statique et dynamique :

Création statique :

Toutes les variables (propriétés ou items) utilisées pour créer une propriété dans un PropertyGroup doivent exister au moment de la création (et donc il ne peut s'agir du résultat d'une méthode appelée au sein d'un target). En effet toutes les propriétés créées via un PropertyGroup sont initialisées au lancement du fichier

Création dynamique :

Si les propriétés créées dans un PropertyGroup sont visibles et existent à tout moment dans le fichier de Projet, celles créées par la tâche « CreateProperty » n'existent qu'une fois la tâche exécutée. Cependant il n'est pas possible de référencer une propriété si celle-ci est définie après son utilisation (voir l'exemple sur les ordres de déclaration).

4-2-5-3. Syntaxe de la tâche CreateProperty

La tâche CreateProperty prend en paramètre d'entrée la valeur de la propriété à créer et nous renvoie la valeur. Il faut alors l'associer au nom de la propriété que l'on veut créer. La syntaxe est similaire pour toutes les tâches ayant des paramètres de sorties (output). Plus synthétiquement, la syntaxe est la suivante :

Syntaxe de la tâche CreateProperty
Sélectionnez
<CreateProperty Value="Valeur de la propriété, par exemple: Hello">
  <Output TaskParameter="Value" 
          PropertyName="Le nom de la Property que l'on veut créer" />
</CreateProperty>

Value est le nom de la propriété de la tâche (propriété marquée avec un OutputAttribute) que l'on veut récupérer sous forme de Property. Dans le cas de la tâche CreateProperty, c'est la propriété « Value ».

4-2-5-4. Exemple d'utilisation

Dans l'exemple ci-dessous, nous allons créer une propriété « MaProprieteDynamique » (de valeur 'Test3') via la tâche CreateProperty. Cette propriété pourra être utilisée exactement de la même façon que celles créées via un PropertyGroup.

Création dynamique de propriété
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Target1">
    <CreateProperty Value="Test3">
      <Output TaskParameter="Value" PropertyName="MaProprieteDynamique" />
    </CreateProperty>

    <Message Text="$(MaProprieteDynamique)" />
  </Target>

</Project>

4-2-6. Changer la valeur d'une propriété

 

Si l'on désire changer la valeur d'une propriété, on peut également utiliser la tâche CreateProperty. Elle ne se contente en effet pas de créer une nouvelle propriété, mais également de mettre à jour la valeur, s'il existe déjà une propriété avec ce nom.

Création dynamique de propriété
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <PropertyGroup>
      <MaPropriete>Valeur initiale</MaPropriete>
   </PropertyGroup>
   
   <Target Name="Target1">
      <Message Text="$(MaPropriete)" />

      <CreateProperty Value="Nouvelle valeur">
         <Output TaskParameter="Value" PropertyName="MaPropriete"/>
      </CreateProperty>

      <Message Text="$(MaPropriete)" />
   </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:18:54.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Valeur initiale
  Nouvelle valeur
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.07

4-2-7. Différer la création d'un PropertyGroup

Nous avons vu dans la section « Création statique de propriétés » que les « PropertyGroup » étaient initialisés lors du lancement du fichier.

Il est cependant possible de différer leur initialisation de façon à ce que les PropertyGroup se comportent comme des propriétés dynamiques. Pour cela, il suffit de les placer au sein d'un Target.

Pour illustrer cet exemple, nous utilisons l'attribut DependsOnTarget. Nous le détaillerons dans la section « Contrôler l'ordre d'exécution des Targets ».
Supposons seulement à ce stade que le Target SetProprietes sera lancé avant le Target Main.

Création dynamique d'une propriété via un PropertyGroup
Sélectionnez
<Project DefaultTargets="Main"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Main" DependsOnTargets="SetProprietes">
      <Message Text="Ma Propriete Dynamique: $(MaProprieteDynamique)" />
   </Target>

   <Target Name="SetProprietes">
      <!-- Ici la propriété n'a pas encore été créée -->
      <Message Text="Ma Propriete Dynamique: $(MaProprieteDynamique)" />

      <!-- Là on va créer dynamiquement la propriété -->
      <PropertyGroup>
         <MaProprieteDynamique>Valeur</MaProprieteDynamique>
      </PropertyGroup>


      <!-- La propriété existe donc ici -->
      <Message Text="Ma Propriete Dynamique: $(MaProprieteDynamique)" />
   </Target>
</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 23/04/2009 8:15:04.
Project "D:\Fichiers de build\Création de propriétés via PropertyGroup.proj" on node 0 (default targets).
  Ma Propriete Dynamique:
  Ma Propriete Dynamique: Valeur
Main:
  Ma Propriete Dynamique: Valeur
Done Building Project "D:\Fichiers de build\Création de propriétés via PropertyGroup.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

Dans l'exemple ci-dessus, on remarque que le PropertyGroup n'a pas été initialisé lors du démarrage du fichier, mais bien lorsque le flot d'exécution est passé sur le PropertyGroup.

Cette syntaxe est en fait une version simplifiée de la tâche CreateProperty.

4-3. Listes d'un fichier de build : les Items et ItemGroup

4-3-1. Définition

Outre les propriétés, on peut également utiliser des Items qui sont une structure beaucoup plus complexe. On peut les comparer en fait à une collection d'objets non typés, chaque objet étant typiquement un type simple (int, string, ...) mais auquel on peut adjoindre des propriétés (appelées MetaData).

Les MetaData sont en fait des propriétés d'une des valeurs de l'Item. Toutes les valeurs d'un même Item ne doivent donc pas forcément posséder les mêmes MetaData.
Nous verrons plus clairement ce cas dans l'exemple proposé dans la partie traitant de la « création statique des items ».

4-3-2. Création statique d'Items

 

Comme les PropertyGroup pour les propriétés, on retrouve des ItemGroup pour la création d'Items. La syntaxe est cependant légèrement différente de par la définition possible des MetaData.

Création de plusieurs items
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Item1 Include="Item avec Metadata"
      <Display>True</Display>
      <AutreMetaData>Valeur</AutreMetaData>
    </Item1>

    <Item2 Include="Item sans Metadata" />
      
    <Item3 Include="Val1;Val2"/>
  </ItemGroup>
</Project>

Dans l'exemple ci-dessus, on a créé

  • Un item « Item1 » possédant une valeur « Item avec Metadata » lui-même composé de deux metadata
    • « Display » de valeur « True »
    • « AutreMetaData » de valeur « Valeur »
  • Un item « Item2 » possédant une valeur : « Item sans Metadata »
  • Un item « Item3 » possédant deux valeurs : « Val1 » et « Val2 »

Si l'on veut déclarer plusieurs valeurs dans un même item, on peut soit utiliser la syntaxe de « Item3 » ci-dessus, soit déclarer deux attributs XML de cette façon :

Création d'un item avec deux valeurs, chacune ayant des MetaData différentes
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Item1 Include="Val1"
      <Display>True</Display>
    </Item1>

    <Item1 Include="Val2"
      <AutreMetaData>Valeur</AutreMetaData>
    </Item1>
  </ItemGroup>
</Project>

C'est de cette façon que l'on peut spécifier des metadata différentes pour certaines valeurs d'un même item.

4-3-3. Utilisation d'Items

Pour utiliser un item, il faut utiliser la syntaxe « @(NomItem) ».

Pour accéder à une metadata particulière d'un Item, il suffit d'utiliser la syntaxe « %(NomItem.NomMetaData) » ou « %(NomMetaData) ». Cette deuxième syntaxe pourrait cependant échouer à la moindre ambiguïté et est d'ailleurs la plupart du temps à déconseiller en termes de lisibilité.

Récupération d'items et de MetaData
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup>
      <Item1 Include="Val1;Val2" />
      <Item2 Include="Test avec Display">
         <Display>True</Display>
      </Item2>
      <Item2 Include="Test sans Display">
         <Display>False</Display>
      </Item2>
   </ItemGroup>

   <Target Name="Target1">
      <Message Text="Item1 = @(Item1)" />
      <Message Text="Item2 = @(Item2)" />
      <Message Text="Item2.Display = %(Item2.Display)" />
   </Target>
   
</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:20:22.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Item1 = Val1;Val2
  Item2 = Test avec Display;Test sans Display
  Item2.Display = True
  Item2.Display = False
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.01

Comme on pouvait s'y attendre, demander la valeur d'Item2 va nous afficher la liste de ses différentes valeurs concaténées par un « ; ».

En demandant la valeur d'une metadata d'Item2, il y aura autant de lignes générées que de valeurs de l'item possédant la metadata demandée.

4-3-4. Création dynamique d'Items

 

4-3-4-1. Syntaxe et exemple

Il est également possible d'utiliser une tâche CreateItem pour créer dynamiquement un item.

La syntaxe sera très proche de celle de la tâche CreateProperty. Le grand avantage est que cela nous permet d'utiliser des conditions de création.

Création dynamique d'un item
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <MyValue>Hello</MyValue>
  </PropertyGroup>

  <ItemGroup>
    <Item2 Include="Test avec Display">
      <Display>True</Display>
    </Item2>
    <Item2 Include="Test sans Display">
      <Display>False</Display>
    </Item2>
  </ItemGroup>

  <Target Name="Target1">

    <CreateItem
      Include="@(Item2)"
      Condition="'%(Display)'=='true'"
      AdditionalMetadata="MonDisplay=%(Display);AutreMetaData=$(MyValue)">

      <Output
         TaskParameter="Include"
         ItemName="MonNouvelItemAvecMetadata"/>
    </CreateItem>

    <Message Text="@(MonNouvelItemAvecMetadata)" />
    <Message Text="%(MonNouvelItemAvecMetadata.MonDisplay)" />
    <Message Text="%(MonNouvelItemAvecMetadata.AutreMetaData)" />
  </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:21:26.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Test avec Display
  True
  Hello
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.04

Dans l'exemple ci-dessus, on créé dynamiquement un Item en spécifiant que

  • On veut le créer à partir de l'Item « Item2 » (qui possède deux valeurs : « Test avec Display » et « Test sans Display »)
  • En filtrant sur tous les Items « Item2 » pour lesquels on a une MetaData « Display » de valeur « true »
  • On veut ajouter deux nouvelles MetaData à toutes les valeurs de l'item que l'on veut créer, le premier étant simplement la valeur de la MetaData « Display » de l'Item inclus, et l'autre provenant d'une propriété

Notez que pour avoir plus d'informations sur les conditions possibles, vous pouvez vous référez à la bibliographie sur les conditions utilisables.

Notez enfin que ces conditions sont également utilisables sur un ItemGroup et un PropertyGroup au complet afin d'éviter la création de certaines variables qui pourraient être inutiles.

4-3-4-2. Cas particulier lors de l'utilisation de metadata

Notez que dans les AdditionalMetaData, on peut utiliser des Properties, des MetaData de l'Item que l'on inclut, ou des MetaData d'autres items. Dans ce dernier cas, s'il y a plusieurs valeurs de cet autre item possédant la MetaData souhaitée, chaque valeur de l'Item généré sera clonée afin que chaque valeur puisse posséder toutes les MetaData possibles. Voyons cela dans l'exemple ci-dessous :

Création dynamique d'un item avec metadata d'autres items - Exemple 1
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup>
      <Item1 Include="Test avec Display">
         <Display>True</Display>
      </Item1>
      <Item1 Include="Test sans Display">
         <Display>False</Display>
      </Item1>
   </ItemGroup>

   <Target Name="Target2">
      <CreateItem Include="Valeur"
                  AdditionalMetadata="Display=%(Item1.Display)">
         <Output TaskParameter="Include" ItemName="MonNouvelItem" />
      </CreateItem>
      
      <Message Text="MonNouvelItem = @(MonNouvelItem)" />
      <Message Text="MonNouvelItem.Display = %(MonNouvelItem.Display)" />
   </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:22:28.
Project "C:\Temp\build.proj" on node 0 (default targets).
  MonNouvelItem = Valeur;Valeur
  MonNouvelItem.Display = True
  MonNouvelItem.Display = False
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.04

Ici, nous avons donc créé un item en lui assignant une seule valeur (« Valeur »), et en lui assignant comme nouvelle metadata la valeur de la metadata « Display » de l'item Item1. Comme Item1 possède plusieurs éléments, et que ces éléments n'ont pas tous la même valeur pour la metadata « Display », alors le nouvel item contiendra deux éléments.

Si tous les éléments d'Item1 possédaient la même valeur pour « Display », alors ce clonage n'aurait pas lieu.

Création dynamique d'un item avec metadata d'autres items - Exemple 2
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup>
      <Item1 Include="Test avec Display">
         <Display>True</Display>
      </Item1>
      <Item1 Include="Test également avec Display">
         <Display>True</Display>
      </Item1>
   </ItemGroup>

   <Target Name="Target1">
      <CreateItem Include="Valeur"
                  AdditionalMetadata="Display=%(Item1.Display)">
         <Output TaskParameter="Include" ItemName="MonNouvelItem" />
      </CreateItem>
      
      <Message Text="MonNouvelItem = @(MonNouvelItem)" />
      <Message Text="MonNouvelItem.Display = %(MonNouvelItem.Display)" />
   </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:24:20.
Project "C:\Temp\build.proj" on node 0 (default targets).
  MonNouvelItem = Valeur
  MonNouvelItem.Display = True
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.07

4-3-5. Précautions lors de l'utilisation d'Items dans des tâches

Comme nous l'avons vu dans les exemples précédents, il faut bien prendre en compte le fait que les Items sont des collections de valeurs, et donc deux items différents pourraient avoir un nombre de valeurs différent et des metadata différentes. De même, deux valeurs d'un même item pourraient également avoir des metadata différentes. Par conséquent, il se peut que les tâches qui utilisent des items aient des comportements particuliers.

En effet, il est impossible de joindre dans une même collection des éléments différents de façon cohérente. MsBuild va donc automatiquement scinder les appels aux tâches lorsque plusieurs Items sont utilisés.

La tâche est appelée plusieurs fois pour chaque MetaData
Sélectionnez
<Project DefaultTargets="Target1"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
    <Item1 Include="ValeurItem1">
      <Data>La MetaData de l'Item1</Data>
    </Item1>
    <AutreItem Include="ValeurAutreItem">
      <Display>True</Display>
    </AutreItem>
  </ItemGroup>

  <Target Name="Target1">
    <Message Text="Item1: @(Item1) - Autre Item: @(AutreItem)" />
    <Message Text="Item1: %(Item1.Data) - Autre Item: %(AutreItem.Display)" />
  </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:25:23.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Item1: ValeurItem1 - Autre Item: ValeurAutreItem
  Item1: La MetaData de l'Item1 - Autre Item:
  Item1:  - Autre Item: True
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

De même si l'on complète l'exemple en ajoutant une nouvelle valeur pour l'item 1, le résultat aura une ligne supplémentaire.

La tâche est appelée plusieurs fois pour chaque MetaData
Sélectionnez
<Project DefaultTargets="Target1"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
    <Item1 Include="ValeurItem1">
      <Data>La MetaData de Item1</Data>
    </Item1>
    <Item1 Include="AutreValeurItem1">
      <Data>La MetaData de l'autre Item1</Data>
    </Item1>
    <AutreItem Include="ValeurAutreItem">
      <Display>True</Display>
    </AutreItem>
  </ItemGroup>

  <Target Name="Target1">
    <Message Text="Item1: @(Item1) - Autre Item: @(AutreItem)" />
    <Message Text="Item1: %(Item1.Data) - Autre Item: %(AutreItem.Display)" />
  </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:26:15.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Item1: ValeurItem1;AutreValeurItem1 - Autre Item: ValeurAutreItem
  Item1: La MetaData de Item1 - Autre Item:
  Item1: La MetaData de l'autre Item1 - Autre Item:
  Item1:  - Autre Item: True
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

Pour réellement concaténer ces valeurs, il faudrait passer par la création d'items ou de propriétés intermédiaires.

4-3-6. Différer la création d'un ItemGroup

De même que pour les PropertyGroup, il est possible de différer la création d'un ItemGroup de façon à ce que celui-ci ne soit pas initialisé au démarrage du fichier. Il suffit également de déplacer l'ItemGroup dans le target, à l'emplacement du flot d'exécution souhaité.

Pour illustrer cet exemple, nous utilisons l'attribut DependsOnTarget. Nous le détaillerons dans la section « Contrôler l'ordre d'exécution des Targets ».
Supposons seulement à ce stade que le Target SetProprietes sera lancé avant le Target Main.

 
Sélectionnez
<Project DefaultTargets="Main"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Main" DependsOnTargets="SetItem">
      <Message Text="Mon Item Dynamique: @(MonItemDynamique)" />
      <Message Text="Mon Item MetaData : %(MonItemDynamique.MetaData)" />
   </Target>

   <Target Name="SetItem">
      <!-- Ici l'item n'a pas encore été créée -->
      <Message Text="Mon Item Dynamique: @(MonItemDynamique)" />
      <Message Text="Mon Item MetaData : %(MonItemDynamique.MetaData)" />

      <!-- Là on va créer dynamiquement la propriété -->
      <ItemGroup>
         <MonItemDynamique Include="Valeur">
            <MetaData>Valeur MetaData</MetaData>
         </MonItemDynamique>
      </ItemGroup>

      <!-- L'item existe donc ici -->
      <Message Text="Mon Item Dynamique: @(MonItemDynamique)" />
      <Message Text="Mon Item MetaData : %(MonItemDynamique.MetaData)" />
   </Target>
</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 23/04/2009 8:26:11.
Project "D:\Fichiers de build\Création d'items via ItemGroup.proj" on node 0 (default targets).
  Mon Item Dynamique:
  Mon Item MetaData :
  Mon Item Dynamique: Valeur
  Mon Item MetaData : Valeur MetaData
Main:
  Mon Item Dynamique: Valeur
  Mon Item MetaData : Valeur MetaData
Done Building Project "D:\Fichiers de build\Création d'items via ItemGroup.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.01

4-4. Exécuter un fichier de build

 

Nous avions vu dans la section « Exécuter un fichier de build » la façon la plus simple pour exécuter un fichier. Il y a cependant d'autres façons de le faire, de façon à surcharger le comportement par défaut.

4-4-1. Exécution par défaut

Pour rappel, l'exécution la plus simple requiert uniquement le nom du fichier « .proj » à lancer. Dans ce cas, le target par défaut sera exécuté.

Le target par défaut sera déterminé comme suit :

  • Si un seul target dans le fichier, c'est celui-là qui sera lancé
  • Si plusieurs targets
    • Si l'un d'entre eux est marqué comme par défaut, alors c'est celui-là qui sera lancé (nous verrons plus d'informations sur la notion de target par défaut dans la section « Contrôler l'ordre d'exécution des Targets »)
    • Sinon, c'est le premier target présent dans le fichier qui sera lancé
MsBuild : Exécution d'un fichier de build
Sélectionnez
MsBuild BuildA.proj

4-4-2. Surcharge du target à exécuter

On peut cependant utiliser l'option « /target:NomTarget » ou « /t:NomTarget » pour spécifier un autre target de démarrage. Dans ce cas, le target par défaut sera ignoré.

Pour en spécifier plusieurs, il faut les séparer par un « ; » ou utiliser plusieurs options « /t ».

MsBuild : Exécution de la cible « Rebuild » d'un fichier de build
Sélectionnez
MsBuild /t:Rebuild BuildA.proj

4-4-3. Surcharge d'une propriété

 

On a également la possibilité de surcharger la valeur des propriétés statiques - c'est à dire celles créées dans un PropertyGroup - lors de l'exécution. Pour cela, il suffit d'utiliser l'option « /property » (ou sa forme abrégée « /p ») avec la syntaxe  « /property:NomPropriete=ValeurPropriete » ou « /p:NomPropriete=ValeurPropriete ».

De nouveau pour surcharger plusieurs propriétés, il faut soit les séparer par un « ; » soit utiliser plusieurs options « /p ».

Par exemple, avec le fichier de projet « Test.proj » suivant :

 
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <PropertyGroup>
      <Message>Hello</Message>
   </PropertyGroup>

   <Target Name="Target1">
      <Message Text="$(Message)" />
   </Target>

</Project>

On peut surcharger la valeur de « Message » de la manière suivante :

Changer la valeur de certaines propriétés à l'exécution
Sélectionnez
REM. Va afficher "Hello"
MsBuild Test.proj 

REM. Va afficher "Bonjour"
MsBuild /property:Message=Bonjour Test.proj
MsBuild /p:Message=Bonjour Test.proj

Notez cependant qu'il n'est pas possible de surcharger d'une manière similaire la valeur ou une metadata d'un item statique.

4-4-4. Surcharge de la verbosité d'exécution

 

Il est également possible de contrôler le niveau de verbosité lors de l'exécution pour avoir plus ou moins de détail et de commentaires.

On peut utiliser pour cela l'option « /verbosity » ou sa forme abrégée « /v ». Les différentes valeurs possibles correspondent en fait aux valeurs (en minuscules) de l'énumération Microsoft.Build.Framework.LoggerVerbosity :

  1. quiet (ou q)
  2. minimal (ou m)
  3. normal (ou n)
  4. detailed (ou d)
  5. diagnostic (ou diag)

Pour plus d'informations sur les différences entre ces différentes valeurs, vous pouvez vous reportez aux liens données dans la bibliographie sur les différents niveaux de verbosité.

Il est cependant important de connaître cette possibilité, puisqu'il peut y avoir un facteur de dix entre la quantité d'information archivée en mode diagnostique et en mode normal.

Changer le niveau de la verbosité
Sélectionnez
MsBuild /verbosity:detailed Test.proj
MsBuild /v:detailed Test.proj

4-4-5. Omission du nom du fichier

Notez enfin que MsBuild exécutera en fait le fichier de projet qu'il trouve dans le répertoire courant. Par conséquent, si votre répertoire courant ne comporte qu'un seul fichier de projet, vous pouvez même l'omettre dans la ligne de commande.

4-5. Référencer une tâche du framework 3.5

 

Par défaut, lorsque l'on exécute MsBuild, il référence déjà un certain nombre de tâches, telle que les tâches Message, CreateProperty et CreateItem. Il référence en fait toutes les tâches qui sont déclarées dans la DLL Microsoft.Build.Task.dll.

Avec l'arrivée du framework 3.5, Microsoft a ajouté de nouvelles tâches et a complété des tâches existantes. Toutes ces « nouvelles » tâches ont été ajoutées dans la DLL Microsoft.Build.Task.v3.5.dll.

Si l'on veut utiliser un de ces tâches définies dans une autre DLL que celle référencée par défaut, on peut utiliser la commande UsingTask.

Notez bien que l'on référence une simple tâche présente dans une DLL, et non toute la DLL. Par conséquent, si l'on veut utiliser trois tâches de la même DLL, il est impératif de déclarer trois UsingTask différents.

La commande UsingTask nous offre deux paramètres mutuellement exclusifs que sont AssemblyName et AssemblyPath. Le premier nous permet de donner le nom de l'assembly - à condition que celle-ci soit définie dans la GAC. Le second nous permet de spécifier le chemin complet vers une DLL.

Utiliser la version « 3.5 » d'une tâche - ici la tâche GetFrameworkPath
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <UsingTask TaskName="GetFrameworkPath" 
              AssemblyName="Microsoft.Build.Tasks.v3.5"/>
   
   <Target Name="Target1">
      <GetFrameworkPath>
         <Output TaskParameter="FrameworkVersion35Path" 
                 PropertyName="MsBuildPath"/>
      </GetFrameworkPath>

      <Message Text="$(MsBuildPath)" />
  </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 27/01/2009 7:55:48.
Project "D:\Fichiers de build\Utilisation de UsingTask.proj" on node 0 (default targets).
  C:\WINDOWS\Microsoft.NET\Framework\v3.5
Done Building Project "D:\Fichiers de build\Utilisation de UsingTask.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)
Time Elapsed 00:00:00.03

Si nous avions omis la commande UsingTask, alors MsBuild aurait simplement utilisé la version « 2.0 » de la tâche et nous aurions reçu l'erreur suivante :

The "FrameworkVersion35Path" parameter is not supported by the "GetFrameworkPath" task. Verify the parameter exists on the task, and it is a gettable public instance property.

Il est donc crucial de bien regarder dans quelle DLL (ie dans quelle version du framework) la tâche que vous voulez utiliser a été déclarée. La MSDN nous fournit cette information via les éléments Assembly et Version Information.

Une tâche existant à la fois dans le framework 2.0 et 3.5 (comme la tâche GetFrameworkPath par exemple) n'apparaitra qu'une seule fois dans la MSDN.
Ainsi lorsque l'on visualisera la tâche elle-même, la MSDN nous indiquera qu'elle existe dans la DLL Microsoft.Build.Task.dll. Mais c'est lorsque l'on regardera la propriété FrameworkVersion35Path que l'on verra qu'elle appartient à la DLL Microsoft.Build.Task.v3.5.dll

4-6. Plus loin avec les Targets

4-6-1. Contrôler l'ordre d'exécution des Targets

 

4-6-1-1. Définition

Bien que l'on puisse choisir lors de l'exécution le « Target » à exécuter (voir la section « Exécuter un fichier de build »), il est possible de contrôler dans le fichier l'ordre d'exécution via les attributs DefaultTargets, InitialTargets et DependsOnTargets.

Ces différents attributs sont assez explicites :

  • DefaultTargets spécifie le(s) target(s) qui sera exécuté si aucun target n'est spécifié lors de l'exécution en ligne de commande (cas de la syntaxe proposé dans la section « Exécuter un fichier de build » - version simple)
  • InitalTargets spécifie le(s) target(s) qui sera lancé au démarrage, avant tout autre target
  • DependsOnTargets spécifie le(s) target(s) à lancer avant l'exécution d'un autre target

Si les deux premiers sont donc liés au fichier de projet, le dernier est lié à un target.

4-6-1-2. Exemple

Contrôler l'ordre d'exécution des targets
Sélectionnez
<Project DefaultTargets="Target1" InitialTargets="Init"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="PreTarget1" />
   <Target Name="PreTarget2" />
   <Target Name="Init" />

   <Target Name="Target1" DependsOnTargets="PreTarget1;PreTarget2" />
</Project>

Dans l'exemple ci-dessus, il est spécifié que :

  • Si aucun autre target n'est spécifié lors de l'exécution, le target exécuté sera « Target1 » (DefaultTargets)
  • Quel que soit le target démarré lors de l'exécution, le target « Init » sera lancé en premier (InitialTargets)
  • Avant de lancer le target « Target1 », les deux targets « PreTarget1 » et « PreTarget2 » seront exécutés - et ce dans cet ordre - (« Target1 » DependsOnTargets « PreTarget1 » et « PreTarget2 »

Comme présenté en exemple dans l'attribut DependsOnTargets, on peut préciser plusieurs Target en les séparant par des « ; ». Ceci est également vrai pour les attributs DefaultTargets et InitialTargets.

4-6-1-3. Cas des dépendances multiples

 

Notez cependant que dans le cas de l'exemple ci-dessous, l'exécution du Target1 nécessite l'exécution des « PreTarget1 » et « PreTarget2 ». De plus « PreTarget2 » nécessite également l'exécution de « PreTarget1 ».

Dans ce cas, le « PreTarget1 » ne sera exécuté qu'une et une seule fois.

Contrôler l'ordre d'exécution des : pas de redondance d'exécution
Sélectionnez
<Project DefaultTargets="Target1"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="PreTarget1">
      <Message Text="Dans PreTarget1" />
   </Target>
   <Target Name="PreTarget2" DependsOnTargets="PreTarget1">
      <Message Text="Dans PreTarget2" />
   </Target>

   <Target Name="Target1" DependsOnTargets="PreTarget1;PreTarget2">
      <Message Text="Dans Target1" />
   </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:35:48.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Dans PreTarget1
PreTarget2:
  Dans PreTarget2
Target1:
  Dans Target1
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.10

4-6-2. Appeler explicitement un Target

Il est possible d'appeler explicitement un target au sein d'un autre target. Pour cela, deux tâches différentes existent : CallTarget et MsBuild.

4-6-2-1. Appeler un target via CallTarget

Cette tâche n'est utilisable que si les targets cibles et source se trouvent dans le même fichier de build, sinon c'est vers la tâche MsBuild qu'il faut se tourner.

Appel explicite d'un Target
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <Message Text="Dans Target 1" />

      <CallTarget Targets="Target2" />
   </Target>

   <Target Name="Target2">
      <Message Text="Dans Target 2" />
   </Target>
</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:37:04.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Dans Target 1
Target2:
  Dans Target 2
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

Notez cependant que le target ne pourra être exécuté qu'une seule fois, de la même façon que pour les dépendances entre les targets décrites dans la partie « Cas des dépendances multiples ».

Ainsi le résultat sera inchangé si on a le fichier de build suivant:

Appel explicite d'un Target - pas de redondance d'exécution
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <Message Text="Dans Target 1" />

      <CallTarget Targets="Target2" />
      <CallTarget Targets="Target2" />
   </Target>

   <Target Name="Target2">
      <Message Text="Dans Target 2" />
   </Target>
</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/05/2009 23:38:02.
Project "C:\Temp\build.proj" on node 0 (default targets).
  Dans Target 1
Target2:
  Dans Target 2
Done Building Project "C:\Temp\build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

Notez enfin qu'avec la tâche CallTarget, les targets sources et cibles partageront les même propriétés, qu'elles aient été créées statiquement ou dynamiquement. Il ne sera donc pas possible de donner une autre valeur à une propriété le temps de l'appel à ce target, comme si l'on passait un paramètre à une méthode. (5)

4-6-2-2. Appeler un target via MsBuild

Nous avons également à notre disposition la tâche MsBuild. Elle possède l'énorme avantage de nous permettre de passer des paramètres (ie des propriétés) au target cible, ainsi que d'appeler plusieurs fois le même target. Par conséquent, nous pouvons utiliser cette tâche afin d'utiliser des targets comme s'il s'agissait de « méthodes utilitaires ».

Pour appeler la tâche, nous devons spécifier le fichier de projet que l'on veut exécuter. Pour cela, nous pouvons :

  • Soit donner le chemin et le nom du fichier à exécuter
  • Soit utiliser la propriété $(MsBuildProjectFile) qui nous permet d'exécuter un target situé dans le fichier de projet courant.
Appel explicite d'un Target en utilisant MsBuild
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <Message Text="Dans Target1" />

      <MSBuild Targets="Target2" Projects="$(MSBuildProjectFile)" />
   </Target>

   <Target Name="Target2">
      <Message Text="Dans Target2" />
   </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 9/01/2009 8:59:47.
Project "D:\Appel de target via MsBuild.proj" on node 0 (default targets).
  Dans Target1
Project "D:\Appel de target via MsBuild.proj" (1) is building "D:\Appel de target via MsBuild.proj" (1:2) on node 0 (Target2 target(s)).
  Dans Target2
Done Building Project "D:\Appel de target via MsBuild.proj" (Target2 target(s)).

Done Building Project "D:\Appel de target via MsBuild.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)
Time Elapsed 00:00:00.04

Comme on peut le voir dans l'exemple, c'est le même process MsBuild.exe qui va exécuter les deux targets.

Cette méthode nous permet d'exécuter plusieurs fois le même target, à quelques limitations près. Il faut savoir en effet que MsBuild.exe stocke la liste de tous les targets exécutés et interdit qu'un target exécuté ne soit ré-exécuté une seconde fois.

Ainsi pour qu'un target puisse être lancé plusieurs fois, il faut impérativement qu'ils soient considérés comme différents. Pour cela, on peut se permettre de passer des propriétés différentes en entrée. Nous donnerons un exemple de ce cas dans la partie « Passer des paramètres à un Target ».

4-6-2-3. Choisir CallTarget ou MsBuild

Reprenons sous la forme d'un tableau les principales différences entre les deux tâches pour savoir laquelle choisir selon les cas.

  CallTarget MsBuild
Exécuter un target se trouvant dans le même fichier OK OK
Exécuter un target se trouvant dans un autre fichier Not Possible OK
Partager toutes les propriétés existantes entre le target source et cible OK Not Applicable (6)
Passer des propriétés au target cible Not Possible Not Applicable (7) OK
Appeler plusieurs fois le même target Not Possible OK
Récupérer des propriétés en sortie de l'exécution OK OK

4-6-2-4. La tâche Exec

Une dernière possibilité existe également : la tâche Exec qui permet d'exécuter une ligne de commande. On va alors construire la ligne de commande comme décrit dans la section « Exécuter un fichier de build ».

Appel explicite d'un Target en utilisant Exec
Sélectionnez
<GetFrameworkPath>
   <Output TaskParameter="Path" PropertyName="MsBuildPath"/>
</GetFrameworkPath>

<Exec Command="$(MsBuildPath)\msbuild %22$(MSBuildProjectFile)%22 /t:Target2" />

Notez qu'ici on utilise la propriété Path de la tâche GetFrameworkPath. Selon nos besoins, il pourra être important d'utiliser les propriétés FrameworkVersion20Path ou FrameworkVersion35Path. Pour cela, on pourra alors utiliser la version 3.5 de la tâche GetFrameworkPath en se basant sur l'exemple fourni dans la section « Référencer une tâche du framework 3.5 ».

4-6-3. Passer des paramètres à un Target

 

4-6-3-1. Paramètres d'entrée

Comme nous l'avons vu, il n'est possible de passer des paramètres d'entrée à une tâche que si on l'appelle via les tâches Exec ou via MsBuild.

Pour la tâche Exec, il suffit bien sûr d'utiliser la même syntaxe que lorsque l'on utilise MsBuild en ligne de commande, soit via les options « /property » ou « /p » tel que décrit dans la section « Surcharge d'une propriété ».

En ce qui concerne la tâche MsBuild, une propriété spécifique peut être utilisée à cet effet.

Passage de propriété avec la tâche MsBuild
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <MSBuild Targets="Target2" 
               Projects="$(MSBuildProjectFile)" 
               Properties="Test=0" />

      <MSBuild Targets="Target2" 
               Projects="$(MSBuildProjectFile)" 
               Properties="Test=1" />
  </Target>

   <Target Name="Target2">
      <Message Text="Dans Target2: Test=$(Test)" />
   </Target>

</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 27/01/2009 18:16:30.
Project "D:\Input Params avec MsBuild.proj" on node 0 (default targets).
Project "D:\Input Params avec MsBuild.proj" (1) is building "D:\Input Params avec MsBuild.proj" (1:2) on node 0 (Target2 target(s)).
  Dans Target2: Test=0
Done Building Project "D:\Input Params avec MsBuild.proj" (Target2 target(s)).

Project "D:\Input Params avec MsBuild.proj" (1) is building "D:\Input Params avec MsBuild.proj" (1:3) on node 0 (Target2 target(s)).
  Dans Target2: Test=1
Done Building Project "D:\Input Params avec MsBuild.proj" (Target2 target(s)).

Done Building Project "D:\Input Params avec MsBuild.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.09

4-6-3-2. Paramètres de sortie

Il est également possible de recevoir des paramètres de sortie lors de l'exécution d'un target. Il peut s'agir soit de propriétés, soit d'items.

Récupération de paramètres de sortie sous forme de propriété
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <!-- Récupération de la sortie lors de l'utilisation de CallTarget -->
      <CallTarget Targets="Target2">
         <Output TaskParameter="TargetOutputs" PropertyName="OutputCallTarget"/>
      </CallTarget>
      <Message Text="Target2 a renvoyé $(OutputCallTarget)" />

      <!-- Récupération de la sortie lors de l'utilisation de MsBuild -->
      <MSBuild Targets="Target2" Projects="$(MSBuildProjectFile)">
         <Output TaskParameter="TargetOutputs" PropertyName="OutputMsBuild" />
      </MSBuild>
      <Message Text="Target2 a renvoyé $(OutputMsBuild)" />
   </Target>

   <Target Name="Target2" Outputs="$(OutputProperty)">
      <CreateProperty Value="MaValeur">
         <Output TaskParameter="Value" PropertyName="OutputProperty" />
      </CreateProperty>
   </Target>
</Project>
 
Sélectionnez
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 27/01/2009 18:28:36.
Project "D:\Output Params.proj" on node 0 (default targets).
  Target2 a renvoyé MaValeur
  Target2 a renvoyé MaValeur
Done Building Project "D:\Output Params.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)
Time Elapsed 00:00:00.03

Dans l'exemple ci-dessus, nous allons simplement appeler (via les tâches CallTarget et MsBuild) le Target2 présent dans le même fichier.

Ce target se contente de créer une propriété, et spécifie qu'elle va la retourner. On peut alors lire la propriété TargetOutputs des tâches pour récupérer la propriété.

De la même façon, on pourrait récupérer un item. Le fichier ci-dessous nous donnerait exactement le même résultat d'exécution.

On fera bien attention d'utiliser l'attribut ItemName et non plus PropertyName pour la récupération de la valeur.

Récupération de paramètres de sortie sous forme d'item
Sélectionnez
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Target1">
      <!-- Récupération de la sortie lors de l'utilisation de CallTarget -->
      <CallTarget Targets="Target2">
         <Output TaskParameter="TargetOutputs" ItemName="OutputCallTarget"/>
      </CallTarget>
      <Message Text="Target2 a renvoyé @(OutputCallTarget)" />

      <!-- Récupération de la sortie lors de l'utilisation de MsBuild -->
      <MSBuild Targets="Target2" Projects="$(MSBuildProjectFile)">
         <Output TaskParameter="TargetOutputs" ItemName="OutputMsBuild" />
      </MSBuild>
      <Message Text="Target2 a renvoyé @(OutputMsBuild)" />
   </Target>

   <Target Name="Target2" Outputs="@(OutputItem)">
      <CreateItem Include="MaValeur">
         <Output TaskParameter="Include" ItemName="OutputItem" />
      </CreateItem>
   </Target>

</Project>

précédentsommairesuivant
On pourrait évidemment utiliser la tâche CreateProperty avant la tâche CallTarget, de façon à changer la valeur courante de la propriété, puis d'appeler de nouveau CreateProperty afin de repositionner la valeur d'origine. Cependant, nous serions très éloignés ici du principe de passage de paramètres.
On peut passer des propriétés au target cible via la tâche MsBuild, donc on peut également passer toutes les propriétés courantes. Cela revient néanmoins à toutes les lister ce qui peut rendre l'exercice fastidieux voire impossible.
On peut utiliser une tâche CreateProperty de façon à créer une propriété qui sera utilisée par le target. Cependant on en revient dans ce cas à partager les propriétés existantes entre le target source et cible, puisque la nouvelle propriété sera également disponible pour le target source

Copyright © 2009 Pierre-Emmanuel Dautreppe . Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.