Premiers pas avec CMake

Installation de CMake

Avec le gestionnaire de paquets de votre distribution Linux. Sur Ubuntu :

apt install cmake cmake-curses-gui cmake-qt-gui

Si la version fournie par votre distribution est trop vieille, il est facile aussi d'installer la dernière version sur le site de CMake, au format binaire.

Principe

CMake met en œuvre l'idée de configuration. On écrit les informations décrivant le code (liste des fichiers, noms des bibliothèques nécessaires (sans les chemins) etc.) dans un fichier appelé CMakeLists.txt. On n'indique pas le compilateur, les options de compilation, le chemin des bibliothèques dans CMakeLists.txt. Ces choix seront faits au moment de la configuration.

CMake gère la configuration et nécessite un autre outil pour la compilation. CMake peut travailler avec plusieurs outils de compilation au choix de l'utilisateur, et selon le système d'exploitation de la machine de compilation (on dit encore : selon la "plateforme"). CMake appelle ces outils des générateurs. Pour voir la liste disponible sur sa machine :

cmake --help

Sur Linux, les générateurs sont make et Ninja. Avec make, par exemple, CMake va créer des makefiles (très compliqués).

Principe

Répertoire de compilation

  • CMake crée des fichiers pour le générateur (des makefiles si le générateur est make, par exemple) dans un répertoire quelconque, choisi par l'utilisateur.
  • Le générateur (make par exemple) est invoqué depuis ce répertoire et les produits de compilation sont créés dans ce répertoire.
  • Répertoire de compilation = build dir = binary dir

La question du suffixe à nouveau

CMake a la même convention que la plupart des compilateurs : il suppose par défaut que .f90 et .F90 indiquent le format libre, .f et .F le format fixe. Il n'y a donc plus de raison (qu'il y avait pour make) de faire un autre choix.

Langage de CMake

(Le point noir de CMake)

  • Un fichier CMakeLists.txt est écrit dans un langage spécifique à CMake.
  • Des variables, des structures de contrôle (alternative, itération), des commandes, des fonctions…
  • Les noms de commandes, de fonctions sont insensibles à la casse. Les noms de variables sont sensibles à la casse.

  • Commentaires : #

  • Valeur d'une variable : ${myVar}
  • Les arguments d'une commande ou d'une fonction sont entre parenthèses séparés par des espaces ou des retours à la ligne.

Manipulation 13 : programme trivial

Écrivez le fichier CMakeLists.txt :

cmake_minimum_required(VERSION 3.16)
project(Plouf LANGUAGES Fortran)
add_executable(plouf plouf.f90)

Dans la commande cmake_minimum_required, vous pouvez choisir un numéro de version de CMake autre que 3.16. Conseil : dans le doute, mettez le numéro de votre version. Ce qui entre en ligne de compte dans le choix : partage du code, version disponible dans les distributions Linux, fonctionnalités de CMake utilisées.

Dans la commande project, le premier arugment est le nom du projet. Vous pouvez choisir ce que vous voulez (vous n'êtes pas obligé de prendre le même nom que celui de l'exécutable, mais c'est une bonne idée).

Dans la commande add_executable, le premier argument est un nom de "cible". C'est un identificateur dans CMake. Le nom du fichier exécutable est créé à partir du nom de la cible, selon la convention du système d'exploitation. Ne pas mettre de suffixe. Vous pouvez choisir ce que vous voulez mais c'est une bonne idée de prendre le nom du fichier source Fortran sans suffixe.

Attention : la casse n'importe pas pour les noms des commandes mais elle importe pour tous les autres mots.

Créez un répertoire de compilation :

mkdir build
cd build

Vous pouvez choisir un nom quelconque autre que build. Vous pouvez choisir ce répertoire n'importe où, en particulier en dehors de l'arborescence des sources. Vous pourriez même ne pas créer de répertoire de compilation et rester dans le répertoire source mais cela est déconseillé : CMake va créer beaucoup de fichiers pour le générateur, en plus des produits de la compilation. Par exemple si le générateur est make, CMake va créer beaucoup plus qu'un makefile.

Lancez la configuration :

cmake ..

L'argument de cmake doit être le chemin vers la racine de l'arborescence source, contenant CMakeLists.txt. Donc ce peut être le répertoire parent, .. ou sinon ce peut être n'importe quel chemin (relatif ou absolu).

Lancez la compilation :

make

Essayez make une seconde fois.

Manipulation 14 : arguments possibles de make

Les cibles de make :

make help

Voir les commandes invoquées par make :

make VERBOSE=1

Manipulation 15 : cmake-gui

Alternative à la commande cmake dans le terminal, pour choisir interactivement la configuration avec une interface graphique.

cd build
rm -r *
cmake-gui ..

L'argument de cmake-gui doit être le chemin vers la racine de l'arborescence source. Cliquer sur "Configure". Choix :

  • du générateur
  • du compilateur
  • du type de compilation : débogage, rapidité (Release), etc.

Cliquer sur "Generate".

make

Configuration et génération

Le travail de CMake est en fait divisé en deux étapes :

  • Configuration : CMake se construit une représentation interne du projet, indépendante du générateur choisi.
  • Génération : CMake crée les fichiers pour le générateur choisi.

Vocabulaire source de confusion : la génération est une opération faite par CMake et non par le générateur.

cmake sur la ligne de commande : configuration et génération enchaînées automatiquement. cmake-gui : deux boutons.

Manipulation 16 : équivalence de cmake et cmake-gui

Tous les choix avec cmake-gui peuvent aussi être faits avec cmake sur la ligne de commande. Par exemple :

cd build
rm -r *
cmake -DCMAKE_BUILD_TYPE=Debug ..
make VERBOSE=1

Manipulation 17 : voir la configuration après coup

Après cmake ou cmake-gui, pour voir la configuration qui a été choisie, regarder le fichier CMakeCache.txt créé dans le répertoire de compilation. Notamment : CMAKE_BUILD_TYPE, CMAKE_Fortran_COMPILER

Pour voir les options de compilation et la commande d'édition de liens qui vont être utilisées par make :

CMakeFiles/plouf.dir/flags.make
CMakeFiles/plouf.dir/link.txt

Le répertoire contenant flags.make et link.txt est nommé à partir du nom de la cible.

Modifier la configuration

On peut relancer cmake ou cmake-gui.

Une fois que le fichier CMakeCache.txt existe, il n'est plus nécessaire de répéter sur la ligne de commande le chemin des sources :

cmake .

ou

cmake-gui .

suffit.

Avec cmake, il n'est plus nécessaire non plus de répéter les options -D. On peut en modifier une partie ou en mettre de nouvelles.

Pour voir simplement les options :

cmake -L -N .

Si on modifie le fichier CMakeLists.txt, il n'est même pas nécessaire de relancer cmake. On peut directement lancer make. La modification de CMakeLists.txt est détectée et la configuration est enchaînée automatiquement avec la compilation.

Manipulation 18 : plusieurs configurations

cd ..
mkdir build_release
cd build_release
cmake -DCMAKE_BUILD_TYPE=Release ..
make VERBOSE=1

Un système prometteur

Le système de CMake : créer des fichiers de générateur (des makefiles) dans un répertoire indépendant des sources, répond à nos attentes :

  • Placer les produits de compilation dans un répertoire indépendant des sources.

  • Basculer facilement entre des options de débogage et des options de rapidité, ou changer de compilateur : il suffit de créer des répertoires pour différentes configurations. Pas de recompilation inutile lorsqu'on passe de l'un à l'autre. Aucune autre opération à faire que changer de répertoire.

  • Changer de machine. On peut laisser sur une machine le répertoire de compilation et déplacer les sources sur une autre machine. Si on revient à une machine, pourvu que l'on rapporte les sources au même endroit, la configuration de compilation est prête : rien à refaire.

  • Partage du code : on partage CMakeLists.txt, indépendant du compilateur et de la machine.