Outils pour utilisateurs

Outils du site


prog:cmake

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
prog:cmake [2023/04/21 14:15] – Ajout de "Fichiers chargés par les tests" rootprog:cmake [2024/08/30 15:13] (Version actuelle) – Ajout des commandes externes aux targets root
Ligne 2: Ligne 2:
  
 ====Compilation==== ====Compilation====
 +
 +Pré-requis sous Linux
 +
 +''sudo apt-get install libssl-dev''.
 +
 +Compilation
  
 <code bash> <code bash>
Ligne 7: Ligne 13:
 cd cmake cd cmake
 cmake -B build cmake -B build
-cmake --build build +cmake --build build --parallel 16 
-cmake --install build+sudo cmake --install build
 </code> </code>
  
Ligne 20: Ligne 26:
  
 <code bash> <code bash>
 +# Etape de configuration.
 CXXFLAGS="..." cmake -S . -B build -DCMAKE_BUILD_TYPE="Release" CXXFLAGS="..." cmake -S . -B build -DCMAKE_BUILD_TYPE="Release"
 +# Etape de compilation.
 cmake --build build/ --target all --parallel --config "Release" cmake --build build/ --target all --parallel --config "Release"
 </code> </code>
Ligne 31: Ligne 39:
 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 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'').+En utilisant la variable d'environnement ''CXXFLAGS'', les flags sont ajoutés au début (''%%...%% /DWIN32 /D_WINDOWS /W3 /GR /EHsc'').
  
 [[https://stackoverflow.com/questions/44284275/passing-compiler-options-cmake|Passing compiler options cmake]] {{ :prog:cmake:passing_compiler_options_cmake_-_stack_overflow_05_10_2022_11_12_25_.html |Archive du 31/05/2017 le 05/10/2022}} [[https://stackoverflow.com/questions/44284275/passing-compiler-options-cmake|Passing compiler options cmake]] {{ :prog:cmake:passing_compiler_options_cmake_-_stack_overflow_05_10_2022_11_12_25_.html |Archive du 31/05/2017 le 05/10/2022}}
 </WRAP> </WRAP>
  
 +  * Effacer le cache et regénérer les CMakeLists.txt
  
-  * Différences entre les générateurs+Il faut effacer le fichier ''CMakeCache.txt'' et le dossier ''CMakeFiles'' dans le dossier de compilation. Cela permet de conserver les binaires / fichiers objets déjà compilés.
  
-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'') :+  * Différences entre les générateurs
  
-  - Debug +Certaines générateurs (''Unix Makefiles'' et ''Ninja'') ne supportent qu'un seul type de compilation à la fois. Il faut définir le type de compilation avec ''CMAKE_BUILD_TYPE''.
-  - Release +
-  - RelWithDebInfo, +
-  - MinSizeRel+
  
-''Debug'' est évidemment ''Debug'' et les 3 autres sont dans la catégorie ''Release''.+D'autres générateurs (''Visual Studio''''Xcode''''Ninja Multi-Config'') acceptent plusieurs types de compilation. Il faut passer par ''CMAKE_CONFIGURATION_TYPES'' qui vaut par défaut ''Debug;Release;MinSizeRel;RelWithDebInfo''.
  
-''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 foisC'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.+''CMAKE_BUILD_TYPE'' est indispensable lors de la génération des CMakeLists.txt pour les générateurs mono-build.
  
-''%%--%%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.+''%%--%%config'' est indispensable lors de la compilation pour les générateurs multi-build.
  
 ====Cross compilation pour Android==== ====Cross compilation pour Android====
Ligne 65: Ligne 71:
 </code> </code>
  
-La version de ''CMAKE_SYSTEM_VERSION'' doit correspondre à minSdkVersion du fichier ''build.gradle''.+La version de ''CMAKE_SYSTEM_VERSION'' doit correspondre à ''minSdkVersion'' du fichier ''build.gradle''.
  
 [[https://developer.android.com/ndk/guides/cmake|CMake]] {{ :prog:cmake:cmake_android_ndk_android_developers_26_09_2022_13_53_29_.html |Archive du 25/04/2022 le 26/09/2022}} [[https://developer.android.com/ndk/guides/cmake|CMake]] {{ :prog:cmake:cmake_android_ndk_android_developers_26_09_2022_13_53_29_.html |Archive du 25/04/2022 le 26/09/2022}}
 +
 =====CMakeLists.txt===== =====CMakeLists.txt=====
 ====Cas courants==== ====Cas courants====
 +
 +Voir une version à jour avec tous les commentaires dans [[https://github.com/bansan85/cmake-library/tree/main/library/lib|cmake-library]].
 +
 +===add_library===
 +
 +  * Depuis le code source
 +
 +<code cmake>
 +add_library(Librairie sources.cpp sources.hpp CMakeLists.txt)
 +add_library(NameSpace::Librairie ALIAS Librairie)
 +set(Librairie_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sources.cpp
 +                  ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
 +set(Librairie_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/sources.h)
 +target_sources(
 +  Librairie
 +  PRIVATE ${Librairie_SRC}
 +  PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ FILES ${Librairie_HEADER})
 +</code>
 +
 +Le fichier ''CMakeLists.txt'' sert uniquement à ajouter le fichier dans l'explorateur de Visual Studio.
 +
 +<code cmake>
 +target_link_libraries(Librairie PUBLIC Librairie2)
 +</code>
 +
 +Ici, ''Librairie'' dépend de ''Librairie2''.
 +
 +''PUBLIC'' : ''Librairie2'' est nécessaire pour compiler ''Librairie'' et est également nécessaire pour qu'un exécutable puisse se lier à ''Librairie''.
 +
 +''PRIVATE'' : ''Librairie2'' est nécessaire pour compiler ''Librairie'' mais n'est pas nécessaire pour qu'un exécutable puisse se lier à ''Librairie''.
 +
 +''INTERFACE'' : ''Librairie2'' n'est pas nécessaire pour compiler ''Librairie'' mais est nécessaire pour qu'un exécutable puisse se lier à ''Librairie''. Cela est surtout nécessaire pour faire une librairie header-only.
 +
 +  * Depuis une librairie dynamique précompilée
 +
 +<code cmake>
 +add_library(Librairie SHARED IMPORTED GLOBAL)
 +set_target_properties(
 +  Librairie
 +  PROPERTIES
 +    IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
 +    IMPORTED_LOCATION_DEBUG librairie-d.dll
 +    IMPORTED_LOCATION_RELEASE librairie.dll
 +    IMPORTED_IMPLIB_DEBUG librairie-d.lib
 +    IMPORTED_IMPLIB_RELEASE librairie.lib
 +)
 +</code>
 +
 +''SHARED'' ou ''STATIC''.
 +
 +''GLOBAL'' : ''add_library'' qui compile propage aux parents. ''add_library'' qui importe ne propage pas aux parents.
 +
 +''IMPORTED_LOCATION'' : emplacement de la librairie (''.dll'' / ''.so'' si ''SHARED'', ''.lib'' / ''.a'' si ''STATIC''). Attention, la librairie dynamique ne doit pas avoir été renommée manuellement afin que le nom de fichier corresponde à son ''SONAME''.
 +
 +''IMPORTED_IMPLIB'' : uniquement pour Windows et des librairies ''SHARED''. Le fichier ''.dll'' ne contient pas les symboles. Il lui faut donc le ''.lib'' associé. Attention, le fichier ''.lib'' associé au ''.dll'' (''SHARED'') n'est pas le même que le ''.lib'' compilé en ''STATIC''.
 +
 ===Librairie header-only=== ===Librairie header-only===
  
-Follow guide:+Suivre les guides :
  
 Exemple sans ''find_package'' : [[http://mariobadr.com/creating-a-header-only-library-with-cmake.html|Creating a header only library with cmake]] {{ :prog:cmake:mario_badr_creating_a_header-only_library_with_cmake_2021-07-11_08_48_29_.html |Archive du 2017 le 11/07/2021}} Exemple sans ''find_package'' : [[http://mariobadr.com/creating-a-header-only-library-with-cmake.html|Creating a header only library with cmake]] {{ :prog:cmake:mario_badr_creating_a_header-only_library_with_cmake_2021-07-11_08_48_29_.html |Archive du 2017 le 11/07/2021}}
Ligne 90: Ligne 153:
  
 ===Activation de l'optimisation global du lieur=== ===Activation de l'optimisation global du lieur===
 +
 Le LTCG (Link Time Code Generation) est identique à l'option lto (Link Time Optimization) de gcc. Le LTCG (Link Time Code Generation) est identique à l'option lto (Link Time Optimization) de gcc.
  
Ligne 117: Ligne 181:
 Ajouter à ''cmake'': 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''+<code bash> 
 +-DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_AR=/usr/bin/llvm-ar -DCMAKE_AS=/usr/bin/llvm-as -DCMAKE_RANLIB=/usr/bin/llvm-ranlib -DCMAKE_LINKER_TYPE=LLD 
 +</code> 
 + 
 +  * ''DWARF error: invalid or unhandled FORM value: 0x23'' 
 + 
 +Ne pas spécifier ''CMAKE_LINKER_TYPE'' va entrainer cette erreur. [[https://github.com/llvm/llvm-project/issues/56994| C++17 leads to linker error with ld due to some strange debug info?]] {{ :prog:cmake:c_17_leads_to_linker_error_with_ld_due_to_some_strange_debug_info_issue_56994_llvm_llvm-project_5_31_2024_12_40_25_pm_.html |Archive du 08/08/2022 le 31/05/2024}} 
 + 
 +Sinon, il est aussi possible de mettre l'option de compilation ''-gdwarf-4'' pour les flags ''C'' et ''CXX''.
  
 ===FetchContent=== ===FetchContent===
Ligne 142: Ligne 214:
 ====Interaction avec la ligne de commande==== ====Interaction avec la ligne de commande====
  
-  * Passer une liste de paramètres qui sera réutilisé comme une liste.+===Options=== 
 + 
 +Les options sont les variables qui peuvent couramment être modifiées par l'utilisation mais qui doivent avoir une valeur par défaut. 
 + 
 +Les options sont des variables ''CACHE'' et ne peuvent donc être écrasés dans un fichier CMakLists.txt que par l'utilisation de ''CACHE %%...%% FORCE''
 + 
 +Deux déclarations équivalentes d'une variable ''CACHE''
 + 
 +<code cmake> 
 +option(BUILD_STATIC "Build static libraries" ON) 
 +set(BUILD_STATIC OFF CACHE BOOL "Build static libraries"
 +</code> 
 + 
 +Il est possible de modifier une variable ''CACHE'' en utilisant ''set'' avec l'option ''CACHE''
 + 
 +<code cmake> 
 +option(BUILD_STATIC "Build static libraries" ON) 
 +set(BUILD_STATIC OFF CACHE BOOL "Build static libraries" FORCE) 
 +</code> 
 + 
 +Enfin la valeur finale d'une variable ''CACHE'' est celle de l'utilisateur s'il la définit. 
 + 
 +<code cmake> 
 +cmake . -DBUILD_STATIC:BOOL=OFF 
 +</code> 
 + 
 +===Passer une liste de paramètres qui sera réutilisé comme une liste===
  
 Le séparateur est le '';''. Le séparateur est le '';''.
Ligne 158: Ligne 256:
 </code> </code>
  
-====Cas spécifiques====+====Environnement de compilation et de sortie====
  
-===Exécuter une action qui n'est rattachée à aucun programme/target===+===Environnement de sortie===
  
-Il suffit de passer par une ''target'' intermédiaire.+<code cmake> 
 +if(WIN32) 
 +  set(OS "Windows"
 +elseif(UNIX AND NOT APPLE) 
 +  set(OS "Linux/Unix"
 +elseif(APPLE) 
 +  set(OS "macOS"
 +else() 
 +  set(OS "Unknown"
 +endif() 
 + 
 +if(CMAKE_SIZEOF_VOID_P EQUAL 8) 
 +  set(ARCHITECTURE "64-bit"
 +elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 
 +  set(ARCHITECTURE "32-bit"
 +else() 
 +  set(ARCHITECTURE "Unknown"
 +endif() 
 +</code> 
 + 
 +====Exécution d'une commande==== 
 + 
 +===En passant par une nouvelle target===
  
 <code cmake> <code cmake>
-# On crée une target qui sera ajoutée à la commande make par défaut. +add_custom_target(clang_fmt ALL COMMAND xxxxxx)
-add_custom_target(clang_fmt ALL+
-# On définir une commande à exécuter. +
-add_custom_command(TARGET clang_fmt COMMAND xxxxxx)+
 </code> </code>
  
-===Exécuter uniquement le préprocesseur===+===Associé une commande à une target existante===
  
-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.+  * En passant par une target intermédiaire
  
 <code cmake> <code cmake>
-add_library(file_obj OBJECT EXCLUDE_FROM_ALL file.cpp) +add_custom_target(clang_fmt_dep COMMAND ...) 
-add_custom_target(file ALL COMMAND make file.cpp.i)+ 
 +add_dependencies(clang_fmt clang_fmt_dep)
 </code> </code>
  
-[[http://anadoxin.org/blog/generating-preprocessed-sources-in-cmake-projects.html|Generating preprocessed sources in CMake projects]{{ :prog:cmake:generating_preprocessed_sources_in_cmake_projects_-_antek_s_tech_blog_2020-07-21_18_01_14_.html |Archive du 21/11/2018 le 21/07/2020}}+  * Sans passer par une target intermédiaire 
 + 
 +<code cmake> 
 +add_custom_command(TARGET clang_fmt PRE_BUILD COMMAND ...) 
 +</code> 
 + 
 +  * En passant par un fichier qui sera généré 
 + 
 +<code cmake> 
 +add_custom_command(OUTPUT file COMMAND ...) 
 + 
 +add_dependencies(clang_fmt file) 
 +</code> 
 + 
 +===Spécificité au générateur Visual Studio=== 
 + 
 +Normalement, une commande échoue si elle ne renvoie pas 0. 
 + 
 +Mais Visual Studio va également analyser la sortie standard. Si le contenu de la sortie standard est faussement considéré comme une erreur, il faut rediriger la sortie standard vers NUL. 
 + 
 +<code cmake> 
 +if(CMAKE_GENERATOR MATCHES "Visual Studio"
 +  set(IGNORE_ERROR_IN_LOG ">" "NUL" "2>&1"
 +else() 
 +  set(IGNORE_ERROR_IN_LOG ""
 +endif() 
 + 
 +  add_custom_target(targ COMMAND ... ${IGNORE_ERROR_IN_LOG}) 
 +
 +</code> 
 + 
 +Ce problème peut se produire en lançant la commande `python -m ensurepip` car elle lance la sous-commande `pip install` et cette commande peut générer l'erreur : 
 + 
 +<code> 
 +"...\target.vcxproj" (default target) (5) -
 +(CustomBuild target) ->  
 +  CUSTOMBUILD : error : pip's dependency resolver does not currently take into account all the packages that are installedThis behaviour is the source of the following dependency conflicts. [...\target.vcxproj] 
 +  C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(254,5)error MSB8066Custom build for '...\file.rule;...\target.rule;...\CMakeLists.txt' exited with code -1[...\target.vcxproj] 
 + 
 +    15 Warning(s) 
 +    2 Error(s) 
 +</code>
  
 ===Dépendances dans un sous-dossier=== ===Dépendances dans un sous-dossier===
Ligne 205: Ligne 364:
  
 [[https://gmt.soest.hawaii.edu/boards/2/topics/34|CMake dependencies on subdirectories]] {{ :prog:cmake:cmake_dependencies_on_subdirectories_-_gmt_-_gmt_the_generic_mapping_tools_2019-11-29_20_46_00_.html |Archive du 16/03/2012 le 29/11/2019}} [[https://gmt.soest.hawaii.edu/boards/2/topics/34|CMake dependencies on subdirectories]] {{ :prog:cmake:cmake_dependencies_on_subdirectories_-_gmt_-_gmt_the_generic_mapping_tools_2019-11-29_20_46_00_.html |Archive du 16/03/2012 le 29/11/2019}}
 +
 +====Rustines à appliquer systématiquement====
 +
 +  * ''configure_file''
 +
 +Il faut forcer la configuration si le fichier a été supprimé depuis la configuration initiale de CMake.
 +
 +<code cmake>
 +configure_file(version.h.in version.h)
 +# Need to regenerate version.h if you remove it.
 +# https://gitlab.kitware.com/cmake/cmake/-/issues/18985
 +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
 +    "${CMAKE_CURRENT_BINARY_DIR}/version.h")
 +</code>
  
 ====Déprécié==== ====Déprécié====
Ligne 222: Ligne 395:
   DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-${version})   DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-${version})
 </code> </code>
 +
 +====Divers====
 +
 +===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.
 +
 +<code cmake>
 +add_library(file_obj OBJECT EXCLUDE_FROM_ALL file.cpp)
 +add_custom_target(file ALL COMMAND make file.cpp.i)
 +</code>
 +
 +[[http://anadoxin.org/blog/generating-preprocessed-sources-in-cmake-projects.html|Generating preprocessed sources in CMake projects]] {{ :prog:cmake:generating_preprocessed_sources_in_cmake_projects_-_antek_s_tech_blog_2020-07-21_18_01_14_.html |Archive du 21/11/2018 le 21/07/2020}}
 +
  
 ====Tests==== ====Tests====
Ligne 295: Ligne 482:
   endif()   endif()
 endforeach() endforeach()
 +</code>
 +
 +Dans le cas de Qt, il va manquer tout l'environnement Qt.
 +
 +Solution Qt 1: copier les dlls comme précédemment et définir une variable d'environnement ''QT_QPA_PLATFORM_PLUGIN_PATH=C:\Qt\5.15.2\msvc2019_64\plugins\platforms''.
 +
 +Solution Qt 2: ajouter tout l'environnement Qt. La définition de la variable ''VCINSTALLDIR'' n'est nécessaire que pour Windows.
 +
 +<code cmake>
 +add_custom_command(
 +  TARGET target
 +  POST_BUILD
 +  COMMAND
 +    ${CMAKE_COMMAND} -E env VCINSTALLDIR=${CMAKE_GENERATOR_INSTANCE}/VC
 +    ${WINDEPLOYQT_EXECUTABLE} --qmldir ${CMAKE_CURRENT_SOURCE_DIR} --pdb
 +    "$<TARGET_FILE:target>")
 </code> </code>
  
Ligne 353: Ligne 556:
 [[https://stackoverflow.com/questions/9298278/cmake-print-out-all-accessible-variables-in-a-script|CMake: Print out all accessible variables in a script]] {{ :prog:cmake:cmake_print_out_all_accessible_variables_in_a_script_-_stack_overflow_18_08_2022_14_09_34_.html |Archive du 15/02/2012 le 18/08/2022}} [[https://stackoverflow.com/questions/9298278/cmake-print-out-all-accessible-variables-in-a-script|CMake: Print out all accessible variables in a script]] {{ :prog:cmake:cmake_print_out_all_accessible_variables_in_a_script_-_stack_overflow_18_08_2022_14_09_34_.html |Archive du 15/02/2012 le 18/08/2022}}
  
-  * Afficher toutes les étapes, line par line, d'un run ''CMake''+  * Afficher toutes les étapes, ligne par ligne, d'un run ''CMake'' (configuration uniquement)
  
 Ajouter l'option ''%%--%%trace-expand''. Ajouter l'option ''%%--%%trace-expand''.
 +
 +  * Afficher le temps d'exécution de chaque ligne CMake (configuration uniquement)
 +
 +Ajouter les options ''%%--profiling-format=google-trace --profiling-output=perf.json%%'' et lire via [[https://ui.perfetto.dev/|Perfetto]].
 +
 +{{:prog:cmake:config-perf.png?1685|}}
  
   * Activer l'affichage des lignes de compilation   * Activer l'affichage des lignes de compilation
Ligne 361: Ligne 570:
 Ajouter dans le ''CMakeLists.txt'' : ''set(CMAKE_VERBOSE_MAKEFILE ON)''. Ou lancer ''VERBOSE=1 cmake ...'' Ajouter dans le ''CMakeLists.txt'' : ''set(CMAKE_VERBOSE_MAKEFILE ON)''. Ou lancer ''VERBOSE=1 cmake ...''
  
 +  * Afficher le temps pour chaque compilation pour chaque objet
  
 +<code cmake>
 +set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
 +set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CMAKE_COMMAND} -E time")
 +</code>
 +
 +Ne fonctionne que pour les Makefile et Ninja. Pas avec Visual Studio.
 +
 +Inconvénient : il faut tout compiler sans l'option ''-j''. Sinon, tous les temps affichés sont mélangés.
 +
 +====Ninja====
 +
 +  * Limiter le nombre de lieur en parallèle
 +
 +Il est possible de limiter le nombre de link en parallèle. Le lieur est consommateur en ressource. Il peut être nécessaire de limiter leur nombre à une valeur plus basse que le nombre de compilateur.
 +
 +<code cmake>
 +set(CMAKE_JOB_POOLS "link=2")
 +set(CMAKE_JOB_POOL_LINK link)
 +</code>
prog/cmake.1682079354.txt.gz · Dernière modification : 2023/04/21 14:15 de root