
Présentation
Cet article décrit l'utilisation du système de génération CMake utilisé dans un grand nombre de projets C / C ++. Il est fortement recommandé de lire la première partie du manuel pour éviter de mal comprendre la syntaxe du langage CMake, qui apparaît explicitement dans tout l'article.
Lancement de CMake
Voici des exemples d'utilisation du langage CMake que vous devez pratiquer. Expérimentez avec le code source en modifiant les commandes existantes et en en ajoutant de nouvelles. Pour exécuter ces exemples, installez CMake à partir du site Web officiel .
Principe de fonctionnement
Le système de construction CMake est un wrapper sur d'autres utilitaires dépendant de la plate-forme (par exemple, Ninja ou Make ). Ainsi, dans le processus d'assemblage lui-même, aussi paradoxal que cela puisse paraître, il ne participe pas directement.
Le système de build CMake accepte un fichier CMakeLists.txt
avec une description des règles de build dans le langage CMake formel, puis génère des fichiers de build natifs et intermédiaires dans le même répertoire accepté sur votre plateforme.
Les fichiers générés contiendront des noms spécifiques d'utilitaires système, de répertoires et de compilateurs, tandis que les commandes CMake n'utilisent que le concept abstrait du compilateur et ne sont pas liées à des outils dépendants de la plate-forme qui diffèrent considérablement selon les différents systèmes d'exploitation.
Vérification de la version de CMake
La commande cmake_minimum_required
vérifie la version en cours d'exécution de CMake: si elle est inférieure au minimum spécifié, alors CMake se termine avec une erreur fatale. Un exemple qui montre l'utilisation typique de cette commande au début de n'importe quel fichier CMake:
Comme indiqué dans les commentaires, la commande cmake_minimum_required
définit tous les indicateurs de compatibilité (voir cmake_policy
). Certains développeurs ont intentionnellement défini une version basse de CMake, puis ajustent la fonctionnalité manuellement. Cela vous permet de prendre en charge simultanément les anciennes versions de CMake et, à certains endroits, de profiter de nouvelles fonctionnalités.
Au début de tout CMakeLists.txt
spécifier les caractéristiques du projet avec l'équipe de projet pour une meilleure conception avec des environnements intégrés et d'autres outils de développement.
Il convient de noter que si le mot clé LANGUAGES
est omis, les langues par défaut sont C CXX
. Vous pouvez également désactiver l'indication de toutes les langues en écrivant le mot-clé NONE
sous forme de liste de langues ou simplement laisser une liste vide.
Exécution de fichiers de script
La commande include
remplace la ligne de son appel par le code du fichier spécifié, agissant de manière similaire à la commande include
préprocesseur C / C ++. Cet exemple exécute le fichier de script MyCMakeScript.cmake
commande décrite:
message("'TEST_VARIABLE' is equal to [${TEST_VARIABLE}]")
Dans cet exemple, le premier message notifiera que la variable TEST_VARIABLE
pas encore été définie, cependant, si le script MyCMakeScript.cmake
cette variable, le deuxième message informera déjà de la nouvelle valeur de la variable de test. Ainsi, le fichier de script inclus par la commande include
ne crée pas sa propre portée, qui était mentionnée dans les commentaires de l' article précédent .
Compilation de fichiers exécutables
La commande add_executable
compile le fichier exécutable avec le nom donné dans la liste source. Il est important de noter que le nom de fichier final dépend de la plate-forme cible (par exemple, <ExecutableName>.exe
ou simplement <ExecutableName>
). Un exemple typique d'appeler cette commande:
Compilation de bibliothèque
La commande add_library
compile la bibliothèque avec la vue et le nom spécifiés à partir de la source. Il est important de noter que le nom de bibliothèque final dépend de la plate-forme cible (par exemple, lib<LibraryName>.a
ou <LibraryName>.lib
). Un exemple typique d'appeler cette commande:
- Les bibliothèques statiques sont spécifiées par le mot clé
STATIC
comme deuxième argument et sont des archives de fichiers objets associés à des fichiers exécutables et à d'autres bibliothèques au moment de la compilation; - Les bibliothèques dynamiques sont spécifiées par le mot clé
SHARED
comme deuxième argument et sont des bibliothèques binaires chargées par le système d'exploitation lors de l'exécution du programme; - Les bibliothèques modulaires sont définies par le mot-clé
MODULE
comme deuxième argument et sont des bibliothèques binaires chargées en utilisant la technique d'exécution par l'exécutable lui-même; - Les bibliothèques d'objets sont définies par le mot clé
OBJECT
comme deuxième argument et sont un ensemble de fichiers objets associés à des fichiers exécutables et à d'autres bibliothèques au moment de la compilation.
Ajout d'une source à l'objectif
Il existe des cas qui nécessitent plusieurs ajouts de fichiers source à la cible. Pour ce faire, la commande target_sources
est target_sources
, qui peut ajouter plusieurs fois des sources à la cible.
Le premier argument de la commande target_sources
est le nom de la cible précédemment spécifié à l'aide des add_executable
add_library
ou add_executable
, et les arguments suivants sont une liste des fichiers source à ajouter.
Les appels répétés à la target_sources
ajoutent les fichiers source à la cible dans l'ordre dans lequel ils ont été appelés, de sorte que les deux derniers blocs de code sont fonctionnellement équivalents:
Fichiers générés
L'emplacement des fichiers de sortie générés par les add_library
add_executable
et add_library
n'est déterminé qu'au stade de la génération, cependant, cette règle peut être modifiée avec plusieurs variables qui déterminent l'emplacement final des fichiers binaires:
Les fichiers exécutables sont toujours considérés comme des objectifs d'exécution, les bibliothèques statiques sont considérées comme des objectifs d'archivage et les bibliothèques modulaires sont considérées comme des objectifs de bibliothèque. Pour les plates-formes "non DLL", les bibliothèques dynamiques sont considérées comme des cibles de bibliothèque et pour les "plates-formes DLL", des objectifs d'exécution. Ces variables ne sont pas fournies pour les bibliothèques d'objets, car ce type de bibliothèques est généré dans les entrailles du répertoire CMakeFiles
.
Il est important de noter que toutes les plates-formes Windows, y compris Cygwin, sont considérées comme des "plates-formes DLL".
Disposition de la bibliothèque
La commande target_link_libraries
bibliothèque ou un exécutable avec d'autres bibliothèques fournies. Le premier argument de cette commande est le nom de la cible générée par les add_library
add_executable
ou add_library
, et les arguments suivants sont les noms des cibles de bibliothèque ou les chemins d'accès complets aux bibliothèques. Un exemple:
Il convient de noter que les bibliothèques modulaires ne peuvent pas être liées à des fichiers exécutables ou à d'autres bibliothèques, car elles sont uniquement destinées au chargement par des techniques d'exécution.
Travailler avec des objectifs
Comme mentionné dans les commentaires, les cibles dans CMake sont également sujettes à une manipulation manuelle, mais très limitée.
Il est possible de contrôler les propriétés des cibles conçues pour définir le processus d'assemblage du projet. La commande get_target_property
valeur de la propriété cible sur la variable fournie. Cet exemple affiche la valeur de la propriété C_STANDARD
de la cible C_STANDARD
à l'écran:
La commande set_target_properties
définit les propriétés cibles spécifiées sur les valeurs spécifiées. Cette commande accepte une liste d'objectifs pour lesquels des valeurs de propriété seront définies, puis le mot-clé PROPERTIES
, suivi d'une liste de la forme < > < >
:
L'exemple ci-dessus définit les propriétés des cibles MyTarget
qui affectent le processus de compilation, à savoir: lors de la compilation de la cible MyTarget
CMake MyTarget
compilateur d'utiliser la norme C11. Tous les noms de propriété cible connus sont répertoriés sur cette page .
Il est également possible de vérifier les cibles précédemment définies à l'aide de la construction if(TARGET <TargetName>)
:
Ajout de sous-projets
La commande add_subdirectory
invite CMake à traiter immédiatement le fichier de sous-projet spécifié. L'exemple ci-dessous illustre l'application du mécanisme décrit:
Dans cet exemple, le premier argument de la commande add_subdirectory
est le sous-projet add_subdirectory
et le deuxième argument est facultatif et informe CMake du dossier destiné aux fichiers générés du sous-projet inclus (par exemple, CMakeCache.txt
et cmake_install.cmake
).
Il convient de noter que toutes les variables de la portée parent sont héritées par le répertoire ajouté, et toutes les variables définies et redéfinies dans ce répertoire ne seront visibles que par lui (si le mot-clé PARENT_SCOPE
pas PARENT_SCOPE
spécifié par l'argument de commande set
). Cette fonctionnalité a été mentionnée dans les commentaires de l' article précédent .
Recherche de package
La commande find_package
recherche et charge les paramètres d'un projet externe. Dans la plupart des cas, il est utilisé pour la liaison ultérieure de bibliothèques externes telles que Boost et GSL . Cet exemple appelle la commande décrite pour rechercher la bibliothèque GSL puis lier:
Dans l'exemple ci-dessus, la commande find_package
accepte le nom du package comme premier argument, puis la version requise. L'option REQUIRED
nécessite l'impression d'une erreur fatale et la fermeture de CMake si le package requis n'est pas trouvé. L'opposé est l'option QUIET
, obligeant CMake à continuer son travail, même si le paquet n'a pas été trouvé.
Ensuite, l' MyExecutable
lié à la bibliothèque GSL avec la commande target_link_libraries
à l'aide de la variable GSL::gsl
, qui encapsule l'emplacement du GSL déjà compilé.
À la fin, la commande target_include_directories
est target_include_directories
, informant le compilateur de l'emplacement des fichiers d'en-tête de bibliothèque GSL. Veuillez noter que la variable GSL_INCLUDE_DIRS
est utilisée pour GSL_INCLUDE_DIRS
emplacement des en-têtes que j'ai décrits (il s'agit d'un exemple de paramètres de package importés).
Vous souhaiterez probablement vérifier le résultat d'une recherche de package si vous avez spécifié l'option QUIET
. Cela peut être fait en vérifiant la <PackageName>_FOUND
, qui est automatiquement déterminée une fois la commande find_package
. Par exemple, si vous importez avec succès les paramètres GSL dans votre projet, la variable GSL_FOUND
deviendra vraie.
En général, la commande find_package
a deux find_package
de lancement: modulaire et configuration. L'exemple ci-dessus a appliqué une forme modulaire. Cela signifie que lorsque la commande est appelée, CMake recherche un fichier de script du formulaire Find<PackageName>.cmake
dans le répertoire CMAKE_MODULE_PATH
, puis le lance et importe tous les paramètres nécessaires (dans ce cas, CMake a lancé le fichier FindGSL.cmake
standard).
Façons d'inclure des en-têtes
Vous pouvez informer le compilateur de l'emplacement des en-têtes inclus en utilisant deux commandes: include_directories
et target_include_directories
. Vous décidez lequel utiliser, cependant, il convient de considérer certaines différences entre eux (l'idée est suggérée dans les commentaires ).
La commande include_directories
affecte la portée du répertoire. Cela signifie que tous les répertoires d'en-tête spécifiés par cette commande seront utilisés pour toutes les fins du CMakeLists.txt
actuel, ainsi que pour les sous-projets traités (voir add_subdirectory
).
La commande target_include_directories
affecte target_include_directories
la cible spécifiée par le premier argument et n'affecte pas les autres cibles. L'exemple ci-dessous montre la différence entre les deux commandes:
add_executable(RequestGenerator RequestGenerator.c) add_executable(ResponseGenerator ResponseGenerator.c)
Dans les commentaires, il est mentionné que dans les projets modernes, l'utilisation des link_libraries
include_directories
et link_libraries
n'est pas souhaitable. Une alternative est les target_link_libraries
target_include_directories
et target_link_libraries
qui n'agissent que sur des objectifs spécifiques, et non sur l'ensemble de la portée actuelle.
Installation du projet
La commande install
génère des règles d'installation pour votre projet. Cette commande est capable de travailler avec des objectifs, des fichiers, des dossiers, etc. Tout d'abord, envisagez de fixer des objectifs.
Pour définir des objectifs, vous devez passer le mot clé TARGETS
comme premier argument de la fonction décrite, suivi d'une liste des objectifs à définir, puis du mot clé DESTINATION
avec l'emplacement du répertoire dans lequel les objectifs spécifiés seront définis. Cet exemple illustre une définition d'objectif typique:
Le processus de description de l'installation des fichiers est similaire, sauf que TARGETS
devez spécifier FILES
au lieu du mot clé TARGETS
. Un exemple démontrant l'installation de fichiers:
Le processus de description de l'installation des dossiers est similaire, sauf que vous devez spécifier DIRECTORY
au lieu du mot-clé FILES
. Il est important de noter que lors de l'installation, tout le contenu du dossier sera copié, et pas seulement son nom. Un exemple d'installation de dossiers est le suivant:
Après avoir terminé le traitement CMake de tous vos fichiers, vous pouvez installer tous les objets décrits avec la sudo checkinstall
(si CMake génère un Makefile
), ou effectuer cette action avec l'environnement de développement intégré qui prend en charge CMake.
Exemple visuel du projet
Ce guide ne serait pas complet sans démontrer un exemple concret d'utilisation du système de construction CMake. Considérons un diagramme de projet simple utilisant CMake comme seul système de construction:
+ MyProject - CMakeLists.txt - Defines.h - StartProgram.c + core - CMakeLists.txt - Core.h - ProcessInvoker.c - SystemManager.c
Le fichier d'assemblage principal CMakeLists.txt
décrit la compilation de l'ensemble du programme: tout d'abord, la commande add_executable
est add_executable
qui compile le fichier exécutable, puis la commande add_subdirectory
est add_subdirectory
, ce qui stimule le traitement du sous-projet, et enfin, le fichier exécutable est lié à la bibliothèque compilée:
Le fichier core/CMakeLists.txt
est appelé par le fichier d'assembly principal et compile la bibliothèque statique MyProgramCore
destinée à la liaison avec le fichier exécutable:
Après une série de commandes cmake . && make && sudo checkinstall
cmake . && make && sudo checkinstall
système de build CMake se termine avec succès. La première commande commence à traiter le fichier CMakeLists.txt
dans le répertoire racine du projet, la deuxième commande compile enfin les fichiers binaires nécessaires et la troisième commande installe l' MyProgram
compilé MyProgram
dans le système.
Conclusion
Vous pouvez maintenant écrire les vôtres et comprendre les fichiers CMake d'autres personnes, et vous pouvez lire en détail d'autres mécanismes sur le site officiel .
Le prochain article de ce guide se concentrera sur les tests et la création de packages à l'aide de CMake et sera publié dans une semaine. A très bientôt!