Procédure pas à pas : créer un fichier projet MSBuild en partant de zéro

Les langages de programmation qui ciblent .NET Framework utilisent des fichiers projet MSBuild pour décrire et contrôler le processus de génération d'application. Quand vous utilisez Visual Studio pour créer un fichier projet MSBuild, le code XML approprié est ajouté automatiquement au fichier. Il peut cependant être utile de comprendre comment le code XML est organisé et comment vous pouvez le modifier pour contrôler une build.

Notes

Cet article est approprié si vous souhaitez découvrir les bases du fonctionnement de MSBuild indépendamment de n’importe quel Kit SDK. La génération à l’aide d’un Kit SDK, par exemple lorsque vous utilisez dotnet build ou lorsque vous ajoutez l’attribut Sdk à l’élément de projet racine, n’est pas abordée dans cet article. Consultez SDK de projet .NET.

Pour plus d’informations sur la création d’un fichier projet pour un projet C++, consultez l’article MSBuild (C++).

Cette procédure pas à pas montre comment créer progressivement un fichier projet de base, en utilisant seulement un éditeur de texte. Cette procédure pas à pas comprend les étapes suivantes :

  1. Étendez la variable d’environnement PATH.

  2. Créer un fichier source d'application minimal.

  3. Créer un fichier projet MSBuild minimal.

  4. Générer l'application en utilisant le fichier projet.

  5. Ajouter des propriétés pour contrôler la build.

  6. Contrôler la build en changeant les valeurs de propriétés.

  7. Ajouter des cibles à la build.

  8. Contrôler la build en spécifiant des cibles.

  9. Générer de façon incrémentielle.

Cette procédure pas à pas montre comment créer le projet sur l'invite de commandes et examiner les résultats. Pour plus d’informations sur MSBuild et son exécution à l’invite de commandes, consultez la Procédure pas à pas : utiliser MSBuild.

Pour effectuer la procédure pas à pas, vous devez disposer de Visual Studio, car il comprend MSBuild et le compilateur C#, qui sont requis pour cette procédure.

Étendre le chemin d’accès

Avant de pouvoir utiliser MSBuild, vous devez étendre la variable d'environnement PATH pour inclure tous les outils requis. Vous pouvez utiliser l’Invite de commandes développeur pour Visual Studio. Recherchez-la sur Windows 10 dans la zone de recherche de la barre des tâches Windows. Pour configurer l’environnement dans une invite de commandes ordinaire ou dans un environnement de script, exécutez VSDevCmd.bat dans le sous-dossier Common7/Tools d’une installation de Visual Studio.

Créer une application minimale

Cette section montre comment créer un fichier source d’application C# minimal en utilisant un éditeur de texte.

  1. À l’invite de commandes, accédez au dossier où vous voulez créer l’application, par exemple, \Mes documents\ ou \Bureau\.

  2. Créez un sous-dossier nommé \HelloWorld\ et modifiez le répertoire pour y accéder.

  3. Dans un éditeur de texte, créez un fichier HelloWorld.cs, puis copiez et collez le code suivant :

    using System;
    
    class HelloWorld
    {
        static void Main()
        {
    #if DebugConfig
            Console.WriteLine("WE ARE IN THE DEBUG CONFIGURATION");
    #endif
    
            Console.WriteLine("Hello, world!");
        }
    }
    
  4. Générez l’application en entrant csc helloworld.cs à l’invite de commandes.

  5. Testez l’application en entrant helloworld à l’invite de commandes.

    Le message Hello, world! doit s’afficher.

  6. Supprimez le fichier exécutable.

Créer un fichier projet MSBuild minimal

Maintenant que vous avez un fichier source d'application minimal, vous pouvez créer un fichier projet minimal pour générer l'application. Ce fichier projet contient les éléments suivants :

  • Le nœud Project racine requis.

  • Un nœud ItemGroup pour contenir les éléments item.

  • Un élément item qui référence le fichier source d'application.

  • Un nœud Target pour contenir les tâches requises pour générer l'application.

  • Un élément Task pour démarrer le compilateur C# afin de générer l’application.

Pour créer un fichier projet MSBuild minimal

  1. Dans l’éditeur de texte, créez un fichier HelloWorld.csproj et entrez le code suivant :

    <Project>
      <ItemGroup>
        <Compile Include="helloworld.cs" />
      </ItemGroup>
    </Project>
    

    Ce ItemGroup contient un élément item Compile et spécifie un fichier source en tant qu’élément.

  2. Ajoutez un nœud Target comme élément enfant du nœud Project. Nommez le nœud Build.

    <Target Name="Build">
    </Target>
    
  3. Insérez cet élément de tâche comme élément enfant du nœud Target :

    <Csc Sources="@(Compile)"/>
    
  4. Enregistrez ce fichier projet et nommez-le Helloworld.csproj.

Votre fichier projet minimal doit ressembler au code suivant :

<Project>
  <ItemGroup>
    <Compile Include="helloworld.cs"/>
  </ItemGroup>
  <Target Name="Build">
    <Csc Sources="@(Compile)"/>
  </Target>
</Project>

Les tâches de la cible Build sont exécutées séquentiellement. Dans ce cas, la tâche Csc du compilateur C# est la seule tâche. Elle attend une liste de fichiers source à compiler, qui lui est donnée par la valeur de l'élément Compile. L'élément Compile ne référence qu'un seul fichier source, Helloworld.cs.

Notes

Dans l’élément item, vous pouvez utiliser le caractère générique astérisque (*) pour référencer tous les fichiers ayant l’extension de nom de fichier .cs, comme ceci :

<Compile Include="*.cs" />

Créer l’application

Maintenant, pour créer l'application, utilisez le fichier projet que vous venez de créer.

  1. Dans l’invite de commandes, tapez msbuild helloworld.csproj -t:Build.

    Ceci crée la cible Build du fichier projet Helloworld en appelant le compilateur C# pour créer l’application Helloworld.

  2. Testez l’application en entrant helloworld.

    Le message Hello, world! doit s’afficher.

Notes

Vous pouvez afficher plus de détails sur la génération en augmentant le niveau de détail. Pour définir le niveau de détail sur « détaillé », entrez cette commande à l’invite de commandes :

msbuild helloworld.csproj -t:Build -verbosity:detailed

Ajouter des propriétés de build

Vous pouvez ajouter des propriétés de build au fichier projet pour contrôler davantage la génération. Ajoutez maintenant ces propriétés :

  • Une propriété AssemblyName pour spécifier le nom de l'application.

  • Une propriété OutputPath pour spécifier un dossier destiné à contenir l'application.

Pour ajouter des propriétés de build

  1. Supprimez le fichier exécutable de l’application existant (plus tard, vous ajouterez une cible Clean pour gérer la suppression des anciens fichiers de sortie).

  2. Dans le fichier projet, insérez cet élément PropertyGroup juste après l'élément Project du début :

    <PropertyGroup>
      <AssemblyName>MSBuildSample</AssemblyName>
      <OutputPath>Bin\</OutputPath>
    </PropertyGroup>
    
  3. Ajoutez cette tâche à la cible Build, juste avant la tâche Csc :

    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    

    La tâche MakeDir crée un dossier dont le nom est donné par la propriété OutputPath, à condition qu'aucun dossier de ce nom n'existe déjà.

  4. Ajoutez cet attribut OutputAssembly à la tâche Csc :

    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
    

    Ceci demande au compilateur C# de produire un assembly dont le nom est donné par la propriété AssemblyName et de le placer dans le dossier dont le nom est donné par la propriété OutputPath.

  5. Enregistrez vos modifications.

Votre fichier projet doit maintenant ressembler au code suivant :

<Project>
  <PropertyGroup>
    <AssemblyName>MSBuildSample</AssemblyName>
    <OutputPath>Bin\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="helloworld.cs" />
  </ItemGroup>
  <Target Name="Build">
    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
  </Target>
</Project>

Notes

Nous vous recommandons d’ajouter le délimiteur de chemin (\) (barre oblique inverse) à la fin du nom du dossier quand vous le spécifiez dans l’élément OutputPath, au lieu de l’ajouter dans l’attribut OutputAssembly de la tâche Csc. Par conséquent,

<OutputPath>Bin\</OutputPath>

OutputAssembly="$(OutputPath)$(AssemblyName).exe" />

est mieux que

<OutputPath>Bin</OutputPath>

OutputAssembly="$(OutputPath)\$(AssemblyName).exe" />

Tester les propriétés de build

Vous pouvez maintenant générer l'application en utilisant le fichier projet où vous avez utilisé des propriétés de build pour spécifier le dossier de sortie et le nom de l'application.

  1. Dans l’invite de commandes, tapez msbuild helloworld.csproj -t:Build.

    Ceci crée le dossier \Bin\, puis appelle le compilateur C# pour créer l’application MSBuildSample et la place dans le dossier \Bin\.

  2. Pour vérifier que le dossier \Bin\ a été créé et qu’il contient l’application MSBuildSample, saisissez dir Bin.

  3. Testez l’application en saisissant Bin\MSBuildSample pour exécuter le fichier exécutable.

    Le message Hello, world! doit s’afficher.

Ajouter des cibles de génération

Ensuite, ajoutez deux cibles de plus au fichier projet, comme suit :

  • Une cible Clean qui supprime les anciens fichiers.

  • Une cible Rebuild qui utilise l'attribut DependsOnTargets pour forcer la tâche Clean à s'exécuter avant la tâche Build.

Maintenant que vous avez plusieurs cibles, vous pouvez définir la cible Build comme cible par défaut.

Pour ajouter des cibles de génération

  1. Dans le fichier projet, ajoutez ces deux cibles juste après la cible Build :

    <Target Name="Clean" >
      <Delete Files="$(OutputPath)$(AssemblyName).exe" />
    </Target>
    <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
    

    La cible Clean appelle la tâche Delete pour supprimer l'application. La cible Rebuild ne s'exécute pas tant que la cible Clean et la cible Build n'ont pas été exécutées. Même si la cible Rebuild n'a pas de tâches, elle provoque l'exécution de la cible Clean avant l'exécution de la cible Build.

  2. Ajoutez cet attribut DefaultTargets à l'élément Project du début :

    <Project DefaultTargets="Build">
    

    Ceci définit la cible Build comme cible par défaut.

Votre fichier projet doit maintenant ressembler au code suivant :

<Project DefaultTargets="Build">
  <PropertyGroup>
    <AssemblyName>MSBuildSample</AssemblyName>
    <OutputPath>Bin\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="helloworld.cs" />
  </ItemGroup>
  <Target Name="Build">
    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
  </Target>
  <Target Name="Clean" >
    <Delete Files="$(OutputPath)$(AssemblyName).exe" />
  </Target>
  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
</Project>

Tester les cibles de génération

Vous pouvez utiliser les nouvelles cibles de génération pour tester ces fonctionnalités dans le fichier projet :

  • Création de la génération par défaut

  • Définition du nom de l'application à l'invite de commandes

  • Suppression de l'application avant la génération d'une autre application

  • Suppression de l'application sans génération d'une autre application

Pour tester les cibles de génération

  1. Dans l’invite de commandes, tapez msbuild helloworld.csproj -p:AssemblyName=Greetings.

    Comme vous n’avez pas utilisé le commutateur - pour définir explicitement la cible, MSBuild exécute la cible Build par défaut. Le commutateur -p remplace la propriété AssemblyName et lui donne la nouvelle valeur, Greetings. Ceci provoque la création d’une nouvelle application, Greetings.exe dans le dossier \Bin\.

  2. Pour vérifier que le dossier \Bin\ contient à la fois l’application MSBuildSample et la nouvelle application Greetings, saisissez dir Bin.

  3. Testez l’application Greetings (par exemple, en saisissant Bin\Greetings sur Windows).

    Le message Hello, world! doit s’afficher.

  4. Supprimez l’application MSBuildSample en tapant msbuild helloworld.csproj -t:clean.

    Cela exécute la tâche Clean pour supprimer l’application qui a la valeur de la propriété AssemblyName par défaut, MSBuildSample.

  5. Supprimez l’application Greetings en tapant msbuild helloworld.csproj -t:clean -p:AssemblyName=Greetings.

    Cela exécute la tâche Clean pour supprimer l’application qui a la valeur de la propriété AssemblyName spécifiée, Greetings.

  6. Pour vérifier que le dossier \Bin\ est maintenant vide, saisissez dir Bin.

  7. Tapez msbuild.

    Même si aucun fichier projet n’est spécifié, MSBuild génère le fichier helloworld.csproj, car il n’existe qu’un seul fichier projet dans le dossier actif. Ceci provoque la création de l’application MSBuildSample dans le dossier \Bin\.

    Pour vérifier que le dossier \Bin\ contient l’application MSBuildSample, saisissez dir Bin.

Générer de façon incrémentielle

Vous pouvez indiquer à MSBuild de générer une cible seulement si les fichiers source ou les fichiers cible dont dépend la cible ont changé. MSBuild utilise l'horodatage d'un fichier pour déterminer s'il a changé.

Pour générer de façon incrémentielle

  1. Dans le fichier projet, ajoutez ces attributs après la cible Build du début :

    Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe"
    

    Ceci spécifie que la cible Build dépend des fichiers d'entrée qui sont spécifiés dans le groupe d'éléments Compile et que la cible en sortie est le fichier d'application.

    La cible Build résultante doit être similaire au code suivant :

    <Target Name="Build" Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe">
      <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
      <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
    </Target>
    
  2. Testez la cible Build en tapant msbuild -v:d dans l’invite de commandes.

    Rappelez-vous que helloworld.csproj est le fichier projet par défaut et que Build est la cible par défaut.

    Le commutateur -v:d est une abréviation de -verbosity:detailed que vous avez utilisée précédemment.

    Si vous avez déjà généré la sortie, ces lignes doivent être affichées :

    La cible est ignorée "Build", car tous les fichiers de sortie sont à jour par rapport aux fichiers d'entrée.

    MSBuild ignore la cible Build, car aucun des fichiers source n'a changé depuis la dernière génération de l'application.

Exemple en code C#

L’exemple suivant montre un fichier de projet qui compile une application C# et consigne un message contenant le nom du fichier de sortie.

Code

<Project DefaultTargets = "Compile">

    <!-- Set the application name as a property -->
    <PropertyGroup>
        <appname>HelloWorldCS</appname>
    </PropertyGroup>

    <!-- Specify the inputs by type and file name -->
    <ItemGroup>
        <CSFile Include = "*.cs"/>
    </ItemGroup>

    <Target Name="Compile">
        <!-- Run the C# compilation using input files of type CSFile -->
        <CSC
            Sources = "@(CSFile)"
            OutputAssembly = "$(appname).exe">
            <!-- Set the OutputAssembly attribute of the CSC task
            to the name of the executable file that is created -->
            <Output
                TaskParameter = "OutputAssembly"
                ItemName = "EXEFile" />
        </CSC>
        <!-- Log the file name of the output file -->
        <Message Text="The output file is @(EXEFile)"/>
    </Target>
</Project>

Exemple Visual Basic

L’exemple suivant montre un fichier de projet qui compile une application Visual Basic et consigne un message contenant le nom du fichier de sortie.

Code

<Project DefaultTargets = "Compile">

    <!-- Set the application name as a property -->
    <PropertyGroup>
        <appname>HelloWorldVB</appname>
    </PropertyGroup>

    <!-- Specify the inputs by type and file name -->
    <ItemGroup>
        <VBFile Include = "consolehwvb1.vb"/>
    </ItemGroup>

    <Target Name = "Compile">
        <!-- Run the Visual Basic compilation using input files of type VBFile -->
        <VBC
            Sources = "@(VBFile)"
            OutputAssembly= "$(appname).exe">
            <!-- Set the OutputAssembly attribute of the VBC task
            to the name of the executable file that is created -->
            <Output
                TaskParameter = "OutputAssembly"
                ItemName = "EXEFile" />
        </VBC>
        <!-- Log the file name of the output file -->
        <Message Text="The output file is @(EXEFile)"/>
    </Target>
</Project>

Et ensuite ?

Visual Studio peut faire automatiquement la plus grande partie du travail qui est montré dans cette procédure pas à pas. Pour découvrir comment utiliser Visual Studio pour créer, modifier, générer et tester des fichiers projet MSBuild, consultez la Procédure pas à pas : utiliser MSBuild.