Ceci est une ancienne révision du document !
Table des matières
cmake
Compilation
git clone https://gitlab.kitware.com/cmake/cmake cd cmake cmake -B build cmake --build build cmake --install build
La méthode de bootstrap
n'est nécessaire que si on ne possède pas un cmake précompilé.
Build CMake from dev sources Archive du 01/03/2021 le 09/01/2023
Utilisation basique
- Générer et lancer la compilation
CXXFLAGS="..." cmake -S . -B build -DCMAKE_BUILD_TYPE="Release" cmake --build build/ --target all --parallel --config "Release"
La deuxième instruction n'a pas besoin d'autres arguments.
Ne pas utiliser cmake -DCMAKE_CXX_FLAGS="..."
mais plutôt CXXFLAGS="..." cmake
En compilant pour Visual Studio
, -DCMAKE_CXX_FLAGS
écrase la valeur qu'aurait dû générer cmake
(/DWIN32 /D_WINDOWS /W3 /GR /EHsc
par défaut).
En utilisant CXXFLAGS
, les flags sont ajoutés au début (... /DWIN32 /D_WINDOWS /W3 /GR /EHsc
).
Passing compiler options cmake Archive du 31/05/2017 le 05/10/2022
- Différences entre les générateurs
En fonction des générateurs (Unix Makefiles
pour Linux et Visual Studio 17 2022
pour Windows), il existe plusieurs types de build (CMAKE_BUILD_TYPE
) :
- Debug
- Release
- RelWithDebInfo,
- MinSizeRel
Debug
est évidemment Debug
et les 3 autres sont dans la catégorie Release
.
CMAKE_BUILD_TYPE
doit être passé dans le premier appel au cmake -S . -B build
. C'est indispensable pour Unix Makefiles
car le générateur ne supporte qu'un seul type de build à la fois. C'est facultatif pour Visual Studio XX YYYY
car il supporte plusieurs configurations à la fois. Cependant, il est quand même conseillé de l'utiliser à chaque fois pour la cohérence.
--config
doit être passé pour chaque cmake --build build
pour Visual Studio XX YYYY
mais est facultatif pour Unix Makefiles
. Il est aussi conseillé de toujours le spécifier.
Cross compilation pour Android
Il faut définir 3 variables d'environnement et passer quelques variables en lignes de commandes.
Pour Windows, il faut forcer l'utilisation de Ninja
car Visual Studio
n'est pas supporté.
export ANDROID_HOME="$HOME/AppData/Local/Android/Sdk" export ANDROID_SDK_PATH="$HOME/AppData/Local/Android/Sdk" export ANDROID_NDK_PATH="$HOME/AppData/Local/Android/Sdk/ndk/21.4.7075529" cmake -S dossier_source -B dossier_build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CONFIGURATION_TYPES=Release -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=30 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK="$HOME/AppData/Local/Android/Sdk/ndk/21.4.7075529" -DCMAKE_ANDROID_STL_TYPE:STRING="c++_static" -DCMAKE_INSTALL_PREFIX="install_prefix_path" -DBUILD_SHARED_LIBS:BOOL=OFF
La version de CMAKE_SYSTEM_VERSION
doit correspondre à minSdkVersion du fichier build.gradle
.
CMakeLists.txt
Cas courants
Librairie header-only
Follow guide:
Exemple sans find_package
: Creating a header only library with cmake Archive du 2017 le 11/07/2021
Exemple avec find_package
: Cmake line by line - creating a header-only library Archive du 24/06/2019 le 11/07/2021
Personnaliser la compilation
Il faut mettre les options après la déclaration de l'exécutable à compiler (add_executable
).
add_executable(boostexecutor executor.cpp main.cpp) target_include_directories(boostexecutor PRIVATE ${Boost_INCLUDE_DIRS}) target_compile_options(boostexecutor PRIVATE -O0) target_link_libraries(boostexecutor Threads::Threads)
Activation de l'optimisation global du lieur
Le LTCG (Link Time Code Generation) est identique à l'option lto (Link Time Optimization) de gcc.
Dans un projet Visual Studio, l'option est automatiquement mise pour le mode Release. Mais pas avec CMake.
Pour l'activer manuellement, il faut ajouter /GL
au compilateur et /LTCG
au lieur. Cela se fait via :
include(CheckIPOSupported) # définition du projet check_ipo_supported(RESULT result) if(result) set_property(TARGET hello PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) endif()
Cela active -lto
pour GCC et /LTCG:INCREMENTAL
pour Visual Studio.
Link Time Code Generation (LTCG) by default, for Release configurations of Visual Studio projects Archive du 05/02/2018 le 29/11/2019
Utiliser clang
Ajouter à cmake
:
-DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_AR=/usr/bin/llvm-ar -DCMAKE_RANLIB=/usr/bin/llvm-ranlib
FetchContent
- Il n'est pas possible d'ajout d'arguments de type
-Dxxx=ON
dans l'invocation d'uncmake
parFetchContent_Declare
.
The
<contentOptions>
can be any of the download, update or patch options that theExternalProject_Add()
command understands. The configure, build, install and test steps are explicitly disabled and therefore options related to them will be ignoredFetchContent Archive du v3.22 le 29/11/2021
Comme les paramètres CMAKE_ARGS
sont ignorés, il faut utiliser set
:
include(FetchContent) set(XXX YYY CACHE INTERNAL "") # Forces the value FetchContent_Declare(...
Passing CMake Arguments to FetchContent Archive du 23/03/2019 le 29/11/2021
Fonctions diverses
- Forcer
-fPIC
:set_property(TARGET 2lgcpoco PROPERTY POSITION_INDEPENDENT_CODE ON)
- Générer le fichier
compile_commands.json
:set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
Interaction avec la ligne de commande
- Passer une liste de paramètres qui sera réutilisé comme une liste.
Le séparateur est le ;
.
Bash:
cmake ... -DLISTE="-DVAR1=champ1;-DVAR2=champ2"
CMakeLists.txt, sans les guillemets.
${LISTE}
Cas spécifiques
Exécuter une action qui n'est rattachée à aucun programme/target
Il suffit de passer par une target
intermédiaire.
# On crée une target qui sera ajoutée à la commande make par défaut. add_custom_target(clang_fmt ALL) # On définir une commande à exécuter. add_custom_command(TARGET clang_fmt COMMAND xxxxxx)
Exécuter uniquement le préprocesseur
Il faut créer une target compilable en l'excluant de all
. Cela va créer des target intermédiaire, notamment xxx.cpp.i
. Il suffit alors de l'exécuter explicitement.
add_library(file_obj OBJECT EXCLUDE_FROM_ALL file.cpp) add_custom_target(file ALL COMMAND make file.cpp.i)
Generating preprocessed sources in CMake projects Archive du 21/11/2018 le 21/07/2020
Dépendances dans un sous-dossier
Il faut impérativement passer par une target
intermédiaire.
En un morceau :
add_custom_target (a_txt DEPENDS a.txt) add_custom_command (OUTPUT a.txt COMMAND cat {b,b}.txt > a.txt DEPENDS b.txt) add_custom_command (OUTPUT b.txt COMMAND paste {c,c}.txt > b.txt DEPENDS c.txt)
En deux morceaux :
add_subdirectory (sub) add_custom_target (a_txt DEPENDS a.txt) add_custom_command (OUTPUT a.txt COMMAND cat sub/{b,b}.txt > a.txt DEPENDS b_txt sub/b.txt)
add_custom_target (b_txt DEPENDS b.txt) add_custom_command (OUTPUT b.txt COMMAND paste {c,c}.txt > b.txt DEPENDS c.txt)
CMake dependencies on subdirectories Archive du 16/03/2012 le 29/11/2019
Déprécié
PUBLIC_HEADER
Utiliser à la place: FILE_SET HEADER
.
Ne pas utiliser car à l'installation, les fichiers entêtes sont installés sans conserver l'arborescence et le dossier de destination n'est pas respecté lors d'un :
install( TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-${version})
Tests
Activer/Désactiver les tests
On commence par toujours inclure :
include(CTest)
Par défaut, BUILD_TESTING
est activé. Pour le désactiver, il faut ajouter -DBUILD_TESTING=OFF
lors de l'invocation de cmake
.
Puis, on peut mettre sous condition toutes les commandes concernant les tests :
if(BUILD_TESTING) add_test(...) ... endif(BUILD_TESTING)
Librairie dynamique, tests et Windows
Souvent le dossier de compilation des tests n'est pas le même que celui des DLLs.
Il y a donc 2 solutions :
- Copier les DLLs dans le dossier des tests (recommandé)
A utiliser si le programme possède des DLL externes.
foreach(TESTI test_a_executer) add_test(NAME ${TESTI} COMMAND $<TARGET_FILE:${TESTI}>) if($<TARGET_RUNTIME_DLLS:${TESTI}>) add_custom_command( TARGET ${TESTI} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${TESTI}> $<TARGET_FILE_DIR:${TESTI}> COMMAND_EXPAND_LISTS) endif() endforeach()
- Compiler tous les binaires dans le même dossier
A utiliser si le programme possède uniquement des DLL internes gérées par le CMakeList.xtx.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") add_test(NAME test_a_executer COMMAND $<TARGET_FILE:test_a_executer>)
CMake cannot find test if CMAKE_RUNTIME_OUTPUT_DIRECTORY is changed Archive du 28/01/2014 le 27/03/2023
RPATH
Eviter cette solution. Préférer celle du paragraphe Librairie dynamique, tests et Windows.
RPATH n'est applicable que sous Linux. Cette notion d'écrire les chemins vers les DLL dans l'exécutable n'existe pas sous Windows.
Les tests ne sont généralement pas installés et il faut que l'exécutable trouve le chemin vers les librairies.
Méthode officielle Archive du 04/03/2020 le 26/08/2022
Après avoir mis à jour CMAKE_INSTALL_RPATH
(set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};${VTK_RUNTIME_DIRS}")
) ou l'attribut INSTALL_RPATH
via set_target_properties
, l'exécutable devrait trouver les librairies tout seul.
Si non, exécuter readelf -d executable
et vérifier que le champ RPATH
ou RUNPATH
est correctement rempli.
0x000000000000000f (RUNPATH) Library rpath: [path1:path2:path3]
Si les valeurs sont correctement remplies sous l'attribut RUNPATH
, il faut forcer l'utilisation de RPATH
. Ajouter au linker l'option -Wl,--disable-new-dtags
.
add_link_options("-Wl,--disable-new-dtags")
How to set RPATH and RUNPATH with GCC/LD? Archive du 25/08/2018 le 26/08/2022
Debug
- Afficher toutes les variables
CMake
Le fichier CMakeCache.txt ne stocke pas toutes les variables provenant des dépendances.
Il est possible de les afficher dans le terminal en ajoutant dans un fichier CMakeLists.txt
.
get_cmake_property(_variableNames VARIABLES) list (SORT _variableNames) foreach (_variableName ${_variableNames}) message(STATUS "${_variableName}=${${_variableName}}") endforeach()
CMake: Print out all accessible variables in a script Archive du 15/02/2012 le 18/08/2022
- Afficher toutes les étapes, line par line, d'un run
CMake
Ajouter l'option --trace-expand
.
- Activer l'affichage des lignes de compilation
Ajouter dans le CMakeLists.txt
: set(CMAKE_VERBOSE_MAKEFILE ON)
. Ou lancer VERBOSE=1 cmake …