cmake est un générateur de fichier de configuration qui permet d'automatiser la compilation et l'édition de lien d'un ensemble de fichiers source de manière à obtenir un exécutable.
On peut, entre autre, générer un makefile, un fichier projet Eclipse ou KDE.
Sous Ubuntu 14.04, installer les packages suivants : cmake et cmake-qt-gui qui est une interface graphique mais qui n'est pas très intuitive.
Dans la partie qui suit on s'intéresse à la génération d'un makefile.
On désire à partir d'un fichier situé dans le répertoire courant main.cpp générer l'exécutable main.exe.
La première étape consiste à écrire un fichier CMakeLists.txt qui décrit les étapes à réaliser pour aller des sources à l'exécutable.
Pour obtenir un makefile, exécuter la commande suivante :
\$ cmake -G "Unix Makefiles"
-- The C compiler identification is Clang 3.6.0
-- The CXX compiler identification is Clang 3.6.0
-- Check for working C compiler: /usr/bin/clang-3.6
-- Check for working C compiler: /usr/bin/clang-3.6 -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++-3.6
-- Check for working CXX compiler: /usr/bin/clang++-3.6 -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: [...]/cmake1
Durant l'exécution de la commande, plusieurs fichiers sont générés :
Pour obtenir l'exécutable, il suffit de taper :
make
Scanning dependencies of target main.exe
[100%] Building CXX object CMakeFiles/main.exe.dir/main.cpp.o
Linking CXX executable main.exe
[100%] Built target main.exe
On rencontre cependant deux problèmes:
Pour répondre au premier problème, il suffit d'ajouter les lignes suivantes au fichier CMakeLists.txt :
set(CMAKE_C_COMPILER "/usr/bin/gcc")
set(CMAKE_CXX_COMPILER "/usr/bin/g++")
Il faut relancer cmake, mais parfois cela n'est pas suffisant, il faut supprimer le fichier CMakeCache.txt et le sous-répertoire CMakeFiles :
\$ rm -rf CMakeFiles CMakeCache.txt
\$ cmake -G "Unix Makefiles"
-- The C compiler identification is GNU 4.9.2
-- The CXX compiler identification is GNU 4.9.2
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/g++
-- Check for working CXX compiler: /usr/bin/g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: [...]/cmake1_1
Pour répondre au second problème, il suffit de lancer make avec l'option VERBOSE=1 :
make VERBOSE=1
...
[100%] Building CXX object CMakeFiles/main.exe.dir/main.cpp.o
/usr/bin/g++ -o CMakeFiles/main.exe.dir/main.cpp.o -c /home/richer/dev/cpp/cmake1_1/main.cpp
Linking CXX executable main.exe
/usr/bin/cmake -E cmake_link_script CMakeFiles/main.exe.dir/link.txt --verbose=1
/usr/bin/g++ CMakeFiles/main.exe.dir/main.cpp.o -o main.exe -rdynamic
...
On s'aperçoit qu'aucune option de compilation (optimisation ou débugage) n'est utilisée.
Il faut choisir un "type de build" (build type en anglais) que l'on peut traduire en français par le mot distribution, on modifie CMakeLists.txt en conséquence :
set(CMAKE_BUILD_TYPE Release)
On a le choix entre :
Par exemple pour définir sa propre distribution :
project(MyProject)
set(CMAKE_BUILD_TYPE ma_distribution)
set(CMAKE_CXX_FLAGS_MA_DISTRIBUTION "-O3 -ftree-vectorize -msse2")
set(CMAKE_C_FLAGS_MA_DISTRIBUTION "-O3 -ftree-vectorize -msse2")
Attention les trois dernières instructions doivent être placées après la directive project, sinon elles ne seront pas prises en compte.
On peut également ajouter des flags à une distribution existante :
project(MyProject)
set(CMAKE_BUILD_TYPE release)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -ftree-vectorize -msse2 -std=c++11")
On compilera alors avec -O3 -DNDEBUG -Wall -ftree-vectorize -msse2 -std=c++11.
Dans cet exemple on place les fichiers sources dans le sous-répertoire src et l'exécutable final dans le répertoire bin.
Attention, l'exécutable main.exe sera situé dans le sous-répertoire bin/Release car on a utilisé la directive set(CMAKE_BUILD_TYPE release).
On dispose de l'arborescence suivante pour les sources :
src
├── file1.cpp
├── file1.h
├── main.cpp
└── maths
├── statistics.cpp
└── statistics.h
On veut faire en sorte de créer une librairie avec les fichiers du sous-répertoire maths.
On ajoute les 4 lignes suivantes :
Au final on obtient une lirairie dans le répertoire principal du projet (libmaths.so) qui est liée à l'exécutable main.exe.