Version minimale
Voici la première ligne de chaque CMakeLists.txt
, qui est le nom requis du fichier recherché par CMake:
cmake_minimum_required(VERSION 3.1)
Mentionnons un peu la syntaxe de CMake. Le nom de la commandecmake_minimum_required
n’est pas sensible à la casse, donc la pratique courante est d’utiliser les minuscules. 1 Le VERSION
est un mot clé spécial pour cettefonction. Et la valeur de la version suit le mot-clé. Comme partout dans ce livre, il suffit de cliquer sur le nom de la commande pour voir la documentation officielle, et d’utiliser la liste déroulante pour changer de documentation entre les versions de CMake.
Cette ligne est spéciale ! 2 La version de CMake va également dicter les politiques,qui définissent les changements de comportement. Ainsi, si vous définissez minimum_required
à VERSION2.8
, vous obtiendrez le mauvais comportement de liaison sur macOS, par exemple, même dans les dernières versions de CMake. Si vous le définissez à 3.3 ou moins, vous obtiendrez le mauvais comportement des symboles cachés, etc. Une liste des politiques et des versions est disponible àpolicies.
À partir de CMake 3.12, cela prend en charge une gamme, comme VERSION 3.1...3.15
;cela signifie que vous prenez en charge aussi bas que 3.1 mais que vous l’avez également testé avec les paramètres de la nouvelle politique jusqu’à 3.15. C’est beaucoup plus agréable pour les utilisateurs qui ont besoin des meilleurs réglages, et en raison d’une astuce dans la syntaxe, c’est rétrocompatible avec les anciennes versions de CMake (bien que l’exécution de CMake 3.1-3.11 ne définira que la version 3.1 des politiques dans cet exemple, puisque ces versions n’ont pas traité cela spécialement). Les nouvelles versions des politiques ont tendance à être plus importantes pour les utilisateurs de macOS etWindows, qui ont aussi généralement une version très récente de CMake.
C’est ce que les nouveaux projets devraient faire :
cmake_minimum_required(VERSION 3.7...3.20)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()
Si la version de CMake est inférieure à 3.12, le bloc if sera vrai, et la politique sera définie à la version actuelle de CMake. Si CMake est 3.12 ou plus, le bloc if sera faux, mais la nouvelle syntaxe dans cmake_minimum_required
sera respectée et cela continuera à fonctionner correctement !
Attention : le mode serveur CMake de MSVC avait à l’origine un abug dans la lecture de ce format, donc si vous avez besoin de supporter des builds Windows sans ligne de commande pour les anciennes versions de MSVC,vous voudrez faire ceci à la place :
cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.20) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.20)endif()
Si vous avez vraiment besoin de définir à une faible valeur ici, vous pouvez utilisercmake_policy
pour augmenter conditionnellement le niveau de politique ou définir une politique aspecifique. S’il vous plaît, faites au moins cela pour vos utilisateurs macOS !
Setting a project
Maintenant, chaque fichier CMake de premier niveau aura la ligne suivante :
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Maintenant, nous voyons encore plus de syntaxe. Les chaînes de caractères sont citées, les espaces n’ont pas d’importance, et le nom du projet est le premier argument (positionnel). Tous les arguments des mots-clés sont optionnels. La version définit un tas de variables, commeMyProject_VERSION
et PROJECT_VERSION
. Les langues sont C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), et SWIFT
(CMake3.15+ experimental). C CXX
est la valeur par défaut. Dans CMake 3.9, DESCRIPTION
a été ajouté pour définir une description de projet, ainsi. La documentation pourproject
peut être utile.
Vous pouvez ajouter descommentaires avec le caractère #
. CMake a aussi une syntaxe en ligne pour les commentaires, mais elle est rarement utilisée.
Il n’y a vraiment rien de spécial à propos du nom du projet. Aucune cible n’est ajoutée à ce stade.
Faire un exécutable
Bien que les bibliothèques soient beaucoup plus intéressantes, et que nous passerons la plupart de notre temps avec elles, commençons par un simple exécutable.
add_executable(one two.cpp three.h)
Il y a plusieurs choses à décortiquer ici. one
est à la fois le nom du fichier exécutable généré, et le nom de la cible CMake créée (vous en entendrez beaucoup plus sur les cibles bientôt, je vous le promets). La liste des fichiers sources vient ensuite, et vous pouvez en lister autant que vous le souhaitez. CMake est intelligent, et ne compilera que les extensions de fichiers sources. Les en-têtes seront, pour la plupart, ignorés ; la seule raison de les lister est de les faire apparaître dans les IDEs. Les cibles apparaissent comme des dossiers dans de nombreux IDEs. Plus d’informations sur le système de construction général et les cibles sont disponibles à buildsystem.
Faire une bibliothèque
Faire une bibliothèque se fait avec add_library
, et est à peu près aussi simple:
add_library(one STATIC two.cpp three.h)
Vous obtenez de choisir un type de bibliothèque, STATIQUE, PARTAGÉE, ou MODULE. Si vous laissez ce choix désactivé, la valeur de BUILD_SHARED_LIBS
sera utilisée pour choisir entre STATIQUE et SHARED.
Comme vous le verrez dans les sections suivantes, vous aurez souvent besoin de faire une cible fictive, c’est-à-dire une cible où rien ne doit être compilé, par exemple, pour une bibliothèque d’en-tête seulement. Cela s’appelle une bibliothèque INTERFACE, et c’est un autre choix ; la seule différence est qu’elle ne peut pas être suivie de noms de fichiers.
Vous pouvez également faire une ALIAS
bibliothèque avec une bibliothèque existante, ce qui vous donne simplement un nouveau nom pour une cible. Le seul avantage à cela est que vous pouvez faire des bibliothèques avec ::
dans le nom (ce que vous verrez plus tard). 3
Les cibles sont vos amies
Maintenant que nous avons spécifié une cible, comment ajouter des informations à son sujet ? Par exemple, peut-être qu’elle a besoin d’un répertoire d’inclusion:
target_include_directories(one PUBLIC include)
target_include_directories
ajoute un répertoire d’inclusion à une cible. PUBLIC
ne signifie pas grand chose pour un exécutable ; pour une bibliothèque, cela permet à CMake de savoir que toutes les cibles qui se lient à cette cible doivent également avoir besoin de ce répertoire include. Les autres options sont PRIVATE
(affecte seulement la cible actuelle, pas les dépendances), et INTERFACE
(seulement nécessaire pour les dépendances).
Nous pouvons alors enchaîner les cibles:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
est probablement la commande la plus utile et la plus confuse de CMake. Elle prend une cible (another
) et ajoute une dépendance si une cible est donnée. Si aucune cible de ce nom (one
) n’existe, alors elle ajoute un lien vers une bibliothèque appelée one
sur votre chemin (d’où le nom de la commande). Ou vous pouvez lui donner un chemin complet vers une bibliothèque. Ou un drapeau d’éditeur de liens. Juste pour ajouter un dernier élément de confusion, CMake classique vous permettait de sauter la sélection de mots-clés de PUBLIC
, etc. Si cela a été fait sur une cible, vous obtiendrez une erreur si vous essayez de mélanger les styles plus bas dans la chaîne.
Concentrez-vous sur l’utilisation de cibles partout, et de mots-clés partout, et vous serez bien.
Les cibles peuvent avoir des répertoires d’inclusion, des bibliothèques liées (ou des cibles liées), des options de compilation, des définitions de compilation, des fonctionnalités de compilation (voir le chapitre C++11), et plus encore. Comme vous le verrez dans les deux chapitres incluant les projets, vous pouvez souvent obtenir des cibles (et toujours faire des cibles) pour représenter toutes les bibliothèques que vous utilisez. Même les choses qui ne sont pas de véritables bibliothèques, comme OpenMP, peuvent être représentées avec des cibles. C’est pourquoi Modern CMake est génial !
Dive in
Voyez si vous pouvez suivre le fichier suivant. Il fabrique une simple bibliothèque C++11 et un programme l’utilisant. Pas de dépendances. Je discuterai de plus d’options standard C++ plus tard, en utilisant le système CMake 3.8 pour le moment.
cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. Dans ce livre, j’éviterai surtout de vous montrer la mauvaise façon de faire les choses ; vous pouvez trouver beaucoup d’exemples de cela en ligne. Je mentionnerai des alternatives de temps en temps, mais elles ne sont pas recommandées à moins qu’elles ne soient absolument nécessaires ; souvent, elles sont juste là pour vous aider à lire un code CMake plus ancien.
2. Vous verrez parfois
FATAL_ERROR
ici, cela était nécessaire pour supporter de belles défaillances lors de l’exécution de ceci dans CMake <2.6, ce qui ne devrait plus être un problème.
3. La syntaxe
::
était initialement prévue pour les bibliothèquesINTERFACE IMPORTED
, qui étaient explicitement censées être des bibliothèques définies en dehors du projet actuel. Mais, à cause de cela, la plupart des commandestarget_*
ne fonctionnent pas sur les bibliothèquesIMPORTED
, ce qui les rend difficiles à configurer soi-même. Donc, n’utilisez pas le mot-cléIMPORTED
pour le moment, et utilisez une cibleALIAS
à la place ; cela ira bien jusqu’à ce que vous commenciez à exporter des cibles. Cette limitation a été corrigée dans CMake 3.11.