Englober plusieurs projets

Projet englobant

On peut aussi inclure dans un projet d'autres projets avec la commande :

add_subdirectory(source_dir)

Portée des variables

add_subdirectory crée un nouvelle portée (scope) pour les variables du CMakeLists.txt du sous-répertoire.

  • Les variables du CMakeLists.txt parent peuvent être lues. Si une telle variable est modifiée, la modification n'est pas visible par le parent.
  • Les variables du CMakeLists.txt du sous-répertoire sont invisibles par le parent.

Notion de liste dans CMake

Une chaîne de caractères peut être interprétée comme une liste, avec le caractère ; comme séparateur.

set(varName value ...)

joint les valeurs avec ; si bien que le contenu de varName peut être interprété comme la liste des valeurs en argument de set.

set(myVar a b c) # myVar = "a;b;c"

La commande list permet diverses opérations :

list(<opération> varName ...)

où opération peut être LENGTH, GET, INSERT, APPEND, PREPEND etc.

Contexte de message

Possibilité de définir un contexte pour chaque message en modifiant la variable normale (pas de cache) CMAKE_MESSAGE_CONTEXT dans CMakeLists.txt. Le contenu de CMAKE_MESSAGE_CONTEXT est interprété comme une liste dont les éléments sont affichés, séparés par des points, avant chaque message. Chaque élément de CMAKE_MESSAGE_CONTEXT ne peut contenir que lettres, chiffres et blanc souligné (_).

Utilisation habituelle :

  • On ajoute à CMAKE_MESSAGE_CONTEXT un élément indiquant le projet courant :
list(APPEND CMAKE_MESSAGE_CONTEXT <projet>)
  • On place cette commande list avant la commande project parce que la commande project déclenche les tests du compilateur (avec des affichages correspondants).
  • Si le projet est englobé, comme chaque projet ajoute un élément au contexte, on voit dans le contexte la pile d'appels.
  • Si le projet est englobé avec add_subdirectory, la modification de CMAKE_MESSAGE_CONTEXT est locale.

Choix par l'utilisateur de l'affichage ou non du contexte :

  • avec l'option --log-context de cmake, seulement pour cette exécution de cmake (pas de création de variable de cache)
  • ou en définissant la variable de cache CMAKE_MESSAGE_CONTEXT_SHOW. Nota bene : cette variable n'est pas prédéfinie par CMake donc si vous la définissez sur la ligne de commande de cmake, donnez-lui son type, BOOL. Exemple :
-DCMAKE_MESSAGE_CONTEXT_SHOW:BOOL=True

Manipulation 23

  • Créer un projet englobant les bibliothèques NR_util et Jumble.
  • Compléter CMakeLists.txt dans NR_util :
target_include_directories(nr_util INTERFACE ${PROJECT_BINARY_DIR})
  • Compléter CMakeLists.txt à la racine de Jumble, écrire les CMakeLists.txt dans les sous-répertoires.
  • Tester.

Manipulation 24

  • Créer un projet englobant les bibliothèques NR_util, Jumble, Numer_Rec_95 et Coriolis.
  • Compléter CMakeLists.txt aux racines de Jumble et Numer_Rec_95.
  • Écrire CMakeLists.txt pour Coriolis.
  • Tester.

Englober ou non un projet dans un autre

Il est intéressant d'englober un projet dans un autre projet dans certains cas particuliers. Exemples :

  • Compiler d'un seul coup un ensemble de bibliothèques, en changeant de machine, ou en changeant de version de compilateur, ou en changeant d'options de compilation (avec options d'analyse de performance, options de débogage, etc.).

  • Quand on distribue le code d'un programme, offrir à l'utilisateur la possibilité de compiler d'un seul coup le programme et ses dépendances, même si les dépendances sont dans des dépôts indépendants. Cf. plus loin FetchContent.

Mais en général, on ne veut pas inclure le projet bibliothèque dans tous les projets qui utilisent cette bibliothèque. Cela signifierait à chaque fois déplacer les sources et recompiler : on perdrait une partie de l'intérêt d'une bibliothèque. On préfère utiliser la bibliothèque déjà compilée.