CMake

Présentation

CMake est un outil permettant d'automatiser le processus de compilation et d'installation d'un logiciel. Comme les autotools, il s'agit d'un moteur de production visant à simplifier la compilation multiplateforme d'un code source.

A partir d'un fichier de configuration CMakeLists.txt, CMake génère les fichiers Makefile adaptés à la machine cible. En principe, pour compiler un logiciel utilisant CMake, il suffit de suivre les étapes suivantes :

$ mkdir build; cd build/ # création d'un répertoire temporaire pour la compilation
$ cmake ../src/          # équivalent du script ./configure des autotools
$ make                   # compilation
$ make install           # installation

A noter que CMake permet aussi de générer la configuration de projets Eclipse, Visual Studio, etc.

CMake fait partie d'une suite d'outils de développement logiciel développée par Kitware comprenant CMake, CTest (tests logiciels), CDash (serveur d'intégration continu) et CPack (distribution de logiciels).

Utilisation de CMake à l'IDRIS

CMake détecte automatiquement l'environnement de compilation, ce qui peut être problématique sur les machines de l'IDRIS. De plus, les fichiers de configuration CMake fournis avec les logiciels ne sont parfois pas écrits de manière assez portable. Cette documentation explique comment utiliser CMake à l'IDRIS mais vous pouvez aussi contacter l'assistance en cas de problème.

Module CMake

CMake est disponible dans l'environnement par défaut des machines de l'IDRIS mais nous vous conseillons d'utiliser une version plus récente de CMake, disponible sous la forme d'un module :

$ module load cmake

Choix des compilateurs

Les machines de l'IDRIS Ada et Turing utilisent respectivement les compilateurs Intel et IBM. Par défaut, CMake va chercher à utiliser les compilateurs GNU qui sont aussi disponibles sur la machine. Pour éviter cela, il faut indiquer à CMake les compilateurs à utiliser. Il est recommandé d'utiliser les variables d'environnement (CC, …) plutôt que les variables CMake (-DCMAKE_C_COMPILER, …)1). À chaque fois que vous changez de compilateur, il faut au préalable supprimer entièrement le répertoire temporaire servant à la compilation car les variables associées aux compilateurs ne peuvent plus être modifiées après la première exécution de CMake 2).

Sur Ada :

$ rm -rf build; mkdir build; cd build
$ CC=icc CXX=icpc cmake ../src/

Détection des dépendances

CMake détecte automatiquement les dépendances du produit à installer. CMake utilise des recettes internes qui décrivent comment trouver les dépendances. Des fichiers de recettes peuvent aussi être fournis avec le produit à installer. Les noms des fichiers de recettes sont de la forme FindDEPENDANCE.cmake.

À l'IDRIS, les dépendances sont gérées avec l'outil module. Les modules rajoutent directement aux arguments des compilateurs les chemins d'accès vers les entêtes et les fichiers de bibliothèques. Ils ne valorisent pas forcément les variables d'environnement qu'utilise CMake pour trouver les dépendances, c'est pourquoi CMake n'arrive pas toujours à trouver les chemins d'accès aux bibliothèques.

Lorsque la dépendance est déjà installée sur la machine de l'IDRIS, vous pouvez tenter de charger les modules nécessaires à la compilation avant l'exécution de CMake mais si cela ne suffit pas, il faudra aider CMake à trouver les bibliothèques en valorisant des variables CMake ou en adaptant les fichiers de recettes.

Exemple:

$ cmake -DFFTW_INCLUDE_DIR=/smplocal/pub/FFTW/3.3.2/include -DFFTW_LIBRARY=/smplocal/pub/FFTW/3.3.2/lib ../src/

La commande module show permet d'obtenir des renseignements sur les chemins d'installation des modules fournis par l'IDRIS. Lorsque les variables CMake sont valorisées, il n'est plus nécessaire de charger le module correspondant.

Les noms des variables CMake dépendent des produits. Ils sont souvent fournis dans le message d'erreur. Sinon, il faut consulter le fichier cache, les fichiers CMakeLists.txt ou utiliser l'interface graphique pour lister les variables.

Si la dépendance n'est pas disponible sur la machine, vous pouvez l'installer sur votre compte ou nous contacter. De même, contactez-nous si vous pensez qu'un module existant peut être amélioré.

Cross compilation sur Turing

Sur Turing, les nœuds de calcul n'ont pas la même architecture que la machine frontale, ce qui nécessite de faire de la compilation croisée.

Avec CMake, il faut créer un fichier décrivant la chaîne de compilation (toolchain).

bgq-toolchain.cmake
set(CMAKE_SYSTEM_NAME BlueGeneQ-static)
 
set(COMPILER_SEARCH_PATHS /bglocal/fe/pub/Modules/IDRIS/wrappers/)
 
find_program(CMAKE_C_COMPILER       mpixlc_r   ${COMPILER_SEARCH_PATHS})
find_program(CMAKE_CXX_COMPILER     mpixlcxx_r ${COMPILER_SEARCH_PATHS})
find_program(CMAKE_Fortran_COMPILER mpixlf90_r ${COMPILER_SEARCH_PATHS})
find_program(CMAKE_LINKER           mpixlcxx_r ${COMPILER_SEARCH_PATHS})
 
find_program(MPI_C_COMPILER         mpixlc_r   ${COMPILER_SEARCH_PATHS})
find_program(MPI_CXX_COMPILER       mpixlcxx_r ${COMPILER_SEARCH_PATHS})
find_program(MPI_Fortran_COMPILER   mpixlf90_r ${COMPILER_SEARCH_PATHS})
 
SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
SET_PROPERTY(GLOBAL PROPERTY TARGET_ARCHIVES_MAY_BE_SHARED_LIBS FALSE)
 
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Ce fichier s'utilise alors de la manière suivante :

$ cmake -DCMAKE_TOOLCHAIN_FILE=../bgq-toolchain.cmake ../src/

Attention: CMake ne ré-execute pas la phase de configuration lorsque le fichier contenant la configuration de la chaine de compilation est modifié.

Pour utiliser HDF5 avec CMake sur Turing, vous devez mettre à jour la variable $PATH avant l’exécution de la commande cmake :

$ module load hdf5
$ export PATH=$PATH:$HDF5_EXEDIR

Voir aussi:

Compléments

Options de configuration

Les options de compilation sont stockées dans des variables CMake. Celles-ci peuvent être valorisées sur la ligne de commande en utilisant l'option -D ou en utilisant l'interface graphique.

Exemple :

$ cmake -DCMAKE_C_FLAGS="-O3 -xAVX" ../src/

La liste des variables CMake est disponible ici mais chaque produit rajoute ses propres options. Il faut consulter le fichier cache, les fichiers CMakeLists.txt ou utiliser l'interface graphique pour lister les variables.

Système de cache

Après avoir lancé cmake une première fois, les paramètres de compilation sont sauvegardés dans le fichier cache CMakeCache.txt. Il est possible de modifier la configuration à postériori en relançant cmake. Lors du premier lancement, c'est le répertoire source qui doit être passé en argument de cmake. Ensuite, il faut lui indiquer le répertoire temporaire de compilation :

$ cd build/
$ cmake -DCMAKE_CXX_FLAGS="-O3 -xAVX" .

Après chaque modification, la phase de configuration est rejouée en utilisant les entrées du cache comme valeurs d'initialisation des variables CMake.

Comme il peut exister une logique complexe entre les variables de compilation, il est parfois moins difficile de repartir de zéro lorsque la première phase de configuration s'est mal déroulée. Il faut alors supprimer le répertoire et valoriser les variables CMake directement sur la ligne de commande.

Interface graphique

La commande ccmake permet d'accéder à l'interface curses de CMake. Comme la commande cmake, elle prend en paramètre un répertoire.

$ cd build/
$ ccmake .

L'interface affiche l'ensemble des variables CMake qui influent sur la compilation. Les variables peuvent être modifiées et les fichiers Makefile régénérés en conséquence.

Les commandes disponibles sont listées en bas de l'interface. Pour modifier une variable, il faut se positionner sur sa ligne3) et taper [Entrée].

Après avoir modifié une variable, la phase de configuration peut être relancée en utilisant [c]. L'interface affiche le résultat et il faut taper [e] pour revenir au menu. Notez que la liste des variables (ou leurs valeurs) a potentiellement été modifiée. [g] permet de valider les modifications et quitter l'interface. [t] permet d'afficher les variables cachées.

Compilation hors des sources

CMake permet d'effectuer la compilation hors du répertoire contenant les fichiers sources. Cela permet notamment de ne pas polluer ce répertoire, d'effacer facilement les fichiers générés par la compilation ou d'installer plusieurs versions d'un produit à partir du même jeu de fichiers sources.

Pour utiliser cette fonctionnalité, il suffit d'appeler la commande cmake à partir d'un répertoire dédié à la compilation (ex: le répertoire build). La commande cmake prend en argument le chemin vers le répertoire des sources.

Voici un exemple classique d'organisation :

$ ls
  src/  build-optim/  install-optim/
        build-debug/  install-debug/
        build-seq/    install-seq/
$ cd build-seq; cmake ../src/

Choix du répertoire d'installation

La variable CMake CMAKE_INSTALL_PREFIX permet de choisir le répertoire d'installation du produit. C'est l'équivalent de l'option --prefix du script ./configure des autotools.

$ cmake -DCMAKE_INSTALL_PREFIX=../install/ ../src/

Options des compilateurs

A l'instar de la plupart des environnements de développement (IDE), CMake permet de gérer un projet avec une configuration de compilation adaptée aux développements (mode Debug) ou à la phase de production (Release).

La variable CMake CMAKE_BUILD_TYPE permet de passer d'un mode à l'autre. Il est aussi possible de changer les options des compilateurs associés à ces deux modes de compilation séparément.

$ cmake -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_C_FLAGS_RELEASE="-O3 -xAVX" \
        -DCMAKE_CXX_FLAGS_RELEASE="-O3 -xAVX" \
        -DCMAKE_C_FLAGS_DEBUG="-g" \
        -DCMAKE_CXX_FLAGS_DEBUG="-g"

Les options des compilateurs Intel et celle des compilateurs IBM sont détaillées sur le site de l'IDRIS.

Afficher les commandes exécutées par CMake à la compilation

Utilisez la variable d'environnement VERBOSE :

$ VERBOSE=1 make

Enregistrer la configuration

Pour faciliter la réinstallation d'un produit sur une machine cible, le plus simple est de conserver un petit script permettant de rejouer la phase de configuration.

do-configure.sh
CC=icc CXX=icpc cmake -DCMAKE_BUILD_TYPE:STRING=Release  \
                      -DCMAKE_INSTALL_PREFIX:PATH="$WORKDIR/opt/" \
                      -DCMAKE_CXX_FLAGS_RELEASE:STRING="-O3 -xAVX" \
                      -DCMAKE_C_FLAGS_RELEASE:STRING="-O3 -xAVX" \
                      ../src/

Il est aussi possible d'utiliser l'option -C de cmake pour initialiser les variables à partir d'un script écrit en langage CMake.

A noter que CMake travaille avec des chemins absolus, ce qui ne permet pas de déplacer les répertoires après configuration4).

Documentation

1) Voir aussi: How do I use a different compiler? dans la FAQ de CMake
3) Notez que la description de la variable courante est affichée en bas de l'interface