Visual Studio 2005: L'essentiel sur MSBuild par Bruno Boucard(boucard.bruno@free.fr)

Table des matières

1. Introduction

Remarque : cet article étant fondé sur la version bêta 1 du produit Visual Studio 2005, certaines caractéristiques décrites peuvent être amenées à changer vis-à-vis de la version finale, prévue courant 2005.

Qu'est-ce que MSBuild ? C'est l'outil de construction d'applications .NET à la fois sous Visual Studio 2005 et au sein du Framework .NET 2.0. Pour les développeurs du prochain système d'exploitation "Longhorn", MSBuild est déjà l'outil pour construire de nouvelles applications. Il n'y a aucun doute, MSBuild sera un des éléments incontournables dans les prochains environnements de développement Microsoft. Selon Alex Kipman, Program Manager MSBuild, son produit serait déjà utilisé en interne pour construire les derniers développements Microsoft.

Dans un premier survol, MSBuild ressemble étrangement à NANT, mais après avoir installé Visual Studio 2005, on remarque que l'une des principales qualités du produit MSBuild, est d'être totalement intégré à Visual Studio 2005 sans pour autant en être dépendant. En interne, Visual Studio 2005 est fondé sur MSBuild pour générer les projets. Ainsi les options proposées dans les fenêtres de l'IDE pour personnaliser la construction d'un projet correspondent à des balises spécifiques d'un fichier MSBuild, qui n'est autre qu'un fichier projet. Ces nouveaux fichiers projets sont spécifiques à Visual Studio 2005 et respectifs aux langages de développement utilisés (par exemple l'extension .vbproj pour un projet VB.NET et .csproj pour un projet C#). En d'autres mots, tous les fichiers projets générés par l'IDE sont directement consommables par l'outil MSBuild.exe, et ceci sans la présence de Visual Studio 2005.

Par exemple, supposons un projet C# engendré par Visual Studio 2005 nommé DemoMsBuild ; recopiez ce projet sur une machine disposant seulement du Framework .NET 2.0; puis à la l'aide de la commande ci-dessous, reconstruisez-le tout comme le ferait Visual Studio 2005 via son menu "Build->Rebuild BonjourMsBuild" sur la machine d'origine:

01. MSBuild DemoMsBuild.csproj /t:Rebuild
Rebuild

Le commutateur "/t" permet de sélectionner la cible (target) désirée, mais nous reviendrons ultérieurement sur cette notion. Cependant, au lieu de traiter un fichier engendré par Visual Studio 2005, vous pourriez aussi écrire vos propres fichiers projets à la main en respectant le schéma XML MSBuild (le fichier msbuild.xsd est installé avec le Framework .NET 2.0). Dans cet article, vous prendrez connaissance des éléments essentiels de la syntaxe MSBuild, principalement à travers l'outil en ligne de commande.

2. Principe d'exécution

Avant de plonger dans la syntaxe de fichiers MSBuild, une petite présentation de l'environnement d'exécution sous-jacent à l'utilisation de l'outil devrait vous permettre de mieux appréhender le fonctionnement de cet outil. Conceptuellement un processus MSBuild peut se décrire comme une orchestration de tâches unitaires (création de répertoires, compilation, copie de fichiers...), s'exécutant via un moteur d'exécution dans un environnement géré (managed). Le moteur d'exécution est nourri par un ou plusieurs fichiers projets décris en XML (notons qu'initialement le nom de code du projet MSBuild était XMake, pour XML Make). Sur le plan de l'architecture, le moteur MSBuild est exposé via l'outil en ligne de commande MSBuild.exe, dont le rôle principal est de permettre l'accès au moteur via un jeu de commutateurs à passer sur la ligne de commande.

Figure 1. Le moteur MSBuild

01. MSBuild [options] [fichier projet | fichier solution]
L'usage de l'outil

Par défaut, si aucun argument n'est passé en ligne de commande, MSBuild.exe, inspecte le répertoire courant à la recherche d'un fichier dont l'extension se termine par ".proj". Si un tel fichier est trouvé, MSBuild le charge et le traite. Si le répertoire contient plusieurs fichiers ".proj", MSBuild ne lance rien et vous réclame de préciser le fichier projet à traiter. Si un fichier solution Visual Studio 2005 est fourni, l'outil traduit la syntaxe non-MSBuild du fichier solution en une syntaxe MSBuild (la syntaxe des fichiers solutions reste propriétaire à Visual Studio). Enfin vous avez toujours la possibilité d'interrompre proprement un traitement, en frappant la combinaison de touches [Ctrl+C].

Option longue Raccourci Description
/help /h ou / ? Montre le message d'usage.
/nologo Supprime la bannière et le message de copyright.
/version /ver Montre les informations au sujet de la version.
@<fichier> Permet de placer dans un fichier des options complémentaires à la ligne de commande.
/quiet /q
/verbosity:<level> /v Redirige vers le logger d'évènement les messages émis par les tâches en fonction du niveau <level> de verbosité réclamé. Du moins verbeux, au plus verbeux: q[uiet], m[inimal], n[ormal], d[etailed], diag[nostic].
/target :<liste de cibles> /t Spécifie la liste de cibles à construire (séparées par un point virgule) contenu dan le fichier projet.
/property :<nom>=<valeur> /p Spécifie la liste de propriétés (séparées par un point virgule) contenu dan le fichier projet. Une propriété est un couple composé du nom et de sa valeur.
/logger :<logger> /l Enregistre un logger à l'écoute des évènements MSBuild.
/noconsolelogger /noconlog Désactive le logger de console.
/validate[:<schema>] /val Valide le fichier projet contre le schéma XML défaut ou celui fournit en paramètre.

3. Application Exemple

Pour illustrer l'introduction à MSBuild, j'ai choisi de construire progressivement un exemple composé d'une application minimaliste et de deux librairies.

3.1. Organisation des composants

L'exemple se décline en une application console, "app.exe" écrite en C#, reposant sur la librairie d'interface "imath.dll" écrite elle aussi en C#. La libraire d'implémentation "math.dll" est composée de deux modules: "simple.netmodule" écrit en C# et "advanced.netmodule" écrit en Java et repose sur la librairie d'interface précédente. Les deux assemblages "IMath" et "Math" sont signés et le dernier s'installe dans le GAC.

Le schéma ci-dessous rappelle comment engendrer via les compilateurs en ligne, les binaires de l'application à partir des divers fichiers sources.

Figure 2. Chaîne de construction

Je reconnais que la complexité engendrée par tous ces fichiers est discutable, mais ce n'est qu'un prétexte pour illustrer MSBuild.

3.2. Codes sources

Pour compléter les informations concernant l'exemple, voici les codes sources répartis par assemblage : IMath, Math et App.

3.2.a. IMath

L'assemblage IMath ne contient que des interfaces définis dans un seul fichier : imath.cs.

01. // imath.cs
02. using System.Reflection;
03. using System.Runtime.CompilerServices;
04. using System;
05.
06. [assembly: AssemblyVersion("1.0.0.0")]
07.
08. namespace Dotnet.Math
09. {
10.      public interface ISum
11.      {
12.          double Sum(double a, double b);
13.      }
14.
15.          public interface ISubstract
16.      {
17.          double Substract(double a, double b);
18.      }
19.
20.          public interface IMultiply
21.      {
22.          double Multiply(double a, double b);
23.      }
24.
25.          public interface IDivide
26.      {
27.          double Divide(double a, double b);
28.      }
29. }
IMath.cs

3.2.b. Math

L'assemblage Math est composé de deux modules .NET et d'une DLL:

01. using System;
02.
03. namespace Dotnet.Math
04. {
05.      internal class Simple : ISum, ISubstract
06.       {
07.
08.          public double Sum(double a, double b)
09.          {
10.              return a + b;
11.          }
12.
13.                  public double Substract(double a, double b)
14.          {
15.              return a - b;
16.          }
17.
18.             public static void Main()
19.          {
20.              double a = 1;
21.              double b = 2;
22.
23.                              Simple instance = new Simple();
24.
25.                          Console.WriteLine("Sum({0}, {1}) = {2}", a, b, instance.Sum(a, b));
26.              Console.WriteLine("Substract({0}, {1}) = {2}", a, b, instance.Substract(a, b));
27.          }
28.      };
29. }
Simple.cs

La classe Simple contient une méthode Main(), offrant l'opportunité de tester le module.

01. package Dotnet.Math;
02.
03. public class Advanced implements IMultiply, IDivide
04. {
05.         public double Multiply(double a, double b)
06.      {
07.          return a * b;
08.      }
09.
10.          public double Divide(double a, double b)
11.      {
12.          return a / b;
13.      }
14. }
Advanced.java

Le fichier math.cs ne contient rien, mis à part l'attribut d'assemblage AssemblyVersion.

01. using System.Reflection;
02. using System.Runtime.CompilerServices;
03.
04. [assembly: AssemblyVersion("1.0.0.0")]
Math.java

3.2.c. App

L'assemblage App consomme simplement les services de la librairie d'interface IMath.DLL, découplant physiquement ainsi l'application de l'implémentation de librairie Math.DLL.

01. using System;
02. using System.Reflection;
03. using Dotnet.Math;
04.
05. class App
06. {
07.      static void Main()
08.      {
09.          double a = 1;
10.          double b = 2;
11.
12.                  Assembly asm = Assembly.Load("Math");
13.
14.                  IMultiply mul =   (IMultiply)asm.CreateInstance("Dotnet.Math.Advanced");
15.               IDivide div = (IDivide)mul;
16.
17.                  Console.WriteLine("Multiply({0}, {1}) = {2}", a, b, mul.Multiply(a, b));
18.          Console.WriteLine("Divide({0}, {1}) = {2}", a, b, div.Divide(a, b));
19.
20.                  ISum sum =   (ISum)asm.CreateInstance("Dotnet.Math.Simple");
21.                       ISubstract sub = (ISubstract)sum;
22.
23.          Console.WriteLine("Sum({0}, {1}) = {2}", a, b, sum.Sum(a, b));
24.          Console.WriteLine("Substract({0}, {1}) = {2}", a, b, sub.Substract(a, b));
25.      }
26. }
App.cs

3.3. Eléments de base

Avant de se lancer dans la confection de projets opérationnels, nous allons introduire point par point la syntaxe de base MSBuild.

3.3.a. Le projet

Sous MSBuild tout commence par un projet. Tous les fichiers MSBuild se doivent de définir un élément XML racine appelé <Projet>. Par exemple, supposons un fichier "demo1.proj" contenant le texte suivant :

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"/>
demo1.proj

Noter que l'espace de noms "http://schemas.microsoft.com/developer/msbuild/2003" est obligatoire. Pour valider ce premier projet (minimaliste) lançons la commande MSBuild et observons le résultat :

Figure 3. Demo1.proj

Aucune cible (target) n'a été précisée sur la ligne de commande et pour cause notre fichier "demo1.proj" est vide. En effet, n'ayant pas défini de cible, le moteur MSBuild en recherche une en vain et nous retourne l'erreur MSB4040. Ceci nous amène à rappeler la première vocation de MSBuild : lancer un ou plusieurs traitements (tâches) réunis sous une ou plusieurs cibles.

3.3.b. Les cibles

Par définition une cible (target) réuni un ensemble de tâches. Vous pouvez nommer une cible via l'attribut "Name" de manière à la désigner explicitement, comme sur la ligne de commande via le commutateur "/t". Par exemple dans le fichier "demo2.proj" nous avons défini une cible (vide de tâches) nommée "ConstruireMath".

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.      <Target Name="ConstruireMath"/>
03. </Project>
demo2.proj

Testons ce projet :

Figure 4. Demo2.proj

Le moteur MSBuild a détecté notre cible "ConstruireMath".

Ajoutons que l'élément racine <Projet> permet de définir l'attribut DefaultTargets, désignant une liste défaut composée de cibles séparées par des points virgules (;) . L'exemple ci-dessous définit trois cibles à exécuter dans l'ordre suivant :

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ConstruireIMath; ConstruireMath; ConstruireApp">
02.      <Target Name="ConstruireMath"/>
03.      <Target Name="ConstruireIMath"/>
04.      <Target Name="ConstruireApp"/>
05. </Project>
demo2.proj

L'exemple précédent ne nous permet pas d'ordonnancer les cibles entre elles. Pour répondre à ce besoin, l'attribut DependsOnTargets de l'élément <Target> permet de lister des cibles dépendantes à traiter avant celle-ci.

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ConstruireApp">
02.      <Target Name="ConstruireMath"/>
03.      <Target Name="ConstruireIMath"/>
04.      <Target Name="ConstruireApp" DependsOnTargets=" ConstruireIMath; ConstruireMath"/>
05. </Project>
demo2.proj

Je dois reconnaître que l'intérêt de ces fichiers reste fort limité, car pour l'instant nous n'avons toujours pas lancé un seul traitement.

3.3.c. Les tâches

La vocation première de MSBuild est de lancer des traitements adaptés au processus de développement, comme la compilation, l'édition de liens, mais aussi les tests unitaires, le déploiement ... Les traitements sont concrétisés à travers la notion de tâche. Au sein d'une cible, vous avez la possibilité de définir des tâches dédiées à votre processus de construction.

Par défaut MSBuild propose l'ensemble de tâches prédéfinies :

Tâche Description
AL Edition de lien pour assemblage, fondée sur l'outil AL.exe. Particulièrement utile pour les assemblages multi-modules.
Copy Copier des fichiers vers une nouvelle destination.
CreateItem Peuple une liste d'items passés en paramètre. Ceci permet de copier des items d'une liste à l'autre.
CreateProperty Peuple des propriétés avec des valeurs passées en entrée
Csc Fondée sur le compilateur C#, CSC.exe, cette tâche produit des binaires identiques à ceux de l'outil : .exe, .dll, .netmodule.
Delete Efface des fichiers.
Exec Exécute une commande système comme si elle était lancée depuis une fenêtre "command prompt".
GenerateApplication Manifest Génère un assemblage de type manifeste pour une application Win32 ou ClickOnce.
GenerateDeploymentManifest Génère un manifeste de déploiement ClickOnce.
LC Fondé sur le compilateur de licence qui génère un fichier .licence depuis un fichier .licx.
MakeDir Création de répertoires
MSBuild Construit des projets fondés sur MSBuild.exe lui-même.
RegisterAssembly Similaire à l'outil framework, RegAsm.exe, cette tâche examine les métas données d'un assemblage pour générer les entrées nécessaires dans le Registre de manière à lancer les classes de cet assemblage comme des composants COM vis-à-vis de clients COM.
RemoveDir Efface des répertoires et leurs fichiers respectifs.
RegGen Similaire à l'outil du framework, ResGen.exe, cette tâche converti un fichier .txt ou .resx en fichier de ressources binaire .NET.
ResolveAssemblyReference Cette tâche prend en entrée un ou plusieurs noms d'assemblages et localise ces noms répartis dans des répertoires sur le disque ou dans le cache global des assemblages (GAC), voir dans la ruche du registre.
ResolveCOMReference Cette tâche prend en entrée un ou plusieurs noms de librairie COM ou fichiers .tlb et localise ceux-ci sur le disque.
Touch Positionne les droits d'accès des fichiers et modifie leurs dates.
UnregisterAssembly Réalise la tâche inverse de RegisterAssembly.
Vbc Equivalent au compilateur VB.NET, vbc.exe, cette tâche produit des binaires identiques à ceux de l'outil : .exe, dll, .netmodule.
VCBuild Exécute le constructeur d'applications fondées sur des projets Visual C++.

Pour illustrer l'utilisation d'une tâche, voici l'exemple "Demo3.proj" fondé sur l'usage de la tâche "MakeDir". Ici nous utilisons l'attribut Directories pour renseigner la liste des répertoires à créer.

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.      <Target Name="CreationDeRepertoire">
03.          <MakeDir Directories= "bin"/>
04.      </Target>
05. </Project>
demo3.proj

Lançons ce projet :

Figure 5. Demo3.proj

Le moteur MSBuild a détecté la cible "CreationDeRepertoire" et nous informe que la tâche MakeDir a créé le répertoire "bin". Notez que si le répertoire existe déjà, la tâche ne fait pas d'erreur.

Une fois encore l'intérêt de cette démonstration est discutable, car nous aurions aimé définir des variables au lieu de coder en dur la chaîne "bin". La majorité des tâches exposent des interfaces d'entrées/sorties bien plus complexes que l'exemple "demo3.proj" et dans ce cadre l'usage de définitions organisées en items et en propriétés dévient une nécessité.

3.3.d. Les items

La notion d'item, permet de définir des valeurs disponibles au niveau du projet et donc accessibles par ses tâches sous-jacentes. Généralement, les items représentent les fichiers à compiler. La syntaxe MSBuild permettant de définir une liste d'items est basée sur l'élément XML <ItemGroup>. Par exemple, nous pourrions définir les items définissant le fichier à compiler et le type d'exécutable à engendrer:

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ConstruireIMath">
02.      <ItemGroup>
03.          <FichierACompiler Include="imath.cs"/>
04.          <ExecutableType Include= "library"/>
05.      </ItemGroup>
06.      <Target Name="ConstruireIMath">
07.          <Csc
08.              Sources="@(FichierACompiler)"
09.              TargetType="@(ExecutableType)"
10.              EmitDebugInformation="true"
11.              KeyFile="public.snk"
12.              DelaySign="true"/>
13.      </Target>
14. </Project>
demo4.proj

Ici, nous souhaitons obtenir un assemblage de type DLL signé "retardé" en mode Debug. Dans ce projet j'ai défini, un élément <ItemGroup> dont la vocation est de grouper des items ; ici FichierACompiler et ExecutableType. On note que l'accès à la valeur d'un item prend la syntaxe @(nom de item ). Si nous avions plusieurs items à traiter, nous pourrions utiliser différentes syntaxes :

Les deux exemples suivants résument les principales pratiques de l'élément <ItemGroup> :

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.      <ItemGroup>
03.          <FichierJavaACompiler Include="advanced.java"/>
04.          <ListeDeFichiersCSharpACompiler Include="math.cs ; simple.cs"/>
05.      </ItemGroup>
06. </Project>
demo4.proj

Avec l'usage de WildCards, le code est plus concis :

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.      <ItemGroup Exclude= " imath2.cs ">
03.          <FichierJavaACompiler Include="*.java"/>
04.          <FichiersCCompiler Include="*.cs"/>
05.      </ItemGroup>
06. </Project>
demo4.proj

3.3.e. Les propriétés

Dans le paragraphe précèdent, nous avons appris que les items étaient essentiels pour nourrir les tâches MSBuild. Cependant il existe un moyen complémentaire pour paramétrer les tâches : les propriétés.

Les propriétés offrent la capacité de caractériser les tâches. Elles proposent le formaliste clef/valeur, dont la syntaxe est fondée sur l'élément XML <PropertyGroup>. Par exemple, nous pourrions définir un groupe composé de trois propriétés, InformationDebug, FichierClef et SignatureRetarde. Dans le projet suivant nous définissons la cible "ConstruireIMath», contenant une tâche C#, dont les paramètres sont répartis à la fois dans des items et des propriétés :

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ConstruireIMath">
02.      <PropertyGroup>
03.          <InformationDebug>true</InformationDebug>
04.          <FichierClef>publicprive.snk</FichierClef>
05.          <SignatureRetarde>false</SignatureRetarde>
06.      </PropertyGroup>
07.      <ItemGroup>
08.          <FichierACompiler Include="imath.cs"/>
09.          <ExecutableType Include= "library"/>
10.      </ItemGroup>
11.      <Target Name="ConstruireIMath">
12.          <Csc
13.              Sources="@(FichierACompiler)"
14.              TargetType="@(ExecutableType)"
15.              EmitDebugInformation="$(InformationDebug)"
16.              KeyFile="$(FichierClef)"
17.              DelaySign="$(SignatureRetarde)"
18.          />
19.      </Target>
20. </Project>
demo5.proj

On note que l'accès aux valeurs d'une propriété au sein d'une tâche prend la syntaxe $(nom de propriété).

Figure 6. Demo5.proj

Dans le cadre des propriétés, sachez que MSBuild définit les siennes.

Nom de la propriété Description Exemple
MSBuildProjectDirectory Répertoire dan lequel le projet est stocké C:\MSBUILD
MSBuildProjetFile Nom du fichier projet BonjourMSBuild.proj
MSBuildProjectExtension Extension du fichier projet .proj
MSBuildProjectFullPath Chemin complet du fichier projet C:\MSBuild\BonjourMSBuild.proj
MSBuildProjectName Nom du fichier projet sans l'extension BonjourMSBuild
MSBuildPath Répertoire dans lequel msbuild.exe est stocké C:\WINDOWS\Microsoft.NET\Framework\v2.0. 40607\MSBuild.exe

Notez que vous ne pouvez pas utiliser ces noms dans vos définitions de propriétés car ils sont naturellement réservés.

3.3.f. Fractionner un projet

Précédemment, nous avons appris que les propriétés et les items étaient conçus pour découpler les paramètres des tâches elles-mêmes. Typiquement, nous pourrions découper les items, les propriétés et les cibles pour un gain de visibilité et de maintenance. La syntaxe MSBuild permet d'importer dans un projet, un autre projet, via l'élément <Import>.

La démonstration précédente peut se découper en trois sous-projets :

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ConstruireIMath">
02.      <ItemGroup>
03.          <FichierACompiler Include="imath.cs"/>
04.          <ExecutableType Include= "library"/>
05.      </ItemGroup>
06.      <Import Project="demo5.properties.proj"/>
07.      <Import Project="demo5.targets.proj"/>
08. </Project>
demo5.main.proj

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.      <PropertyGroup>
03.          <InformationDebug>true</InformationDebug>
04.          <FichierClef>publicprive.snk</FichierClef>
05.          <SignatureRetarde>false</SignatureRetarde>
06.      </PropertyGroup>
07. </Project>
demo5.properties.proj

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.      <Target Name="ConstruireIMath">
03.          <Csc
04.                      Sources="@(FichierACompiler)"
05.              TargetType="@(ExecutableType)"
06.              EmitDebugInformation="$(InformationDebug)"
07.              KeyFile="$(FichierClef)"
08.              DelaySign="$(SignatureRetarde)"
09.          />
10.      </Target>
11. </Project>
demo5.targets.proj

Du point de vue technique, l'élément <Import> s'apparente à l'ordre #include du pré-processeur des compilateurs C/C++. Le code contenu dans le fichier importé est injecté là où l'élément <Import> a été placé.

3.3.g. Communiquer entre tâches

Nous savons maintenant organiser de manière modulaire notre processus de construction. Cependant, il est parfois légitime de vouloir prendre le résultat d'une tâche pour le placer en entrée d'une autre. Par nature les tâches ne peuvent communiquer entre elles directement, elles doivent impérativement utiliser des variables intermédiaires. Pour ce faire, MSBuild définit "un item de sortie", permettant d'associer un paramètre d'une tâche avec un nom d'item dont la syntaxe est la suivante :

Output

Pour illustrer l'usage d'un "item de sortie", je propose les fichiers demo6.main.proj, demo6.properties.proj, demo6.targets.proj:

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"   DefaultTargets="ConstruireTestSimple">
02.      <ItemGroup>
03.          <FichierACompiler Include="simple.cs"/>
04.          <References Include="imath.dll"/>
05.          <ExecutableType Include="module"/>
06.      </ItemGroup>
07.      <Import Project="demo6.properties.proj"/>
08.      <Import Project="demo6.targets.proj"/>
09. </Project>
demo6.main.proj

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.       <PropertyGroup>
03.          <InformationDebug>true</InformationDebug>
04.          <PointEntreePrincipal>Dotnet.Math.Simple.Main</PointEntreePrincipal>
05.          <FichierClef>publicprive.snk</FichierClef>
06.          <SignatureRetarde>false</SignatureRetarde>
07.      </PropertyGroup>
08. </Project>
demo6.properties.proj

01. <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
02.         <Target Name="ConstruireSimple">
03.          <Csc
04.              EmitDebugInformation="$(InformationDebug)"
05.              References="@(References)"
06.              TargetType="@(ExecutableType)"
07.              Sources="@(FichierACompiler)">
08.              <Output
09.                  ItemName="NomDuModule"
10.                  TaskParameter="OutputAssembly"
11.              />
12.          </Csc>
13.      </Target>
14.      <Target Name="ConstruireTestSimple" DefaultTargets="ConstruireSimple">
15.          <AL
16.              MainEntryPoint="$(PointEntreePrincipal)"
17.              SourceModules="@(NomDuModule)"
18.              TargetType="exe"
19.              KeyFile="$(FichierClef)"
20.              DelaySign="$(SignatureRetarde)"
21.              OutputAssembly="@(NomDuModule->'%(FileName)').exe"
22.              Version="1.0.0.0"
23.          />
24.      </Target>
25. </Project>
demo6.targets.proj

L'item NomDuModule permet d'édifier un lien entre deux tâches, ici <Csc> et <AL>.

Dans le fichier "demo6.targets.proj" j'ai utilisé une instruction de transformation dans le cadre de la tâche AL de manière à extraire le nom du fichier sans l'extension de l'item NomDuModule (simple.netmodule) :

OutputAssembly="@(NomDuModule->'%(FileName)').exe"

La motivation des transformations est d'extraire des éléments d'une chaîne contenant un nom de fichier. Voici une liste non exhaustive des transformations courantes.

Transformation C:\MSBuild\bin\source.exe
%{FileName} Source
%{Extension} .exe
%{RelativeDir} C:\MSBuild\bin\
%{FullPath} C:\MSBuild\bin\source.exe

3.3.h. Poser des conditions

Généralement, dans les environnements de développements nous souhaitons générer au moins deux types de distribution : Debug et Release (nous avons pour l'instant généré des modules exclusivement en mode Debug). Pour répondre à ce type de besoin, MSBuild propose un attribut Condition permettant de conditionner la plupart des éléments sur les opérateurs suivants :

Condition Description
‘Chaîne1' == ‘Chaîne2' Retourne vraie si Chaîne1 est égale à Chaîne2.
‘Chaîne1' != ‘Chaîne2' Retourne vraie si Chaîne1 n'est pas égale à Chaîne2.
Exists(‘Chaîne1') Retourne vraie si le fichier ou le répertoire nommé Chaîne1 existe.
!Exists(‘Chaîne1') Retourne vraie si le fichier ou le répertoire nommé Chaîne1 n'existe pas

Il existe un élément nommé <Error> permettant de rattraper des erreurs sur condition. Par exemple nous aimerions indiquer à l'utilisateur un message d'erreur lorsque celui n'indique pas une propriété testée dans une conditi