Procédure pas à pas : Importer des bibliothèques STL en tant qu’unités d’en-tête
Cette procédure pas à pas montre comment importer des bibliothèques STL (Standard Template Library) C++ en tant qu’unités d’en-tête dans Visual Studio. Pour découvrir un moyen encore plus rapide et plus robuste d’importer la bibliothèque standard, consultez Tutoriel : Importer la bibliothèque standard C++ à l’aide de modules.
L’importation d’un en-tête STL en tant qu’unité d’en-tête est plus simple que d’utiliser des fichiers d’en-têtes précompilés. Les unités d’en-tête sont plus faciles à configurer et à utiliser, sont sensiblement plus petites sur le disque, offrent des avantages similaires en terme de performances, et sont plus flexibles qu’un PCH partagé.
Pour plus d’informations sur les unités d’en-tête et les avantages qu’ils procurent, consultez Qu’est-ce qu’une unité d’en-tête ?. Pour comparer les unités d’en-tête avec d’autres façons d’importer la bibliothèque standard, consultez Comparer les unités d’en-tête, les modules et les en-têtes précompilés.
Prérequis
Pour utiliser des unités d’en-tête, utilisez Visual Studio 2022 ou version ultérieure, ou Visual Studio 2019 version 16.11 ou ultérieure. L’option /std:c++20
(ou ultérieure) est nécessaire pour utiliser des unités d’en-tête.
Deux approches pour importer des en-têtes STL en tant qu’unités d’en-tête
Avant de pouvoir être importé, un en-tête STL doit être compilé dans une unité d’en-tête. Une unité d’en-tête est une représentation binaire d’un fichier d’en-tête. Elle a une extension .ifc
.
L’approche recommandée consiste à créer une bibliothèque statique qui contient les unités d’en-tête générées pour les en-têtes STL que vous souhaitez utiliser. Référencez ensuite cette bibliothèque et exécutez import
sur ses unités d’en-tête. Cette approche est susceptible d’accélérer les builds et de procurer une meilleure réutilisation. Pour tester cette approche, consultez Approche 1 : Créer une bibliothèque statique d’unités d’en-tête de bibliothèque STL.
Une autre approche consiste à faire en sorte que Visual Studio recherche les en-têtes STL que vous #include
dans votre projet, à les compiler en unités d’en-tête, et à import
plutôt que #include
ces en-têtes. Cette approche est utile si vous avez un codebase volumineux, car vous n’avez pas à modifier votre code source. Cette approche est moins flexible que l’approche de bibliothèque statique, car elle ne se prête pas à la réutilisation des unités d’en-tête générées dans d’autres projets. Toutefois, vous bénéficiez toujours de l’avantage en terme de performances offert par l’importation de bibliothèques STL individuelles en tant qu’unités d’en-tête. Pour tester cette approche, consultez Approche 2 : Analyser les includes à la recherche des en-têtes STL à importer.
Approche 1 : Créer une bibliothèque statique d’unités d’en-tête de bibliothèque STL
La méthode recommandée pour consommer des bibliothèques STL en tant qu’unités d’en-tête consiste à créer un ou plusieurs projets de bibliothèque statique. Ces projets doivent se composer des unités d’en-tête de bibliothèque STL que vous souhaitez utiliser. Vous devez ensuite référencer les projets de bibliothèque pour consommer ces unités d’en-tête STL. Cela s’apparente à l’utilisation d’en-têtes précompilés partagés, mais est plus facile.
Les unités d’en-tête (et modules) intégrées à un projet de bibliothèque statique sont automatiquement accessibles aux projets de référence, car le système de projet ajoute automatiquement l’option de ligne de commande appropriée /headerUnit
au compilateur afin que les projets de référence puissent importer les unités d’en-tête.
Cette approche garantit que l’unité d’en-tête d’un en-tête particulier n’est générée qu’une seule fois. Cela vous permet d’importer une partie ou l’ensemble des unités d’en-tête, ce qui n’est pas possible avec un PCH. Vous pouvez inclure des unités d’en-tête dans n’importe quel ordre.
Dans l’exemple suivant, vous créez un projet de bibliothèque statique composé des unités d’en-tête <iostream>
et <vector>
. Une fois la solution générée, vous référencerez ce projet d’unité d’en-tête partagée à partir d’un autre projet C++. Partout où import <iostream>;
ou import <vector>;
est trouvé, l’unité d’en-tête générée pour cette bibliothèque est utilisée au lieu de traduire l’en-tête avec le préprocesseur. Cela améliore les performances de build (comme avec les fichiers PCH) lorsque le même en-tête est inclus dans plusieurs fichiers. L’en-tête n’a pas besoin d’être traité de manière répétée par les fichiers qui l’incluent. Au lieu de cela, l’unité d’en-tête compilée déjà traitée est importée.
Pour créer une bibliothèque statique qui contient les bibliothèques STL <iostream>
et <vector>
, effectuez ces étapes :
Créez un projet C++ vide. Nommez-le SharedPrj.
Sélectionnez Projet vide pour C++ parmi les types de projet disponibles dans la fenêtre Créer un projet :Ajoutez un nouveau fichier C++ au projet. Insérez-y le contenu suivant :
import <iostream>; import <vector>;
Définir les propriétés du projet
Définissez les propriétés du projet de façon à partager les unités d’en-tête de ce projet :
- Dans le menu principal de Visual Studio, sélectionnez Projet>Propriétés de SharedPrj pour ouvrir la boîte de dialogue Pages de propriétés du projet :
- Sélectionnez Toutes les configurations dans la liste déroulante Configuration, puis Toutes les plateformes dans la liste déroulante Plateforme. Ces paramètres garantissent l’application de vos modifications, que vous génériez pour le débogage ou pour la mise en production.
- Dans le volet gauche de la boîte de dialogue Pages de propriétés du projet, sélectionnez Propriétés de configuration>Général.
- Définissez l’option Type de configuration sur Bibliothèque statique (.lib).
- Définissez Norme du langage C++ sur Norme ISO C++20 (/std:c++20) (ou version ultérieure).
- Dans le volet gauche de la boîte de dialogue Pages de propriétés du projet, sélectionnez Propriétés de configuration>C/C++>Général.
- Dans la liste déroulante Analyser les sources à la recherche de dépendances de module, sélectionnez Oui. (Cette option fait en sorte que le compilateur analyse votre code à la recherche des dépendances qui peuvent être intégrées à des unités d’en-tête) :
- Choisissez OK pour fermer la boîte de dialogue Pages de propriétés du projet. Générez la solution en sélectionnant Générer>Générer la solution dans le menu principal.
Référencer la bibliothèque d’unités d’en-tête
Pour importer <iostream>
et <vector>
en tant qu’unités d’en-tête à partir de la bibliothèque statique, créez un projet qui référence la bibliothèque statique comme suit :
Avec la solution actuelle toujours ouverte, dans le menu Visual Studio, sélectionnez Fichier>Ajouter>Nouveau projet.
Dans l’Assistant Création d’un projet, sélectionnez le modèle Application console C++ et choisissez Suivant.
Nommez le nouveau projet Walkthrough. Dans la zone de liste déroulante Solution, sélectionnez Ajouter à la solution. Choisissez Créer pour créer le projet et l’ajouter à votre solution.
Modifiez le contenu du fichier source Walkthrough.cpp comme suit :
import <iostream>; import <vector>; int main() { std::vector<int> numbers = {0, 1, 2}; std::cout << numbers[1]; }
Les unités d’en-tête nécessitent l’option /std:c++20
(ou version ultérieure). Définissez la norme de langage en effectuant les étapes suivantes :
- Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet Walkthrough et sélectionnez Propriétés pour ouvrir la boîte de dialogue Pages de propriétés du projet :
- Dans le volet gauche de la boîte de dialogue Pages de propriétés du projet Walkthrough, sélectionnez Propriétés de configuration>Général.
- Dans la liste déroulante Norme du langage C++, sélectionnez Norme ISO C++20 (/std:c++20) (ou version ultérieure).
- Choisissez OK pour fermer la boîte de dialogue Pages de propriétés du projet.
Dans le projet Walkthrough, ajoutez une référence au projet SharedPrj en effectuant les étapes suivantes :
- Dans le projet Walkthrough, sélectionnez le nœud Références, puis Ajouter une référence. Sélectionnez SharedPrj dans la liste des projets : L’ajout de cette référence fait en sorte que le système de build utilise les unités d’en-tête générées par SharedPrj chaque fois qu’un
import
dans le projet Walkthrough correspond à l’une des unités d’en-tête générées dans SharedPrj. - Choisissez OK pour fermer la boîte de dialogue Ajouter une référence.
- Cliquez avec le bouton droit sur le projet Walkthrough, puis sélectionnez Définir comme projet de démarrage.
- Générez la solution. (Utilisez Générer> Générer la solution dans le menu principal.) Exécutez-le pour vérifier qu’il produit la sortie attendue :
1
L’avantage de cette approche est que vous pouvez référencer le projet de bibliothèque statique à partir de n’importe quel projet afin de réutiliser les unités d’en-tête qui s’y trouvent. Dans cet exemple, la bibliothèque statique contient les unités d’en-tête <vector>
et <iostream>
.
Vous pouvez créer un projet de bibliothèque statique monolithique qui contient tous les en-têtes STL couramment utilisés que vous souhaitez importer à partir de vos différents projets. Vous pouvez également créer des projets de bibliothèque partagée plus petits pour les différents regroupements de bibliothèques STL que vous souhaitez importer en tant qu’unités d’en-tête. Vous référencez ensuite ces projets d’unités d’en-tête partagées en fonction des besoins.
Le résultat doit être une augmentation du débit de build, car l’importation d’une unité d’en-tête réduit considérablement le travail que le compilateur doit effectuer.
Lorsque vous adoptez cette approche avec vos propres projets, générez le projet de bibliothèque statique avec des options de compilateur compatibles avec le projet qui le référence. Par exemple, les projets STL doivent être générés avec l’option du compilateur /EHsc
afin d’activer la gestion des exceptions. Il en est de même pour les projets qui référencent le projet de bibliothèque statique.
Utilisez /translateInclude
.
L’option du compilateur /translateInclude
(disponible dans la boîte de dialogue Pages de propriétés du projet sous C/C++>Général>Traduire les Includes en Imports) facilite l’utilisation d’une bibliothèque d’unités d’en-tête dans les projets plus anciens qui #include
les bibliothèques STL. Cela évite de devoir remplacer les directives #include
par import
dans votre projet, tout en vous procurant l’avantage de pouvoir importer les unités d’en-tête au lieu de les inclure.
Par exemple, si vous avez #include <vector>
dans votre projet et que vous référencez une bibliothèque statique qui contient une unité d’en-tête pour <vector>
, vous n’avez pas besoin de remplacer manuellement #include <vector>
par import <vector>;
dans votre code source. Au lieu de cela, le compilateur traite automatiquement #include <vector>
comme import <vector>;
. Pour plus d’informations sur cette approche, consultez Approche 2 : Analyser les includes à la recherche des en-têtes STL à importer. Les fichiers d’en-tête STL ne peuvent pas tous être compilés en une unité d’en-tête. Le header-units.json
fourni avec Visual Studio répertorie les fichiers d’en-tête STL pouvant être compilés en unités d’en-tête. Souvent, un en-tête qui s’appuie sur des macros pour spécifier son comportement ne peut pas être compilé en une unité d’en-tête.
Une instruction #include
qui ne fait pas référence à une unité d’en-tête est traitée comme une instruction #include
normale.
Réutiliser des unités d’en-tête parmi des projets
Les unités d’en-tête générées par un projet de bibliothèque statique sont automatiquement disponibles pour tous les projets de référence directe et indirecte. Il existe des paramètres de projet qui vous permettent de sélectionner les unités d’en-tête qui doivent être automatiquement disponibles pour tous les projets de référence. Les paramètres figurent dans les paramètres du projet sous Répertoires VC++.
- Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet et sélectionnez Propriétés pour ouvrir la boîte de dialogue Pages de propriétés du projet.
- Dans le volet gauche de la boîte de dialogue, sélectionnez Propriétés de configuration>Répertoires VC++ :
Les propriétés suivantes contrôlent la visibilité des unités d’en-tête sur le système de génération :
- Répertoires Include publics spécifie les répertoires de projet pour les unités d’en-tête qui doivent être automatiquement ajoutées au chemin d’accès include dans les projets de référence.
- Répertoires de module C++ publics spécifie les répertoires de projet qui contiennent des unités d’en-tête qui doivent être accessibles aux projets de référence. Cette propriété vous permet de rendre certaines unités d’en-tête publiques. Elle est visible par d’autres projets ; vous devez donc placer ici les unités d’en-tête que vous souhaitez partager. Si vous utilisez ce paramètre, pour plus de commodité, spécifiez Répertoires Include publics afin d’ajouter automatiquement vos en-têtes publics au chemin d’accès Include dans les projets de référence.
- Tous les modules sont publics : lorsque vous utilisez des unités d’en-tête générées dans le cadre d’un projet DLL, les symboles doivent être exportés à partir de la DLL. Pour exporter automatiquement des symboles de module, définissez cette propriété sur Oui.
Utiliser un fichier de module prédéfini
En règle générale, le moyen le plus simple de réutiliser des unités d’en-tête dans différentes solutions consiste à référencer un projet d’unités d’en-tête partagés à partir de chaque solution.
Si vous devez utiliser une unité d’en-tête générée pour laquelle vous n’avez pas le projet, vous pouvez spécifier l’emplacement où se trouve le fichier .ifc
généré afin de pouvoir l’importer dans votre solution. Pour accéder à ce paramètre :
- Dans le menu principal, sélectionnez Projet>Propriétés pour ouvrir la boîte de dialogue Pages de propriétés du projet.
- Dans le volet gauche de la boîte de dialogue, sélectionnez Propriétés de configuration>C/C++>Général.
- Dans Dépendances de module supplémentaires, ajoutez les modules à référencer, séparés par des points-virgules. Voici un exemple de format à utiliser pour Dépendances de module supplémentaires :
ModuleName1=Path\To\ModuleName1.ifc; ModuleName2=Path\To\ModuleName2.ifc
Sélectionner parmi plusieurs copies d’une unité d’en-tête
Si vous référencez des projets qui génèrent plusieurs unités d’en-tête, soit avec le même nom, soit pour le même fichier d’en-tête, vous devez spécifier celui à utiliser. Il se peut par exemple que vous disposiez de différentes versions de l’unité d’en-tête générées avec différents paramètres du compilateur, et que vous deviez spécifier celle qui correspond aux paramètres de votre projet.
Utilisez la propriété Dépendances supplémentaires de l’unité d’en-tête du projet pour résoudre les collisions en spécifiant l’unité d’en-tête à utiliser. Autrement, il n’est pas possible de prédire celle qui sera choisie.
Pour définir la propriété Dépendances supplémentaires de l’unité d’en-tête :
- Dans le menu principal, sélectionnez Projet>Propriétés pour ouvrir la boîte de dialogue Pages de propriétés du projet.
- Dans le volet gauche de la boîte de dialogue, sélectionnez Propriétés de configuration>C/C++>Général.
- Spécifiez les modules ou les fichiers d’unités d’en-tête à utiliser dans Dépendances supplémentaires de l’unité d’en-tête pour résoudre les collisions. Utilisez ce format pour Dépendances supplémentaires de l’unité d’en-tête :
Path\To\Header1.h= Path\To\HeaderUnit1.ifc;Path\To\Header2.h= Path\To\ HeaderUnit2.ifc
Important
Vérifiez que les projets qui partagent des unités d’en-tête sont générés avec des options de compilation compatibles. Si, lorsque vous implémentez l’unité d’en-tête, vous utilisez des options de compilation différentes de celles que vous avez utilisées lors de sa création, le compilateur émet des avertissements.
Remarque
Pour utiliser des unités d’en-tête générées dans le cadre d’un projet DLL, affectez la valeur Oui à Tous les modules sont publics.
Approche 2 : Analyser les includes à la recherche des en-têtes STL à importer
Une autre façon d’importer des bibliothèques STL consiste à faire en sorte que Visual Studio recherche les en-têtes STL que vous #include
dans votre projet et à les compiler en unités d’en-tête. Ensuite, le compilateur importe ces en-têtes plutôt que de les inclure.
Cette option est pratique lorsque votre projet inclut de nombreux fichiers d’en-têtes STL dans de nombreux fichiers, ou lorsque le débit de build n’est pas critique. Cette option ne garantit pas qu’une unité d’en-tête pour un fichier d’en-tête particulier n’est générée qu’une seule fois. Toutefois, elle est utile si vous avez un codebase volumineux : vous n’avez pas besoin de modifier votre code source pour tirer parti des avantages offerts par les unités d’en-tête pour la plupart des bibliothèques STL que vous utilisez.
Cette approche est moins flexible que l’approche de bibliothèque statique, car elle ne se prête pas à la réutilisation des unités d’en-tête générées dans d’autres projets. Cette approche peut ne pas convenir aux projets volumineux : elle ne garantit pas une durée de génération optimale, car toutes les sources doivent être analysées à la recherche d’instructions #include
.
Les fichiers d’en-tête ne peuvent pas tous être automatiquement convertis en unités d’en-tête. Par exemple, les en-têtes qui dépendent de la compilation conditionnelle via des macros ne doivent pas être convertis en unités d’en-tête. Il existe une liste verte sous la forme d’un fichier header-units.json
pour les en-têtes STL que le compilateur utilise lorsque /translateInclude
est spécifié. Cette liste verte détermine quels en-têtes STL peuvent être compilés en unités d’en-tête. Le fichier header-units.json
se trouve dans le répertoire d’installation de Visual Studio. Par exemple : %ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.json
. Si le fichier d’en-tête STL ne figure pas dans la liste, l’instruction est traitée comme une instruction #include
normale au lieu d’être importée comme une unité d’en-tête. Un autre avantage du fichier header-units.json
est qu’il empêche la duplication de symboles dans les unités d’en-tête générées. Autrement dit, si la compilation d’une unité d’en-tête apporte plusieurs fois un autre en-tête de bibliothèque, les symboles ne sont pas dupliqués.
Pour tester cette approche, créez un projet qui inclut deux bibliothèques STL. Ensuite, modifiez les propriétés du projet afin qu’il importe les bibliothèques en tant qu’unités d’en-tête au lieu de les inclure, comme décrit dans la section suivante.
Créer un projet d’application console C++
Effectuez ces étapes pour créer un projet qui inclut deux bibliothèques STL : <iostream>
et <vector>
.
Dans Visual Studio, créez un projet d’application console C++.
Remplacez le contenu du fichier source comme suit :
#include <iostream>; #include <vector>; int main() { std::vector<int> numbers = {0, 1, 2}; std::cout << numbers[1]; }
Définir les options du projet et exécuter le projet
Les étapes suivantes définissent l’option qui fait en sorte que le compilateur recherche les en-têtes inclus à traduire en unités d’en-tête. Elles définissent également l’option qui fait en sorte que le compilateur traite #include
comme si vous aviez écrit import
pour les fichiers d’en-tête qui peuvent être traités comme des unités d’en-tête.
- Dans le menu principal, sélectionnez Projet>Propriétés pour ouvrir la boîte de dialogue Pages de propriétés du projet.
- Sélectionnez Toutes les configurations dans la liste déroulante Configuration, puis Toutes les plateformes dans la liste déroulante Plateforme. Ces paramètres garantissent l’application de vos modifications, que vous génériez pour le débogage ou pour la mise en production, et d’autres configurations.
- Dans le volet gauche de la boîte de dialogue, sélectionnez Propriétés de configuration>C/C++>Général.
- Affectez la valeur Oui à Analyser les sources à la recherche de dépendances de module. Ce paramètre garantit que tous les fichiers d’en-tête compatibles sont compilés en unités d’en-tête.
- Affectez la valeur Oui à Traduire les Includes en Imports. Ce paramètre compile les fichiers d’en-tête STL répertoriés dans le fichier
header-unit.json
en tant qu’unités d’en-tête, puis les importe au lieu d’utiliser le préprocesseur pour les#include
. - Choisissez OK pour enregistrer vos modifications et fermer la boîte de dialogue Pages de propriétés du projet.
L’option /std:c++20
ou ultérieure est nécessaire pour utiliser des unités d’en-tête. Pour modifier la norme de langage C++ utilisée par le compilateur :
- Dans le menu principal, sélectionnez Projet>Propriétés pour ouvrir la boîte de dialogue Pages de propriétés du projet.
- Sélectionnez Toutes les configurations dans la liste déroulante Configuration, puis Toutes les plateformes dans la liste déroulante Plateforme. Ces paramètres garantissent l’application de vos modifications, que vous génériez pour le débogage ou pour la mise en production, et d’autres configurations.
- Dans le volet gauche de la boîte de dialogue Pages de propriétés du projet, sélectionnez Propriétés de configuration>Général.
- Dans la liste déroulante Norme du langage C++, sélectionnez Norme ISO C++20 (/std:c++20) (ou version ultérieure).
- Choisissez OK pour enregistrer vos modifications et fermer la boîte de dialogue Pages de propriétés du projet.
- Dans le menu principal, générez la solution en sélectionnant Générer>Générer la solution.
Exécutez la solution pour vérifier qu’elle produit la sortie attendue : 1
Pour savoir s’il convient d’adopter cette approche, le principal élément à prendre en considération est l’équilibre entre commodité et coût d’analyse de tous vos fichiers pour déterminer les fichiers d’en-tête à générer en tant qu’unités d’en-tête.
Voir aussi
Comparer les unités d’en-tête, les modules et les en-têtes précompilés
Tutoriel : Importer la bibliothèque standard C++ en utilisant des modules
Procédure pas à pas : Générer et importer des unités d’en-tête dans des projets Visual C++
/translateInclude