Académique Documents
Professionnel Documents
Culture Documents
Dans ce TL, nous allons étudier l'utilisation de cmake, un moteur de production particulier qu'on
retrouvera par la suite quand on utilisera ROS par exemple. Mais qu'est ce qu'un moteur de production
et pourquoi on s'y intéresserait ?
Prenons un exemple et racontons une petite histoire. Vous développez une librairie C++ sous Linux.
Vous êtes un peu calé en C++ et vous savez compiler "à la main" votre librairie. Supposons que ma
librairie ne soit définie que par le fichier malib.cpp,
Ok très bien mais en plus vous souhaitez inclure des exemples pour montrer aux utilisateurs de votre
librairie comment l'utiliser. Pas de problème, on sait compiler des exemples "à la main" en précisant à
l'édition de lien notre librairie.
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 2/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
bash:$ ./ex1
Mais au fait, comme disait un auteur célèbre "un code sans commentaire est comme un commentaire
sans code", donc on commente le code et on voudrait générer une documentation Doxygen pour avoir
de jolies pages de documentation facilement exploitables. Et puis imaginons qu'on ait envie d'ajouter
des exemples à compiler séparément, faut-il vraiment tout se compiler à la main en se souvenant de
toutes ces syntaxes ? Et si jamais seul le fichier d'exemple a changé, on sait qu'on a besoin de
recompiler uniquement le binaire associé. D'accord, mais si vous êtes plusieurs à travailler sur le projet
comment savoir ce qui doit être recompilé au regard de ce qui a changé ? Une première réponse qui
n'est pas complètement satisfaisante est d'utiliser des Makefile. Les Makefiles vous permettent
d'automatiser en partie la compilation, s'assurant en particulier de ne recompiler que ce qui est
nécessaire et fournissant également des règles de compilation génériques applicables à plusieurs cibles.
Make qui utilise les fichiers de configuration Makefile est un moteur de production. Néanmoins la
syntaxe des Makefiles reste un peu lourde (croyez moi). On lui préfère parfois soit des alternatives
(comme scons, distutils, ant), soit des surcouches à Make qui vont générer des Makefiles à partir de
quelques fichiers de configuration plus simples à écrire que les Makefile. C'est ce deuxième aspect
qu'on va voir dans ce TL.
On va en particulier s'intéresser à CMake qui présente plusieurs avantages par rapport à d'autres
générateurs de Makefiles (comme les autotools) :
on compile généralement "en dehors" du répertoire source et on laisse donc le répertoire source
intact
on utilise une seule syntaxe relativement simple
l'outil est cross-plateform, il tourne aussi bien sous Linux, MacOS, Windows
faire appel à cmake pour qu'il génère les makefiles (et éventuellement d'autres formats, on en
reparlera)
faire appel à make pour compiler le projet
Principe général
Le principe d’une compilation à l’aide de CMake est d’écrire des fichiers CMakeLists.txt dans tous les
répertoires qui contiennent du code, documentation, .. à compiler/installer. Appelons ROOT le répertoire
racine du projet. La coutume est alors de créer un sous-répertoire build, dans lequel on va compiler
notre package puis d’y appeler cmake. On dit alors qu'on construit le projet "out-of-source", tout les
fichiers temporaires seront dans le sous-répertoire ROOT/build qu'on pourra supprimer si besoin sans
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 4/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
affecter notre projet. cmake va alors créer des fichiers de compilation dépendants de l’architecture/OS.
CMake peut générer différents fichiers projets ou de compilation :
bash:~$ cd ROOT
bash:~/ROOT$ mkdir build
bash:~/ROOT$ cd build
bash:~/ROOT/build/$ cmake .. -G"Unix Makefiles"
// Ou plus simplement sous Linux
bash:~/ROOT/build/$ cmake ..
bash:~/ROOT/build/$ make
// et pour l'installation
bash:~/ROOT/build/$ make install
Cmake est multi-plateforme et présente l'avantage de n'utiliser qu'une seule syntaxe pour les
CMakeLists.txt par rapport aux autotools pour lesquels la syntaxe peut être un peu obscure.
Fichiers de configuration
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 5/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Ex1
|----- CMakeLists.txt
|----- src
|---- CMakeLists.txt
|---- main.cpp
|----- build
Fichier Ex1/src/main.cpp
#include <iostream>
Il nous reste à définir les fichiers CMakeLists.txt. Le fichier à la racine s'assure que la version de cmake
est suffisamment récente, définit le nom du projet (pas nécessaire pour les Makefile Unix mais
nécessaires pour générer, par exemple des fichiers de projet Eclipse, CodeBlocks, ..) indique de
compiler en release (en incluant les options d'optimisation du compilateur) et indique le sous-répertoire
dans lequel il y a quelque chose à faire (en l'occurrence compiler notre exécutable).
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 6/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex1/CMakeLists.txt
Dans le sous-répertoire src/, on indique un exécutable à construire, son nom et les fichiers sources
nécessaires pour le compiler en appelant add_executable.
La commande install permet d'installer des fichiers comme par exemple notre exécutable une fois
compilé. Il existe en fait plusieurs commandes install en fonction des arguments qui lui sont passés :
"install(TARGETS ...)", "install(FILES ...)", "install(PROGRAMS ...)", "install(DIRECTORY ...)". Pour
installer notre exécutable, nous allons utiliser "install(PROGRAMS ...)" qui donne les droits d'exécution
au fichier installé. La commande prends également en argument la destination qui doit se comprendre
comme relative au chemin définit par la variable CMAKE_INSTALL_PREFIX qui vaut par défaut
/usr/local. On va voir un peu plus loin comment le changer.
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 7/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/mainDemo
DESTINATION bin
RENAME ${CMAKE_PROJECT_NAME}-mainDemo)
Compilation et installation
Pour compiler le projet, il suffit de se rendre dans le répertoire build puis de générer des makefiles en
invoquant cmake et enfin de compiler le projet:
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 8/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
cd Ex1/build
cmake ..
make
./src/mainDemo
Si vous voulez voir les commandes de compilation utilisées, appelez make VERBOSE=true.
Pour l'installation, tentons
make install
Oups, l'installation ne fonctionne pas. Vous devriez voir dans le message d'erreur que cmake essayer
d'installer votre cible dans /usr/local/, chemin auquel vous n'avez pas en principe droit d'écriture. Si
c'est malgré tout l'endroit ou vous souhaitiez installer votre cible, il faudrait invoquer la commande
"sudo make install". Mais imaginons qu'on souhaite installer nos cibles dans "MONCHEMIN/..". On
invoquerait alors cmake ainsi :
cmake .. -DCMAKE_INSTALL_PREFIX=MONCHEMIN
make install
Pour construire une librairie, le principe est similaire à la construction d’un binaire sauf qu’on fait appel
à la commande add_library au lieu de add_executable. On considère l’arborescence suivante :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 9/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Ex2
|----- CMakeLists.txt
|----- src
|---- CMakeLists.txt
|---- fonct.cpp
|---- fonct.hpp
|---- monct.cpp
|---- monct.hpp
|----- examples
|---- CMakeLists.txt
|---- ex1.cpp
|---- ex2.cpp
|----- build
Fichier Ex2/src/fonct.hpp
#pragma once
Fichier Ex2/src/fonct.cpp
#include "fonct.hpp"
int f(int x) {
return 3 * x;
}
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 10/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex2/src/monct.hpp
#pragma once
Fichier Ex2/src/monct.cpp
#include "monct.hpp"
#include <math.h>
double m(double x) {
return sqrt(x);
}
Fichier Ex2/examples/ex1.cpp
#include <iostream>
#include <cassert>
#include "fonct.hpp"
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 11/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex2/examples/ex2.cpp
#include <iostream>
#include <cassert>
#include "monct.hpp"
Fichiers de configuration
Fichier Ex2/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Release)
project(ex2)
add_subdirectory(src)
add_subdirectory(examples)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 12/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Le fichier src/CMakeLists.txt introduit la syntaxer pour compiler une librairie partagée (dynamique). La
deuxième partie du fichier introduit une nouvelle commande, la commande file que nous utilisons ici
pour collecter tout les fichiers hpp. Pour le coup, on peut ajouter des hpp dans le répertoire, pas besoin
de toucher au CMakeLists.txt pour qu'ils soient pris en compte. On ne pourrait pas faire de même
pour définir les sources permettant de compiler la librairie ?
Fichier Ex2/src/CMakeLists.txt
add_library(toto
SHARED
fonct.cpp monct.cpp)
file(
GLOB
headers
*.hpp
)
install(FILES ${headers}
DESTINATION include/${CMAKE_PROJECT_NAME})
Il nous reste un dernier CMakeLists à définir, celui du répertoire Ex2/examples. Je vous le montre et on
le commente ensuite.
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 13/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex2/examples/CMakeLists.txt
include_directories (${CMAKE_SOURCE_DIR}/src)
file(
GLOB
usage_examples
*.cpp
)
foreach(f ${usage_examples})
get_filename_component(exampleName ${f} NAME_WE)
add_executable (${exampleName} ${f})
target_link_libraries(${exampleName} toto)
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${exampleName}
DESTINATION bin
RENAME ${CMAKE_PROJECT_NAME}-${exampleName})
endforeach(f)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 14/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Que vous compiliez un exécutable ou une librairie, vous pouvez avoir besoin d'ajouter des flags de
compilation/linkage à votre cible. Nous verrons dans la prochaine partie comment récupérer des flags
de compilation/linkage lorsque votre cible a des dépendances externes (e.g. écrire une interface
graphique GTK, QT, ..) et que nous pouvons récupérer grâce à l'outil pkg-config ou à la macro CMake
find_package. Qu'en est-il si vous souhaitez ajouter des flags propres à votre projet ? Les flags à ajouter
sont de deux natures :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 15/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Pour modifier ces différents flags, on peut utiliser les commandes cmake ci-dessous, appliquées à
"macible" construite par add_executable ou add_library :
Pour voir le chemin de compilation/linkage utilisé à la compilation, vous pouvez invoquer make
VERBOSE=true. Vous pouvez aussi inspecter et modifier les variables utilisées pour construire votre cible
:
Notez que certaines options sont déjà passées par cmake lors de l'appel de certaines macros :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 16/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Pour le moment, nous avons construit des exécutables et des librairies qui vivent dans leur monde et
n'ont pas besoin de fonctions définies par des librairies non standards (autres que libc, libstdc++ par
example). On pourrait les spécifier à la main dans cmake (il y a des variables pour les CFLAGS et
LDFLAGS) mais ça ne serait pas élégant et pas efficace. Regardez par exemple ce qu'il faut préciser
quand on compile un exécutable utilisant gtk+2.0 :
Il y a au moins deux façons d'indiquer à cmake de chercher des librairies non standards et de les inclure
dans les chemins de compilation.
find_package
La première façon de faire est d'utiliser la commande find_package. Son utilisation est assez simple, on
insère dans un CMakeLists.txt une ligne du style : find_package(MON_MODULE REQUIRED) . Le mot
REQUIRED est optionnel mais stoppe la compilation si le package n’est pas trouvé. find_package fait
appel à des fichiers fournit lors de l’installation de CMake qui permette de trouver un certain nombre de
packages standards. Pour savoir lesquels, faites :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 17/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
cmake --help-module-list
En invoquant find_package(toto) par example, cmake va chercher un script FindToto.cmake; Ces scripts
sont par défauts dans /usr/share/cmake-2.8/Modules/. On trouve par example FindGTK2, FindQT,
FindBoost, ...; En passant, vous pouvez créer vos propres scripts pour rechercher des modules (voir ici).
Prenons un example plus concret en supposant que vous ayiez besoin de la librairie gtk2.0, on écrirait
alors dans notre CMakeLists.txt :
find_package(GTK2 REQUIRED)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 18/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
target_link_libraries : permet d'ajouter des librairies dans le chemin de compilation d'une cible (les
-lxxxx)
target_include_directories : permet d'ajouter des chemins vers des entêtes d'une cible (les -Ixxxx)
pkg_check_modules
La deuxième façon consiste à utiliser pkg-config. Pour pouvoir utiliser pkg-config, il faut l'inclure dans
CMake et mettre dans le CMakeLists et l'invoquer:
find_package(PkgConfig)
pkg_check_modules(GTK2 gtk+-2.0 REQUIRED)
Comme pour find_package, on a ensuite accès aux variables GTK2_INCLUDE_DIRS, GTK2_LIBRARIES plus
quelques autres, notamment GTK2_CFLAGS_OTHER. Vous pouvez regarder la doc de pkg_ckeck_modules
en ouvrant le fichier /usr/share/cmake-2.8/Modules/FindPkgConfig.cmake. Il reste maintenant à
ajouter ces dépendances à une cible. Supposons par exemple qu'on souhaite compiler le fichier toto.cpp
qui dépend de GTK2. Il faut indiquer à CMake comment :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 19/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
target_link_libraries : permet d'ajouter des librairies dans le chemin de compilation d'une cible (les
-lxxx)
target_include_directories : permet d'ajouter des chemins vers des entêtes d'une cible (les -Ixxxx)
target_compile_options : permet d'ajouter des "cflags" comme -std=c++11 à une cible
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 20/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Notez que le set_property ainsi écrit écrase la propriété. Si vous souhaitez ajouter un élément à la
propriété, vous devez ajouter APPEND_STRING aux arguments de set_property.
Un example
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 21/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Ex3
|----- CMakeLists.txt
|----- src
|---- CMakeLists.txt
|---- main.cpp
|----- build
Fichier Ex3/CMakeLists.txt
project(ex3)
add_subdirectory (src)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 22/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex3/src/CMakeLists.txt
Pour qu'un utilisateur puisse utiliser votre librairie facilement, en particulier en utilisant pkg-config, il
faut fournir et installer un fichier ".pc". On peut utiliser deux approches : la première consiste à écrire
le fichier pc depuis cmake, la seconde consiste à se définir un template et à le remplir depuis cmake.
Tout d'abord, parlons un peu de la structure d'un fichier pc (vous en trouverez de nombreux exemples
dans /usr/lib/pkgconfig ou /usr/lib/i386-linux-gnu/pkgconfig/ sur 32 bits) en regardant
"gtk+-2.0.pc":
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 23/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
prefix=/usr
exec_prefix=${prefix}
libdir=/usr/lib/i386-linux-gnu
includedir=${prefix}/include
target=x11
gtk_binary_version=2.10.0
gtk_host=i686-pc-linux-gnu
Name: GTK+
Description: GTK+ Graphical UI Library (${target} target)
Version: 2.24.23
Requires: gdk-${target}-2.0 atk cairo gdk-pixbuf-2.0 gio-2.0 pangoft2
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0
Au début du fichier, on trouve la définition de quelques variables, le contenu vraiment intéressant étant
la dernière partie, celle à laquelle on accède quand on invoque pkg-config en lui demandant par
exemple les libs ou les cflags. pkg-config va non seulement utiliser les libs et cflags qu'introduisent ce
fichier pc mais également les libs et cflags des dépendances (champ Requires).
Pour écrire un fichier depuis CMakeLists, il suffit d'invoquer la commande file avec la signature WRITE.
On peut faire apparaître dans la chaîne de caractères à écrire des variables de cmake, par exemple :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 24/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.pc
"
Name: ${CMAKE_PROJECT_NAME}
Description: C'est une super librairie qui utilise gtk2
Version: 0.0.1
Requires: gtk2
Libs: -L${CMAKE_INSTALL_PREFIX}/lib
Cflags: -I${CMAKE_INSTALL_PREIFX}/include
"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.pc
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
La deuxième façon de faire est de se définir un fichier dans lequel il reste des variables à substituer.
Pourquoi ? et bien parce que le contenu du fichier pkg-config va dépendre, par exemple, du préfixe
d'installation choisi par l'utilisateur. Cette fois ci on va se définir un fichier ex3.pc.in, qu'on placerait à la
racine du projet, avec des variables CMake entourées par des "@":
Fichier Ex3/ex3.pc.in
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 25/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Name: @CMAKE_PROJECT_NAME@
Description: C'est une super librairie qui utilise gtk2
Version: 0.0.1
Requires: gtk2
Libs: -L@CMAKE_INSTALL_PREFIX@/lib
Cflags: -I@CMAKE_INSTALL_PREIFX@/include
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/ex3.pc.in
${CMAKE_CURRENT_BINARY_DIR}/ex3.pc @ONLY)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/ex3.pc
DESTINATION lib/pkgconfig/)
Ex5 : Et la documentation ?
Pour générer la documentation, nous allons utiliser Doxygen. On va partir sur un projet dont la
hiérarchie est la suivante (on reprends ex2) :
Ex5
|----- CMakeLists.txt
|----- src
|---- CMakeLists.txt
|---- fonct.cpp
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 26/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
|---- fonct.hpp
|---- monct.cpp
|---- monct.hpp
|----- doc
|---- CMakeLists.txt
|---- Doxyfile.in
|----- examples
|---- CMakeLists.txt
|---- ex1.cpp
|----- build
doxygen -g Doxyfile.in
Au sein du fichier Doxyfile.in, il faut modifier quelques variables pour que ce fichier soit configuré par
cmake :
PROJECT_NAME = ${CMAKE_PROJECT_NAME}
OUTPUT_DIRECTORY = ${CMAKE_BINARY_DIR}/doc/
INPUT = ${CMAKE_SOURCE_DIR}/src
EXAMPLE_PATH = ${CMAKE_SOURCE_DIR}/examples
EXTRACT_ALL = YES
Il nous reste maintenant à indiquer à cmake de générer la documentation. Première chose, on ajoute le
sous-répertoire doc au CMakeLists.txt principal :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 27/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex5/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Release)
project(ex5)
add_subdirectory(src)
add_subdirectory(examples)
add_subdirectory(doc)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 28/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex5/doc/CMakeLists.txt
find_package(Doxygen)
if(NOT DOXYGEN_FOUND)
message("Doxygen not found, I will not generate/install the documentation")
else()
configure_file(Doxyfile.in Doxyfile)
set(DOXYGEN_INPUT ${CMAKE_BINARY_DIR}/doc/Doxyfile)
set(DOXYGEN_OUTPUT ${APIDOC_DIR}/html/index.html)
add_custom_target(doc ALL
COMMAND ${CMAKE_COMMAND} -E echo_append "Building API Documentation..."
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_INPUT} > /dev/null
COMMAND ${CMAKE_COMMAND} -E echo "Done."
)
install(DIRECTORY ${CMAKE_BINARY_DIR}/doc/html
DESTINATION share/doc/${CMAKE_PROJECT_NAME})
endif()
la première ligne fait appel à find_package pour trouver Doxygen. Incidemment, cette commande
définit la variable DOXYGEN_FOUND qui permet de générer ou non la documentation si
l'exécutable est présent
configure_file remplace les variables cmake dans le fichier Doxyfile.in; Par défaut un chemin relatif
pour le fichier d'entrée (Doxyfile.in) est à comprendre relativement au répertoire source courant
(CMAKE_CURRENT_SOURCE_DIR) et le chemin relatif du fichier destination (Doxyfile) est à
comprendre relativement au répertoire binaire courant (CMAKE_CURRENT_BINARY_DIR)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 29/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
enfin, après quelques définitions de variables pour rendre plus lisible le code, on se définit la cible
doc à l'aide de add_custom_target. On liste l'ensemble des commandes à exécuter lors de l'appel de
make doc. Le mot clé ALL indique que la cible doc sera construite sans avoir à l'expliciter, i.e. quand
on tape make tout court.
Ex5b : Elle est moche la doc, je veux un example qui en jette un peu
plus.
Work in progress .... Dans cette partie, vous n'avez rien de particulier à faire à part compiler le projet.
J'espère vous convaincre qu'on peut faire une jolie documentation avec Doxygen. On va partir d'un code
C++ que vous avez vu en cours et qui nous donnera une bonne base pour générer une belle
documentation. J'ai un tout petit peu modifié le code pour faire apparaître des balises Doxygen.
Cmake permet d'intégrer des tests unitaires à votre projet. Les tests unitaires sont des tests qui
s'assurent de la stabilité de certaines fonctionnalités fournies par votre projet. Il existe plusieurs
frameworks permettant de définir des tests unitaires, on va ici utiliser celui de Boost avec des exemples
extrêmement simples, le but étant de montrer l'intégration dans cmake. On va partir de l'arborescence
suivante :
Ex6
|----- CMakeLists.txt
|----- src
|---- CMakeLists.txt
|---- fonct.cpp
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 30/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
|---- fonct.hpp
|---- monct.cpp
|---- monct.hpp
|----- doc
|---- CMakeLists.txt
|---- Doxyfile.in
|----- tests
|---- CMakeLists.txt
|---- test_lib.cpp
|----- examples
|---- CMakeLists.txt
|---- ex1.cpp
|----- build
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 31/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex6/tests/test_lib.cpp
#define BOOST_TEST_MODULE TotoTests
#include "fonct.hpp"
#include "monct.hpp"
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(TestFonct)
{
BOOST_CHECK_EQUAL(6, f(2));
}
BOOST_AUTO_TEST_CASE(TestMonct)
{
BOOST_CHECK_EQUAL(2, m(4));
}
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 32/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex6/tests/CMakeLists.txt
include_directories (${CMAKE_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS}
)
add_definitions (-DBOOST_TEST_DYN_LINK)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 33/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Fichier Ex6/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Release)
project(ex6)
add_subdirectory(src)
add_subdirectory(examples)
add_subdirectory(doc)
add_subdirectory(tests)
enable_testing ()
add_test (NAME MyTest
COMMAND test_mylib
)
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 34/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Start 1: MyTest
1/1 Test #1: MyTest ........................... Passed 0.00 sec
Modifiez votre code ou vos tests unitaires pour faire échouer le test unitaire. Vous remarquerez que
make test n'est pas très verbeux et que si il y a un échec, on ne sait pas quel test a échoué. Pour que la
sortie soit verbeuse, il suffit d'exécuter CTEST_OUTPUT_ON_FAILURE=TRUE make test.
La dernière commande que j'aimerais introduire est une commande permettant de facilement générer
une archive .tar.gz en créant la cible make dist. Pour cela, il suffit d'ajouter au CMakeLists de la racine
un appel à add_custom_target :
SET(DIST_DIR "${CMAKE_PROJECT_NAME}")
ADD_CUSTOM_TARGET(dist
COMMAND rm -rf ${DIST_DIR}
COMMAND mkdir ${DIST_DIR}
COMMAND cp -r ${CMAKE_SOURCE_DIR}/* ${DIST_DIR} || true
COMMAND rm -rf ${DIST_DIR}/build
COMMAND mkdir ${DIST_DIR}/build
COMMAND tar --exclude="*~" --exclude="._*" -zcvf ${DIST_DIR}.tar.gz ${DIST_DIR}
COMMAND rm -rf ${DIST_DIR}
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 35/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
La commande est définie pour faire une copie des sources dans le répertoire
build/${CMAKE_PROJECT_NAME}. On s'assure que le répertoire build existe et soit vide puis on
invoque tar pour créer l'archive.
Pour finir, je vous propose un ensemble de fichiers C++ en vrac et je vous demande de construire un
package cmake tout ficelé. L'archive ExEnsemble.tar.gz contient:
J'aimerais que le package compile/installe la librairie, installe les fichiers d'entête, génère un fichier
pkg-config et l'installe, compile les exemples, la documentation. A vous de jouer !
Une solution.
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 36/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
Si votre machine possède plusieurs coeurs, vous pouvez en profiter avantageusement à la phase de
compilation/linkage en appelant make -jn en remplaçant n par le nombre de processus à lancer; e.g.
sur une machine à 4 coeurs :
Il peut être nécessaire d'indiquer des priorités de compilation entre les cibles, ce que cmake appelle des
dépendances. Si la cible target1 (issue d'un add_custom_target, add_executable, add_library) doit être
compilée avec la cible target2, on pourra l'indiquer à cmake en invoquant add_dependencies:
add_dependencies(target2 target1)
Nous n'avons pas eu à l'utiliser dans les exemples ci-dessous parce que target_link_libraries ajoute de
lui même une dépendance entre l'exécutable linké et la librairie compilée dans notre projet.
Je l'ai évoqué un peu plus haut, quand vous compilez votre code, n'hésitez pas à lancer
Pour débugger du cmake, on peut simplement afficher un message pendant que cmake génère les
Makefiles en invoquant la commande message
On peut également demander à cmake d'afficher les variables qu'il a défini à l'aide de la commande
get_cmake_property :
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 37/38
12/03/2023, 01:04 Tutoriel CMAKE, CentraleSupélec
get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
message(STATUS "${_variableName}=${${_variableName}}")
endforeach()
Sachez qu'il est également possible de construire des paquets deb, rpm, osx, windows .. installables
grâce à cpack.
sirien.metz.supelec.fr/depot/SIR/TutorielCMake/index.html 38/38