Intégration de l’extensibilité et l’ensemble d’outils du système de projet de Visual Studio C++

Le système de projet de Visual C++ est utilisé dans des fichiers .vcxproj. Il est basé sur le Système commun de projets de Visual Studio (CPS) et fournit des points d’extensibilité spécifiques à C++ supplémentaires pour faciliter l’intégration des nouveaux ensembles d’outils, des architectures de build et des plateformes cibles.

Structure des cibles MSBuild C++

Tous les fichiers .vcxproj importent ces fichiers :

<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Ces fichiers ne définissent pas trop par eux-mêmes. Au lieu de cela, ils importent d’autres fichiers basés sur les valeurs de propriété suivantes :

  • $(ApplicationType)

    Exemples : Windows Store, Android, Linux

  • $(ApplicationTypeRevision)

    Il doit s’agir d’une chaîne de version valide, avec le format major.minor[.build[.revision]].

    Par exemple : 1.0, 10.0.0.0

  • $(Platform)

    Architecture de build, nommée « Platform » pour des raisons historiques.

    Exemples : Win32, x86, x64, ARM

  • $(PlatformToolset)

    Exemples : v140, v141, v141_xp, llvm

Ces valeurs de propriété spécifient les noms des dossiers sous le dossier racine $(VCTargetsPath) :

$(VCTargetsPath)\
    Type d’application\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                Platforms\
                    $(Platform)\
                        PlatformToolsets\
                            $(PlatformToolset)
    Platforms\
        $(Platform)\
            PlatformToolsets\
                $(PlatformToolset)

Le dossier $(VCTargetsPath)\Platforms\ est utilisé lorsque $(ApplicationType) est vide, dans des projets Windows Desktop.

Ajouter un nouvel ensemble d’outils de plateforme

Pour ajouter un nouvel ensemble d’outils, par exemple « MyToolset », pour la plateforme Win32 existante, créez un dossier MyToolset sous $(VCTargetsPath)\Platforms\Win32\PlatformToolsets\, puis créez des fichiers Toolset.props et Toolset.targets à l’intérieur du dossier créé.

Chaque nom de dossier sous PlatformToolsets apparaît dans la boîte de dialogue Propriétés du projet comme un Ensemble d’outils de plateforme disponible pour la plateforme spécifiée, comme illustré ici :

Propriété de l’Ensemble d’outils de plateforme dans la boîte de dialogue Pages de propriétés du projet

Créez des dossiers MyToolset similaires et des fichiers Toolset.props et Toolset.targets dans chaque dossier de plateforme existant, pris en charge par cet ensemble d’outils.

Ajouter une nouvelle plateforme

Pour ajouter une nouvelle plateforme, par exemple, « MyPlatform », créez un dossier MyPlatform sous $(VCTargetsPath)\Platforms\, puis créez des fichiers Platform.default.props, Platform.props et Platform.targets à l’intérieur du dossier créé. Créez également un dossier $(VCTargetsPath)\Platforms\MyPlatform\PlatformToolsets\ et au moins un ensemble d’outils dans ce dernier.

Tous les noms de dossiers sous le dossier Platforms pour chaque $(ApplicationType) et $(ApplicationTypeRevision) s’affichent dans l’IDE comme des options de plateforme disponibles pour un projet.

Choix de la nouvelle plateforme dans la boîte de dialogue Nouvelle plateforme de projet

Ajouter un nouveau type d’application

Pour ajouter un nouveau type d’application, créez un dossier MyApplicationType sous $(VCTargetsPath)\Application Type\, puis créez un fichier Defaults.props à l’intérieur du dossier créé. Au moins une révision est requise pour un type d’application, créez donc également un dossier $(VCTargetsPath)\Application Type\MyApplicationType\1.0, puis créez un fichierDefaults.props à l’intérieur du dossier créé. Vous devez également créer un dossier $(VCTargetsPath)\ApplicationType\MyApplicationType\1.0\Platforms, puis vous devez créer au moins une plateforme à l’intérieur du dossier créé.

Les propriétés $(ApplicationType) et $(ApplicationTypeRevision) ne sont pas visibles dans l’interface utilisateur. Elles sont définies dans les modèles de projets et ne peuvent pas être modifiées une fois le projet créé.

Arborescence d’importation .vcxproj

Une arborescence simplifiée des importations des fichiers props et targets et des fichiers cibles Microsoft C++ présente l’apparence suivante :

$(VCTargetsPath)\Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*.props
    $(VCTargetsPath)\Type d’application\$(ApplicationType)\Default.props
    $(VCTargetsPath)\Type d’application\$(ApplicationType)\$(ApplicationTypeRevision)\Default.props
    $(VCTargetsPath)\Type d’application\$(ApplicationType)\$(ApplicationTypeRevision)\Plateformes\$(Platform)\Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.props

Les projets Windows Desktop ne définissent pas $(ApplicationType), donc ils importent uniquement

$(VCTargetsPath)\Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*.props
    $(VCTargetsPath)\Plateformes\$(Platform)\Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.props

Nous allons utiliser la propriété $(_PlatformFolder) pour conserver les emplacements des dossiers dans la plateforme $(Platform). La propriété est utilisée

$(VCTargetsPath)\Platforms\$(Platform)

dans les applications Windows Desktop, et le

$(VCTargetsPath)\Type d’application\$(ApplicationType)\$(ApplicationTypeRevision)\Plateformes\$(Platform)

dans tout le reste.

Les fichiers .props sont importés dans l’ordre suivant :

$(VCTargetsPath)\Microsoft.Cpp.props
    $(_PlatformFolder)\Platform.props
        $(VCTargetsPath)\Microsoft.Cpp.Platform.props
            $(_PlatformFolder)\ImportBefore\*.props
            $(_PlatformFolder)\PlatformToolsets\$(PlatformToolset)\Toolset.props
            $(_PlatformFolder)\ImportAfter\*.props

Les fichiers .targets sont importés dans l’ordre suivant :

$(VCTargetsPath)\Microsoft.Cpp.targets
    $(VCTargetsPath)\Microsoft.Cpp.Current.targets
        $(_PlatformFolder)\Platform.targets
            $(VCTargetsPath)\Microsoft.Cpp.Platform.targets
                $(_PlatformFolder)\ImportBefore\*.targets
                $(_PlatformFolder)\PlatformToolsets\$(PlatformToolset)\Toolset.target
                $(_PlatformFolder)\ImportAfter\*.targets

Si vous devez définir certaines propriétés par défaut pour votre ensemble d’outils, vous pouvez ajouter des fichiers aux dossiers ImportBefore et ImportAfter appropriés.

Créer des fichiers Toolset.props et Toolset.targets

Les fichiers Toolset.props et Toolset.targets ont un contrôle total sur ce qui se passe lors d’une build lorsque cet ensemble d’outils est utilisé. Ils peuvent également contrôler les débogueurs disponibles, une certaine partie de l’interface utilisateur de l’IDE, comme le contenu de la boîte de dialogue Pages de propriétés, et d’autres aspects liés au comportement du projet.

Bien qu’un ensemble d’outils puisse remplacer l’ensemble du processus de build, en général votre ensemble d’outils doit uniquement modifier ou ajouter des étapes de build, ou utiliser différents outils de build, dans le cadre d’un processus de build existant. Pour atteindre cet objectif, il existe plusieurs fichiers props et targets courants que votre ensemble d’outils peut importer. Selon ce que vous souhaitez que votre ensemble d’outils réalise, ces fichiers peuvent être utilisés comme des importations ou des exemples :

  • $(VCTargetsPath)\Microsoft.CppCommon.targets

    Ce fichier définit les parties principales du processus de build native et il importe également :

    • $(VCTargetsPath)\Microsoft.CppBuild.targets

    • $(VCTargetsPath)\Microsoft.BuildSteps.targets

    • $(MSBuildToolsPath)\Microsoft.Common.targets

  • $(VCTargetsPath)\Microsoft.Cpp.Common.props

    Définit les valeurs par défaut des ensembles d’outils utilisant les compilateurs Microsoft et ciblant Windows.

  • $(VCTargetsPath)\Microsoft.Cpp.WindowsSDK.props

    Ce fichier détermine l’emplacement du kit de développement logiciel (SDK) Windows et définit certaines propriétés importantes des applications ciblant Windows.

Intégrer des cibles spécifiques à l’ensemble d’outils avec le processus de build C++ par défaut

Le processus de build C++ par défaut est défini dans Microsoft.CppCommon.targets. Les cibles n’appellent aucun outil de build spécifique, mais ils spécifient les étapes principales de build, leur ordre et leurs dépendances.

La build C++ comporte trois étapes principales, représentées par les cibles suivantes :

  • BuildGenerateSources

  • BuildCompile

  • BuildLink

Étant donné que chaque étape de build peut être exécutée indépendamment, les cibles s’exécutant en une seule étape ne peuvent pas compter sur les groupes d’éléments et les propriétés définis dans les cibles s’exécutant dans une étape différente. Cette division facilite certaines optimisations de la performance des builds. Bien que cette séparation ne soit pas utilisée par défaut, vous êtes toujours encouragé à la respecter.

Les cibles s’exécutant à l’intérieur de chaque étape sont contrôlées par les propriétés suivantes :

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

Chaque étape comprend également les propriétés « Before » et « After ».

<Target
  Name="_BuildGenerateSourcesAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildGenerateSourcesTargets);$(BuildGenerateSourcesTargets);$(AfterBuildGenerateSourcesTargets)" />

<Target
  Name="\_BuildCompileAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildCompileTargets);$(BuildCompileTargets);$(AfterBuildCompileTargets)" />

<Target
  Name="\_BuildLinkAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildLinkTargets);$(BuildLinkTargets);$(AfterBuildLinkTargets)" />

Consultez le fichier Microsoft.CppBuild.targets pour voir des exemples des cibles incluses dans chaque étape :

<BuildCompileTargets Condition="'$(ConfigurationType)'\!='Utility'">
  $(BuildCompileTargets);
  _ClCompile;
  _ResGen;
  _ResourceCompile;
  $(BuildLibTargets);
</BuildCompileTargets>

Si vous observez les cibles, telles que _ClCompile, vous verrez qu’elles ne font rien directement par elles-mêmes, mais dépendent plutôt d’autres cibles, y compris ClCompile :

<Target Name="_ClCompile"
  DependsOnTargets="$(BeforeClCompileTargets);$(ComputeCompileInputsTargets);MakeDirsForCl;ClCompile;$(AfterClCompileTargets)" >
</Target>

ClCompile et d’autres cibles spécifiques à l’outil de build sont définies comme des cibles vides dans Microsoft.CppBuild.targets :

<Target Name="ClCompile"/>

Étant donné que la cible ClCompile est vide (sauf si elle est remplacée par un ensemble d’outils), aucune action de build réelle n’est effectuée. Les cibles des ensemble d’outils peuvent remplacer la cible ClCompile ; autrement dit, elles peuvent contenir une autre définition ClCompile après l’importation de Microsoft.CppBuild.targets :

<Target Name="ClCompile"
  Condition="'@(ClCompile)' != ''"
  DependsOnTargets="SelectClCompile">
  <!-- call some MSBuild tasks -->
</Target>

Malgré son nom, créé avant l’implémentation de la prise en charge multiplateforme par Visual Studio, la cible ClCompile n’a pas besoin d’appeler CL.exe. Elle peut également appeler Clang, gcc ou d’autres compilateurs à l’aide des tâches MSBuild appropriées.

La cible ClCompile ne doit pas avoir de dépendances, à l’exception de la cible SelectClCompile, requise pour le fonctionnement de la commande de compilation de fichiers unique dans l’IDE.

Tâches MSBuild à utiliser dans les cibles des ensemble d’outils

Pour invoquer un outil de build réel, la cible doit appeler une tâche MSBuild. Il existe une tâche Exec de base qui vous permet de spécifier la ligne de commande à exécuter. Toutefois, les outils de build disposent généralement de nombreuses options, entrées et sorties pour réaliser le suivi des builds incrémentielles. Il est donc plus judicieux de définir des tâches spéciales pour eux. Par exemple, la tâche CL convertit les propriétés MSBuild en commutateurs CL.exe, les écrit dans un fichier réponse et appelle CL.exe. Elle réalise également le suivi de tous les fichiers d’entrée et de sortie pour les builds incrémentielles ultérieures. Pour plus d’informations, consultez Builds incrémentielles et vérifications mises à jour.

Microsoft.Cpp.Common.Tasks.dll implémente ces tâches :

  • BSCMake

  • CL

  • ClangCompile (clang-gcc switches)

  • LIB

  • LINK

  • MIDL

  • Mt

  • RC

  • XDCMake

  • CustomBuild (comme Exec, mais avec le suivi d’entrée et de sortie)

  • SetEnv

  • GetOutOfDateItems

Si vous avez un outil qui réalise la même action qu’un outil existant et comprend des commutateurs de ligne de commande similaires (comme clang-cl et CL), vous pouvez utiliser la même tâche pour les deux.

Si vous devez créer une nouvelle tâche pour un outil de build, vous pouvez choisir parmi les options suivantes :

  1. Si vous utilisez cette tâche excepcionellement ou si quelques secondes n’affectent pas votre build, vous pouvez utiliser des tâches MSBuild « inline » :

    • Tâche Xaml (règle de génération personnalisée)

      Pour voir un exemple de déclaration de tâche Xaml, consultez $(VCTargetsPath)\BuildCustomizations\masm.xml et, pour son utilisation, consultez $(VCTargetsPath)\BuildCustomizations\masm.targets.

    • Tâche de code

  2. Si vous souhaitez améliorer les performances des tâches ou si vous avez simplement besoin de fonctionnalités plus complexes, utilisez le processus d’écriture de tâches MSBuild standard.

    Si toutes les entrées et sorties de l’outil ne sont pas répertoriées sur la ligne de commande de l’outil, comme dans les cas CL, MIDL et RC, et si vous souhaitez appliquer le suivi automatique des fichiers d’entrée et de sortie et la création de fichiers .tlog, dérivez votre tâche de la classe Microsoft.Build.CPPTasks.TrackedVCToolTask. Actuellement, bien qu’il existe une documentation pour la classe de base ToolTask, il n’existe aucun exemple ni documentation pour les détails de la classe TrackedVCToolTask. En cas d’un intérêt particulier, ajoutez votre voix à une demande sur la Developer Community.

Builds incrémentielles et vérifications mises à jour

Les cibles des builds MSBuild incrémentielles par défaut utilisent les attributs Inputs et Outputs. Si vous le spécifiez, MSBuild n’appelle la cible que si l’une des entrées comprend un horodateur plus récent que toutes les sorties. Étant donné que les fichiers sources incluent ou importent souvent d’autres fichiers et que les outils de build produisent différentes sorties en fonction des options de l’outil, il est difficile de spécifier toutes les entrées et sorties possibles des cibles MSBuild.

Pour gérer ce problème, la build C++ utilise une autre technique pour prendre en charge les builds incrémentielles. La plupart des cibles ne spécifient pas des entrées et des sorties, et, par conséquent, s’exécutent toujours pendant la build. Les tâches appelées par des cibles écrivent des informations sur toutes les entrées et sorties dans les fichiers tlog avec une extension .tlog. Les fichiers .tlog sont utilisés par des builds ultérieures pour vérifier ce qui a été modifié et doit être reconstruit, et ce qui est à jour. Les fichiers .tlog sont également la seule source pour la vérification mise à jour de la build par défaut dans l’IDE.

Pour déterminer toutes les entrées et sorties, les tâches d’outils natifs utilisent tracker.exe et la classe FileTracker fournie par MSBuild.

Microsoft.Build.CPPTasks.Common.dll définit la classe de base abstraite publique TrackedVCToolTask. La plupart des tâches d’outil natifs sont dérivées de cette classe.

À partir de la mise à jour 15.8 de Visual Studio 2017, vous pouvez utiliser la tâche GetOutOfDateItems implémentée dans Microsoft.Cpp.Common.Tasks.dll pour produire des fichiers .tlog pour des cibles personnalisées avec des entrées et des sorties connues. Vous pouvez également les créer à l’aide de la tâche WriteLinesToFile. Consultez la cible _WriteMasmTlogs dans $(VCTargetsPath)\BuildCustomizations\masm.targets comme exemple.

Fichiers .tlog

Il existe trois types de fichiers .tlog : lecture, écriture et ligne de commande. Les fichiers .tlog de lecture et d’écriture sont utilisés par les builds incrémentielles et par les vérifications mises à jour dans l’IDE. Les fichiers .tlog de ligne de commande sont utilisés uniquement dans les builds incrémentielles.

MSBuild fournit ces classes d’assistance pour lire et écrire des fichiers .tlog :

La classe FlatTrackingData peut être utilisée pour accéder aux fichiers .tlog de lecture et écriture, et pour identifier les entrées plus récentes que les sorties, ou si une sortie est absente. Elle est utilisée dans la vérification mise à jour.

Les fichiers .tlog de ligne de commande contiennent des informations sur les lignes de commande utilisées dans la build. Ils sont utilisés uniquement pour les builds incrémentielles, et non pour les vérifications mises à jour, de sorte que le format interne est déterminé par la tâche MSBuild qui les produit.

Format de lecture .tlog

Les fichiers de lecture .tlog (*.read.*.tlog) contiennent des informations sur les fichiers source et leurs dépendances.

Un point d’insertion (^) au début d’une ligne indique une ou plusieurs sources. Les sources qui partagent les mêmes dépendances sont séparées par une barre verticale (|).

Les fichiers de dépendances sont répertoriés après les sources, chacun sur sa propre ligne. Tous les noms de fichiers sont des chemins complets.

Par exemple, supposons que vos sources de projets se trouvent dans F:\test\ConsoleApplication1\ConsoleApplication1. Si votre fichier source, Class1.cpp, contient ces éléments,

#include "stdafx.h" //precompiled header
#include "Class1.h"

le fichier CL.read.1.tlog contient le fichier source suivi de ses deux dépendances :

^F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\CLASS1.CPP
F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.PCH
F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\CLASS1.H

Il n’est pas nécessaire d’écrire des noms de fichiers en majuscules, mais cela s’avère outil dans le cas de certains outils.

Format d’écriture .tlog

Les fichiers d’écriture .tlog (*.write.*.tlog) connectent des sources et des sorties.

Un point d’insertion (^) au début d’une ligne indique une ou plusieurs sources. Les sources multiples sont séparées par une barre verticale (|).

Les fichiers de sortie générés à partir des sources doivent être répertoriés après les sources, chacun sur sa propre ligne. Tous les noms de fichiers doivent être des chemins complets.

Par exemple, pour un projet ConsoleApplication simple qui a un fichier source Class1.cpp supplémentaire, le fichier link.write.1.tlog peut contenir :

^F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CLASS1.OBJ|F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.OBJ|F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\STDAFX.OBJ
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.ILK
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.EXE
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.PDB

Build au moment du design

Dans l’IDE, les projets .vcxproj utilisent un ensemble de cibles MSBuild pour obtenir des informations supplémentaires à partir du projet et pour régénérer les fichiers de sortie. Certaines de ces cibles sont utilisées uniquement dans les builds au moment du design, mais la plupart d’entre elles sont utilisées dans les builds régulières et dans les builds au moment du design.

Pour obtenir des informations générales sur les builds au moment du design, consultez la documentation CPS pour voir des informations sur les builds au moment du design. Cette documentation ne s’applique que partiellement aux projets Visual C++.

Les cibles CompileDesignTime et Compile mentionnées dans la documentation sur les builds au moment du design ne s’exécutent jamais dans des projets .vcxproj. Les projets .vcxproj Visual C++ utilisent différentes cibles au moment du design pour obtenir des informations IntelliSense.

Cibles au moment du design pour les informations IntelliSense

Les cibles au moment du design utilisées dans des projets .vcxproj sont définies dans $(VCTargetsPath)\Microsoft.Cpp.DesignTime.targets.

La cible GetClCommandLines collecte les options de compilateur pour IntelliSense :

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets : cibles au moment du design uniquement, requises pour l’initialisation de la build au moment du design. Parmi d’autres choses, ces cibles désactivent certaines fonctionnalités régulières des builds pour améliorer leur performance.

  • ComputeCompileInputsTargets : ensemble de cibles qui modifient les options et les éléments de compilateur. Ces cibles s’exécutent à la fois dans les builds au moment du design et dans les builds régulières.

La cible appelle la tâche CLCommandLine pour créer la ligne de commande à utiliser avec IntelliSense. Là encore, malgré son nom, elle peut gérer non seulement les options CL, mais aussi les options Clang et gcc. Le type de commutateurs du compilateur est contrôlé par la propriété ClangMode.

Actuellement, la ligne de commande produite par la tâche CLCommandLine utilise toujours des commutateurs CL (même en mode Clang), car ils sont plus faciles à analyser par le moteur IntelliSense.

Si vous ajoutez une cible qui s’exécute avant la compilation, qu’elle soit régulière ou au moment du design, assurez-vous qu’elle n’interrompt pas les builds au moment du design ni affecte leur performance. Le moyen le plus simple de tester votre cible consiste à ouvrir une invite de commandes développeur et l’exécuter :

msbuild /p:SolutionDir=*solution-directory-with-trailing-backslash*;Configuration=Debug;Platform=Win32;BuildingInsideVisualStudio=true;DesignTimebuild=true /t:\_PerfIntellisenseInfo /v:d /fl /fileloggerparameters:PerformanceSummary \*.vcxproj

Cette commande produit un journal de génération détaillé, msbuild.log, qui inclut un résumé de la performance des cibles et des tâches finales.

Assurez-vous d’utiliser Condition ="'$(DesignTimeBuild)' != 'true'" dans toutes les opérations qui sont logiques pour les builds régulières, mais qui ne le sont pas pour les builds au moment du design.

Cibles au moment du design qui génèrent des sources

Cette caractéristique est désactivée par défaut pour les projets de bureau natifs et n’est actuellement pas prise en charge dans les projets mis en cache.

Si les métadonnées GeneratorTarget sont définies pour un élément du projet, la cible s’exécute automatiquement lorsque le projet est chargé et lorsque le fichier source est modifié.

Par exemple, pour générer automatiquement des fichiers .cpp ou .h à partir des fichiers .xaml, les fichiers $(VSInstallDir)\MSBuild\Microsoft\WindowsXaml\v16.0\*\Microsoft.Windows.UI.Xaml.CPP.Targets définissent ces entités :

<ItemDefinitionGroup>
  <Page>
    <GeneratorTarget>DesignTimeMarkupCompilation</GeneratorTarget>
  </Page>
  <ApplicationDefinition>
    <GeneratorTarget>DesignTimeMarkupCompilation</GeneratorTarget>
  </ApplicationDefinition>
</ItemDefinitionGroup>
<Target Name="DesignTimeMarkupCompilation">
  <!-- BuildingProject is used in Managed builds (always true in Native) -->
  <!-- DesignTimeBuild is used in Native builds (always false in Managed) -->
  <CallTarget Condition="'$(BuildingProject)' != 'true' Or $(DesignTimeBuild) == 'true'" Targets="DesignTimeMarkupCompilationCT" />
</Target>

Pour utiliser Task.HostObject afin d’obtenir le contenu non sauvegardé des fichiers sources, les cibles et la tâche doivent être enregistrées comme MsbuildHostObjects pour les projets dans un pkgdef :

\[$RootKey$\\Projects\\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\MSBuildHostObjects\]
\[$RootKey$\\Projects\\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\MSBuildHostObjects\\DesignTimeMarkupCompilationCT;CompileXaml\]
@="{83046B3F-8984-444B-A5D2-8029DEE2DB70}"

Extensibilité du projet Visual C++ dans l’IDE Visual Studio

Le système du projet Visual C++ est basé sur le Système du projet VS et il utilise ses points d’extension. Toutefois, l’implémentation de la hiérarchie du projet est spécifique à Visual C++ et elle n’est pas basée sur CPS, l’extensibilité de la hiérarchie se limite donc aux éléments du projet.

Pages de propriétés du projet

Pour obtenir des informations générales sur la conception, consultez NET Framework Multi-Targeting pour projets VC++.

Autrement dit, les pages de propriétés que vous voyez dans la boîte de dialogue Propriétés du projet pour un projet C++ sont définies par les fichiers de règles. Un fichier de règles spécifie un ensemble de propriétés à afficher sur une page de propriétés et montre où et comment ces propriétés doivent être enregistrées dans le fichier projet. Les fichiers de règles sont des fichiers .xml utilisant le format Xaml. Les types utilisés pour les sérialiser sont décrits dans Microsoft.Build.Framework.XamlTypes. Pour plus d’informations sur l’utilisation des fichiers de règles dans des projets, consultez Fichiers de règles XML de la page de propriétés.

Les fichiers de règles doivent être ajoutés au groupe d’éléments PropertyPageSchema :

<ItemGroup>
  <PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\general.xml;"/>
  <PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\general_file.xml">
    <Context>File</Context>
  </PropertyPageSchema>
</ItemGroup>

Les métadonnées Context limitent la visibilité de la règle, qui est à son tour contrôlée par le type de règle et peut avoir l’une des valeurs suivantes :

Project | File | PropertySheet

CPS prend en charge d’autres valeurs selon le type de contexte, mais elles ne sont pas utilisées dans les projets Visual C++.

Si la règle doit rester visible dans plusieurs contextes, utilisez des points-virgules (;) pour séparer les valeurs de contexte, comme illustré ici :

<PropertyPageSchema Include="$(MyFolder)\MyRule.xml">
  <Context>Project;PropertySheet</Context>
</PropertyPageSchema>

Format de règle et types principaux

Le format de règle est simple. Cette section décrit uniquement les attributs affectant l’apparence de la règle dans l’interface utilisateur.

<Rule
  Name="ConfigurationGeneral"
  DisplayName="General"
  PageTemplate="generic"
  Description="General"
  xmlns="http://schemas.microsoft.com/build/2009/properties">

L’attribut PageTemplate définit l’affichage de la règle dans la boîte de dialogue Pages de propriétés . L’attribut peut avoir l’une des valeurs suivantes :

Attribut Description
generic Toutes les propriétés sont affichées sur une page, sous Titres de catégories
La règle peut être visible dans les contextes Project et PropertySheet, mais pas dans File.

Exemple : $(VCTargetsPath)\1033\general.xml
tool Les catégories sont affichées comme sous-pages.
La règle peut être visible dans tous les contextes : Project, PropertySheet et File.
La règle n’est visible dans les propriétés du projet que si le projet comprend des éléments avec ItemType défini comme Rule.DataSource, sauf si le nom de la règle est inclus dans le groupe d’éléments ProjectTools.

Exemple : $(VCTargetsPath)\1033\clang.xml
debugger La page est affichée dans la page de débogage.
Les catégories sont actuellement ignorées.
Le nom de la règle doit correspondre à l’attribut ExportDebugger de l’objet MEF du démarrage du débogage.

Exemple : $(VCTargetsPath)\1033\debugger_local_windows.xml
custom Modèle personnalisé. Le nom du modèle doit correspondre à l’attribut ExportPropertyPageUIFactoryProvider de l’objet MEF de PropertyPageUIFactoryProvider. Consultez Microsoft.VisualStudio.ProjectSystem.Designers.Properties.IPropertyPageUIFactoryProvider.

Exemple : $(VCTargetsPath)\1033\userMacros.xml

Si la règle utilise l’un des modèles de propriété basés sur grilles, elle peut utiliser ces points d’extensibilité dans ses propriétés :

Étendre une règle

Si vous souhaitez utiliser une règle existante, mais que vous devez ajouter ou supprimer (autrement dit, masquer) quelques propriétés, vous pouvez créer une règle d’extension.

Remplacer une règle

Peut-être souhaitez-vous que votre ensemble d’outils utilise la plupart des règles par défaut du projet, mais seulement pour remplacer une ou plusieurs d’entre elles. Par exemple, supposons que vous souhaitez uniquement modifier la règle C/C++ pour afficher différents commutateurs du compilateur. Vous pouvez fournir une nouvelle règle avec le même nom et le même nom d’affichage que la règle existante, et l’inclure dans le groupe d’éléments PropertyPageSchema après l’importation des cibles cpp par défaut. Une seule règle avec un nom attribué est utilisée dans le projet et la dernière règle incluse dans le groupe d’éléments PropertyPageSchema l’emporte.

Éléments de projet

Le fichier ProjectItemsSchema.xml définit les valeurs ContentType et ItemType des éléments traités comme des éléments de projet, et définit les éléments FileExtension pour déterminer le groupe d’éléments auquel un nouveau fichier est ajouté.

Le fichier ProjectItemsSchema par défaut se trouve dans $(VCTargetsPath)\1033\ProjectItemsSchema.xml. Pour l’étendre, vous devez créer un fichier de schéma avec un nouveau nom, tel que MyProjectItemsSchema.xml :

<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">

  <ItemType Name="MyItemType" DisplayName="C/C++ compiler"/>

  <ContentType
    Name="MyItems"
    DisplayName="My items"
    ItemType=" MyItemType ">
  </ContentType>

  <FileExtension Name=".abc" ContentType=" MyItems"/>

</ProjectSchemaDefinitions>

Ensuite, dans le fichier cible, ajoutez :

<ItemGroup>
  <PropertyPageSchema Include="MyProjectItemsSchema.xml"/>
</ItemGroup>

Exemple : $(VCTargetsPath)\BuildCustomizations\masm.xml

Débogueurs

Le service de débogage dans Visual Studio prend en charge l’extensibilité du moteur de débogage. Pour plus d’informations, consultez ces exemples :

Pour spécifier les moteurs de débogage et d’autres propriétés de la session de débogage, vous devez implémenter un composant MEF du Lanceur de débogage et ajouter une règle debugger. Pour voir un exemple, consultez le fichier $(VCTargetsPath)\1033\debugger_local_windows.xml file.

Déployer

Les projets .vcxproj utilisent l’extensibilité du système de projets Visual Studio pour les fournisseurs de déploiement.

Vérification mise à jour des bulds

Par défaut, la vérification mise à jour des builds exige la création de fichiers .tlog d’écriture et lecture dans le dossier $(TlogLocation) pendant la build pour toutes les entrées et sorties de la build.

Pour utiliser une vérification mise à jour :

  1. Désactivez la vérification mise à jour par défaut en ajoutant la fonctionnalité NoVCDefaultBuildUpToDateCheckProvider dans le fichier Toolset.targets :

    <ItemGroup>
      <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" />
    </ItemGroup>
    
  2. Implémentez votre propre IBuildUpToDateCheckProvider.

Mise à niveau des projets

Moteur de mise à niveau par défaut des projets .vcxproj

Le moteur de mise à niveau par défaut des projets .vcxproj modifie PlatformToolset, ApplicationTypeRevision, la version de l’ensemble d’outils MSBuild et .NET Framework. Les deux derniers sont toujours remplacés par les valeurs par défaut de la version de Visual Studio, mais PlatformToolset et ApplicationTypeRevision peuvent être contrôlés par des propriétés MSBuild spéciales.

Le moteur de mise à niveau utilise ces critères pour déterminer si un projet peut faire l’objet d’une mise à niveau ou non :

  1. Pour les projets qui définissent ApplicationType et ApplicationTypeRevision, il existe un dossier avec un numéro de révision plus élevé que le dossier actuel.

  2. La propriété _UpgradePlatformToolsetFor_<safe_toolset_name> est définie pour l’ensemble d’outils actuel et sa valeur n’est pas égale à l’ensemble d’outils actuel.

    Dans ces noms de propriétés, <safe_toolset_name> représente le nom de l’ensemble d’outils avec tous les caractères non alphanumériques remplacés par un trait de soulignement (_).

Lorsqu’un projet est susceptible d’être mis à niveau, il participe à la solution de reciblage. Pour plus d’informations, consultez IVsTrackProjectRetargeting2.

Si vous souhaitez peaufiner le noms d’un projet dans l’Explorateur de solutions lorsque les projets utilisent un ensemble d’outils spécifique, définissez une propriété _PlatformToolsetShortNameFor_<safe_toolset_name>.

Pour voir des exemples de définitions de propriétés_UpgradePlatformToolsetFor_<safe_toolset_name> et _PlatformToolsetShortNameFor_<safe_toolset_name>, consultez le fichier Microsoft.Cpp.Default.props. Pour voir des exemples d’utilisation, consultez le fichier $(VCTargetPath)\Microsoft.Cpp.Platform.targets.

Moteur de mise à niveau d’un projet personnalisé

Pour utiliser un objet du moteur de mise à niveau d’un projet personnalisé, implémentez un composant MEF, comme illustré ici :

/// </summary>
[Export("MyProjectUpgrader", typeof(IProjectRetargetHandler))]
[Export(typeof(IProjectRetargetHandler))]
[ExportMetadata("Name", "MyProjectUpgrader")]
[OrderPrecedence(20)]
[PartMetadata(ProjectCapabilities.Requires, ProjectCapabilities.VisualC)]

internal class MyProjectUpgrader: IProjectRetargetHandler
{
    // ...
}

Votre code peut importer et appeler l’objet du moteur de mise à niveau .vcxproj par défaut :

// ...
[Import("VCDefaultProjectUpgrader")]
// ...
    IProjectRetargetHandler Lazy<IProjectRetargetHandler>
    VCDefaultProjectUpgrader { get; set; }
// ...

IProjectRetargetHandler est défini dans Microsoft.VisualStudio.ProjectSystem.VS.dll et est similaire à IVsRetargetProjectAsync.

Définissez la propriété VCProjectUpgraderObjectName pour indiquer au système de projet qu’il doit utiliser votre objet du moteur de mise à niveau personnalisé :

<PropertyGroup>
  <VCProjectUpgraderObjectName>MyProjectUpgrader</VCProjectUpgraderObjectName>
</PropertyGroup>

Désactiver la mise à niveau d’un projet

Pour désactiver les mises à niveau des projets, utilisez une valeur NoUpgrade :

<PropertyGroup>
  <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
</PropertyGroup>

Mise en cache et extensibilité d’un projet

La mise en cache du projet a été introduite pour améliorer la performance lors de l’utilisation des solutions C++ volumineuses dans Visual Studio 2017. Elle est implémentée en tant que base de données SQLite peuplée avec des données de projet, puis elle est utilisée pour charger des projets sans charger des projets MSBuild ou CPS dans la mémoire.

Comme il n'y a pas d'objets CPS présents pour les projets .vcxproj chargés à partir du cache, les composants MEF de l'extension qui importent UnconfiguredProject ou ConfiguredProject ne peuvent pas être créés. Pour prendre en charge l’extensibilité, la mise en cache du projet n’est pas utilisée si Visual Studio détecte qu’un projet utilise (ou est susceptible d’utiliser) des extensions MEF.

Ces types de projets sont toujours entièrement chargés et comprennent des objets CPS dans la mémoire, de sorte que toutes les extensions MEF sont créées pour eux :

  • Projets start-up

  • Projets qui disposent d’un moteur de mise à niveau de projets personnalisé ; c’est à dire qu’ils définissent une propriété VCProjectUpgraderObjectName.

  • Projets qui ne ciblent pas Windows de bureau ; c’est-à-dire qu’ils définissent une propriété ApplicationType

  • Projets avec éléments partagés (.vcxitems) et tous les projets qui les référencent par l’importation des projets .vcxitems.

Si aucune de ces conditions n’est détectée, une mise en cache du projet est créée. Le cache inclut toutes les données du projet MSBuild requises pour répondre aux requêtes get sur les interfaces VCProjectEngine. Cela signifie que toutes les modifications au niveau des fichiers props et targets de MSBuild réalisées par une extension doivent simplement fonctionner dans les projets chargés à partir du cache.

Expédition de votre extension

Pour plus d’informations sur la création de fichiers VSIX, consultez Expédition des extensions Visual Studio. Pour plus d’informations sur l’ajout de fichiers à des emplacements d’installation spéciaux, par exemple pour ajouter des fichiers sous $(VCTargetsPath), consultez Installation en dehors du dossier d’extensions.

Ressources supplémentaires

Le système de génération de Microsoft (MSBuild) fournit le moteur de build et le format XML extensible pour les fichiers projet. Vous devez être familiarisé avec les concepts MSBuild de base et le mode de fonctionnement de MSBuild pour Visual C++, afin d’étendre le système de projet Visual C++.

L’infrastructure d’extensibilité managée (MEF) fournit les API d’extension utilisées par CPS et le système de projet Visual C++. Pour obtenir une vue d’ensemble de l’utilisation de MEF par CPS, consultez CPS et MEF dans la vue d’ensemble de VSProjectSystem de MEF.

Vous pouvez personnaliser le système de build existant pour ajouter des étapes de build ou de nouveaux types de fichiers. Pour plus d’informations, consultez la Vue d’ensemble de MSBuild (Visual C++) et Utilisation des propriétés des projets.