CMake - Mini howto

Qu’est-ce que CMake ?

CMake est un utilitaire permettant de gĂ©nĂ©rer le “build process” d’un projet. C’est un outils du mĂȘme genre que les autotools (aussi appelĂ© pour des raisons que je tairai ‘autohell’) en

Il est bon aussi de savoir que CMake est capable de générer aussi bien des Makefiles que des fichiers de projet VC++ ou XCode (pas mal, hein?).

On a aussi une jolie progression en % de la compilation (et l’on peut toujours utiliser make -j42 pour faire chauffer les cƓurs).

##Comment on s’en sert ?

On connais tous le ./autogen.sh, ./configure puis make && sudo make install. Bien entendu, on produit tous les fichiers bien salle dans le dossier des sources, ce qui donne une magnifique liste de fichiers à ajouter au .gitignore du votre projet (ou tout autre fichier équivalent pour svn / mercurial). Avec cmake, on peut reproduire le schéma des autotools via cmake . puis make && sudo make install. Mais mieux, vous pouvez (par exemple) faire mkdir build && cd build puis cmake .. et make && sudo make install. Dite bonjour a la propreté de votre projet grùce à CMake ;)

##Comment ça fonctionne ?

C’est lĂ  qu’est le plus beau. Configurer CMake pour un projet, gĂ©rer les dĂ©pendances de libs, gĂ©nĂ©rer les libs, voir mĂȘme gĂ©nĂ©rer les packages (que ce soit des packages archlinux, debian 
). On prend trĂšs vite en main, c’est claire, et la documentation est excellente.

Je ne vais pas dĂ©tailler comment construire un fichier de config ; le tutorial CMake le fait dĂ©jĂ  trĂšs bien, et l’on trouve tout ce qu’il manque dans le wiki. (Notez que dans un VRAI projet, il vous faudra un peu plus que le tutorial). Je vais aborder les idĂ©es gĂ©nĂ©rales et les petites astuces qui m’ont servies.

D’abord, on place les instructions dans un fichier CMakeLists.txt a la racine du projet. On Ă©vite donc la multiplication des fichiers de configuration. Il est possible d’appeler des scripts d’autres dossier grĂące Ă  add_subdirectory("${PROJECT_SOURCE_DIR}/your_folder"). Il est important d’utiliser ${PROJECT_SOURCE_DIR} pour que tout se place bien quand on souhaite compiler dans un autre dossier.

On peut facilement demander a cmake de trouver des libs. En rĂšgle gĂ©nĂ©rale, on trouve un FindNomDeLaLib.cmake que l’on placera dans projet/cmake/Modules/, et l’on prendras soin d’ajouter set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/").

Une façon pratique pour compiler votre projet est de placer tous vos .c/.cpp dans un dossier src, et de tous les sĂ©lectionner (ça Ă©vite d’oublier d’ajouter un .cpp a la liste des fichiers du projet). Avec file(GLOB_RECURSE SOURCE_FILES src/*.cpp SRC) le liste des fichiers figure dans la variable “SOURCE_FILES”. Si il vous faut exclure certains fichiers, vous pouvez utiliser : file(GLOB_RECURSE UNWANTED_FILES src/FichierAExclure.cpp SRC) list (REMOVE_ITEM SOURCE_FILES ${UNWANTED_FILES})

Si vous ĂȘtes fan des tests unitaires, CMake propose une façon agrĂ©able de lancer des tests avec : add_test (NAME NomDuTeste WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/repertoiredexecution" COMMAND "commande a executer") Ça vas de “lancer un programme et vĂ©rifier qu’il EXIT_SUCCESS” Ă  “vĂ©rifier que la sortie du programme contient cette expression”.

Chose utile, que ne fournissent pas les autotools, c’est une façon unifiĂ©e de gĂšrer le numĂ©ro de version de l’application ; Toute les variables d’un CMakeListes peuvent ĂȘtre utiliser pour gĂ©nĂ©rer des fichiers Ă  partir de templates (souvent le nom du fichier avec le suffixe .in). En pratique, on dĂ©finit VERSION_MAJOR et VERSION_MINOR, puis on gĂ©nĂšre un Version.h, un doxyfile, et on utilise les valeurs pour gĂ©nĂ©rer les noms des bibliothĂšques exportĂ©s. C’est simple, intuitif, et trĂšs bien expliquĂ© dans le tutoriel. Faire une release se limite alors a changer le numĂ©ro de version dans un fichier, et de lancer la compilation pour obtenir les binaires et packages.

CMake dispose aussi d’un systùme de macros, pour faciliter la vie des maintainers, et l’on comprend donc que de plus en plus de projets tendent à l’utiliser.

Un fichier de configuration emacs est disponible (depuis la doc de cmake) pour ajouter un “cmake-mode”, et se charge avec, par exemple, (load "~/.emacs.d/cmake-mode.el").

On peux aussi contrĂŽler la gĂ©nĂ©ration d’une documentation avec doxygen. Pour cela, on rajoute un CMakeListes dans un rĂ©pertoire /doc. On demande Ă  ce que doxygen soit prĂ©sent via find_package(Doxygen). On Ă©crit un fichier template doxygen.in de configuration, oĂč les valeurs Ă  modifier sont de la forme @NOM_DUN_DEFINE@, et dĂ©finies dans le fichier de fonfiguration CMake par set(NOM_DUN_DEFINE pouĂŻc). Ensuite, on peut facilement ajouter une rĂšgle “make doc” de la façon suivante :

if(DOXYGEN_FOUND)
  configure_file(${DOXYGEN_TEMPLATE_FILE}
    ${DOXYGEN_CONFIGURED_FILE}
    @ONLY
    )
  add_custom_target(doc
    ${DOXYGEN_EXECUTABLE}
    ${DOXYGEN_CONFIGURED_FILE}
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    COMMENT "Generating API documentation with Doxygen" VERBATIM
    )
endif(DOXYGEN_FOUND)

oĂč le @ONLY signifie que seul les mots entourĂ© d’@ seront remplacĂ© (Sinon, les ${SOMETHING} sont aussi affectĂ©s).

Conclusion :

Ce qu’il faut retenir, c’est que CMake est simple Ă  configurer, offre de nombreuses fonctionnalitĂ©s, et laisse la possibilitĂ© d’ajouter celles manquantes. Beaucoup de gens sont encore habituĂ© au ./configure, et sont effrayĂ© par cette nouvelle façon d’aborder ce problĂšme. Pourtant, CMake est un rĂ©el gain de temps, et l’on voit des gros projets comme KDE changer de build system pour CMake.  On peux mĂȘme l’utiliser pour de minuscule projets (compiler les .cpp d’un dossier en un exĂ©cutable, sans dĂ©pendances particuliĂšres, se fait avec un fichier de configuration de 3 lignes), et je vous encourage justement Ă  le faire. Trois lignes pour avoir une gestion automatique des dĂ©pendances des .h, gĂ©nĂ©ration des makefiles, le tout multiplateforme, ce n’est pas cher payĂ©.

Resources :