CMake Cheatsheet¶
Überblick¶
CMake ist ein plattformunabhängiger Systemgenerator, der plattformunabhängige Konfigurationsdateien verwendet, um native Build-Tooldateien zu generieren (Makefiles, Visual Studio-Projekte, Xcode-Projekte, etc.).
Installation¶
Paketmanager¶
# Ubuntu/Debian
sudo apt install cmake
# macOS
brew install cmake
# CentOS/RHEL
sudo yum install cmake
# Windows (Chocolatey)
choco install cmake
# From source
wget https://cmake.org/files/v3.25/cmake-3.25.0.tar.gz
tar -xzf cmake-3.25.0.tar.gz
cd cmake-3.25.0 && ./bootstrap && make && sudo make install
```_
## Grundkonzepte
### Schlüsselbegriffe
Basic CMakeLists.txt¶
Minimales Beispiel¶
```cmake cmake_minimum_required(VERSION 3.10) project(MyProject)
set(CMAKE_CXX_STANDARD 17)
add_executable(myapp main.cpp) ```_
Einfache Bibliothek¶
```cmake cmake_minimum_required(VERSION 3.10) project(MyProject VERSION 1.0.0)
Set C++ standard¶
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)
Add library¶
add_library(mylib utils.cpp network.cpp)
Add executable¶
add_executable(myapp main.cpp)
Link library to executable¶
target_link_libraries(myapp mylib) ```_
Variablen¶
Einbauvariablen¶
```cmake
Project information¶
$\\{PROJECT_NAME\\} $\\{PROJECT_VERSION\\} $\\{PROJECT_SOURCE_DIR\\} $\\{PROJECT_BINARY_DIR\\}
System information¶
$\\{CMAKE_SYSTEM_NAME\\} # Linux, Windows, Darwin $\\{CMAKE_SYSTEM_VERSION\\} $\\{CMAKE_SYSTEM_PROCESSOR\\}
Compiler information¶
$\\{CMAKE_CXX_COMPILER\\} $\\{CMAKE_CXX_COMPILER_ID\\} # GNU, Clang, MSVC $\\{CMAKE_CXX_COMPILER_VERSION\\}
Build information¶
$\\{CMAKE_BUILD_TYPE\\} # Debug, Release, RelWithDebInfo $\\{CMAKE_CURRENT_SOURCE_DIR\\} $\\{CMAKE_CURRENT_BINARY_DIR\\} ```_
Einstellvariablen¶
```cmake
Set variable¶
set(SOURCES main.cpp utils.cpp) set(MY_VAR "value")
List operations¶
list(APPEND SOURCES network.cpp) list(REMOVE_ITEM SOURCES main.cpp) list(LENGTH SOURCES NUM_SOURCES)
String operations¶
string(TOUPPER $\\{PROJECT_NAME\\} PROJECT_NAME_UPPER) string(REPLACE "old" "new" NEW_STRING $\\{OLD_STRING\\})
Cache variables¶
set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries") ```_
Ziele¶
Ausführbare¶
```cmake
Simple executable¶
add_executable(myapp main.cpp)
Executable with multiple sources¶
add_executable(myapp main.cpp utils.cpp network.cpp )
Executable with variable sources¶
set(SOURCES main.cpp utils.cpp) add_executable(myapp $\\{SOURCES\\}) ```_
Bibliotheken¶
```cmake
Static library¶
add_library(mylib STATIC utils.cpp network.cpp)
Shared library¶
add_library(mylib SHARED utils.cpp network.cpp)
Header-only library¶
add_library(mylib INTERFACE) target_include_directories(mylib INTERFACE include/)
Object library¶
add_library(mylib OBJECT utils.cpp network.cpp)
add_executable(myapp main.cpp $
Zieleigenschaften¶
```cmake
Set target properties¶
set_target_properties(myapp PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON OUTPUT_NAME "my_application" )
Include directories¶
target_include_directories(myapp PRIVATE include/ PUBLIC $\\{CMAKE_CURRENT_SOURCE_DIR\\}/public_include/ )
Compile definitions¶
target_compile_definitions(myapp PRIVATE DEBUG_MODE PUBLIC API_VERSION=2 )
Compile options¶
target_compile_options(myapp PRIVATE -Wall -Wextra PUBLIC -fPIC )
Link libraries¶
target_link_libraries(myapp PRIVATE mylib PUBLIC pthread ) ```_
Finden von Paketen¶
find_packing¶
```cmake
Find required package¶
find_package(Threads REQUIRED) target_link_libraries(myapp Threads::Threads)
Find optional package¶
find_package(OpenSSL) if(OpenSSL_FOUND) target_link_libraries(myapp OpenSSL::SSL OpenSSL::Crypto) target_compile_definitions(myapp PRIVATE HAVE_OPENSSL) endif()
Find package with components¶
find_package(Boost REQUIRED COMPONENTS system filesystem) target_link_libraries(myapp Boost::system Boost::filesystem)
Find package with version¶
find_package(Qt5 5.10 REQUIRED COMPONENTS Core Widgets) target_link_libraries(myapp Qt5::Core Qt5::Widgets) ```_
pkg-config¶
```cmake find_package(PkgConfig REQUIRED) pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
target_include_directories(myapp PRIVATE $\\{GTK3_INCLUDE_DIRS\\}) target_link_libraries(myapp $\\{GTK3_LIBRARIES\\}) target_compile_options(myapp PRIVATE $\\{GTK3_CFLAGS_OTHER\\}) ```_
Bedingte Logik¶
wenn/else/endif¶
```cmake if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_definitions(myapp PRIVATE DEBUG_MODE) elseif(CMAKE_BUILD_TYPE STREQUAL "Release") target_compile_definitions(myapp PRIVATE RELEASE_MODE) endif()
Platform-specific code¶
if(WIN32) target_sources(myapp PRIVATE windows_specific.cpp) elseif(UNIX) target_sources(myapp PRIVATE unix_specific.cpp) endif()
Compiler-specific options¶
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(myapp PRIVATE -Wall -Wextra) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") target_compile_options(myapp PRIVATE /W4) endif() ```_
Option¶
```cmake option(BUILD_TESTS "Build test programs" ON) option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
if(BUILD_TESTS) enable_testing() add_subdirectory(tests) endif() ```_
Funktionen und Makros¶
Funktionen¶
```cmake function(add_my_executable name) add_executable(\(\\\\{name\\\\} \(\\\\{ARGN\\\\}) target_compile_features(\)\\\\{name\\\\} PRIVATE cxx_std_17) target_compile_options(\)\\{name\\} PRIVATE -Wall -Wextra) endfunction()
Usage¶
add_my_executable(myapp main.cpp utils.cpp) ```_
Macros¶
```cmake macro(set_default_build_type) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) endif() endmacro()
Usage¶
set_default_build_type() ```_
Erweiterte Funktionen¶
```cmake function(add_library_with_alias target_name) set(options SHARED STATIC) set(oneValueArgs ALIAS) set(multiValueArgs SOURCES HEADERS)
cmake_parse_arguments(ARG "$\\\\{options\\\\}" "$\\\\{oneValueArgs\\\\}" "$\\\\{multiValueArgs\\\\}" $\\\\{ARGN\\\\})
if(ARG_SHARED)
add_library($\\\\{target_name\\\\} SHARED $\\\\{ARG_SOURCES\\\\})
else()
add_library($\\\\{target_name\\\\} STATIC $\\\\{ARG_SOURCES\\\\})
endif()
if(ARG_ALIAS)
add_library($\\\\{ARG_ALIAS\\\\} ALIAS $\\\\{target_name\\\\})
endif()
endfunction()
Usage¶
add_library_with_alias(mylib SHARED ALIAS MyNamespace::mylib SOURCES utils.cpp network.cpp ) ```_
Prüfung¶
CTest Integration¶
```cmake enable_testing()
Add test executable¶
add_executable(test_utils test_utils.cpp) target_link_libraries(test_utils mylib)
Add test¶
add_test(NAME test_utils COMMAND test_utils)
Test with arguments¶
add_test(NAME test_with_args COMMAND myapp --test --verbose)
Test properties¶
set_tests_properties(test_utils PROPERTIES TIMEOUT 30 WORKING_DIRECTORY $\\{CMAKE_CURRENT_BINARY_DIR\\} ) ```_
Google Test Integration¶
```cmake find_package(GTest REQUIRED)
add_executable(unit_tests test_main.cpp test_utils.cpp )
target_link_libraries(unit_tests mylib GTest::GTest GTest::Main )
Discover tests automatically¶
include(GoogleTest) gtest_discover_tests(unit_tests) ```_
Installation¶
Einfache Installation¶
```cmake
Install executable¶
install(TARGETS myapp RUNTIME DESTINATION bin )
Install library¶
install(TARGETS mylib LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin )
Install headers¶
install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h" )
Install files¶
install(FILES config.txt DESTINATION etc ) ```_
Paketkonfiguration¶
```cmake
Generate package config files¶
include(CMakePackageConfigHelpers)
Create config file¶
configure_package_config_file( $\\{CMAKE_CURRENT_SOURCE_DIR\\}/Config.cmake.in $\\{CMAKE_CURRENT_BINARY_DIR\\}/MyProjectConfig.cmake INSTALL_DESTINATION lib/cmake/MyProject )
Create version file¶
write_basic_package_version_file( $\\{CMAKE_CURRENT_BINARY_DIR\\}/MyProjectConfigVersion.cmake VERSION $\\{PROJECT_VERSION\\} COMPATIBILITY SameMajorVersion )
Install config files¶
install(FILES $\\{CMAKE_CURRENT_BINARY_DIR\\}/MyProjectConfig.cmake $\\{CMAKE_CURRENT_BINARY_DIR\\}/MyProjectConfigVersion.cmake DESTINATION lib/cmake/MyProject )
Export targets¶
install(EXPORT MyProjectTargets FILE MyProjectTargets.cmake NAMESPACE MyProject:: DESTINATION lib/cmake/MyProject ) ```_
Generator-Ausdrücke¶
Ausdrücke des Basisgenerators¶
```cmake
Build type specific¶
target_compile_definitions(myapp PRIVATE
\(<\)
Platform specific¶
target_compile_definitions(myapp PRIVATE
\(<\)
Compiler specific¶
target_compile_options(myapp PRIVATE
\(<\)
Erweiterte Generatorausdrücke¶
```cmake
Target properties¶
target_include_directories(myapp PRIVATE
$
Conditional linking¶
target_link_libraries(myapp
\(<\)
File operations¶
target_sources(myapp PRIVATE
\(<\)
Verwendung der Befehlszeile¶
Grundlegende Befehle¶
```bash
Configure (generate build files)¶
cmake -S . -B build
Build¶
cmake --build build
Install¶
cmake --install build
Test¶
cd build && ctest
Clean¶
cmake --build build --target clean ```_
Konfigurationsoptionen¶
```bash
Set build type¶
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
Set variables¶
cmake -S . -B build -DBUILD_TESTS=ON -DBUILD_SHARED_LIBS=ON
Set generator¶
cmake -S . -B build -G "Unix Makefiles" cmake -S . -B build -G "Ninja" cmake -S . -B build -G "Visual Studio 16 2019"
Set toolchain¶
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
Parallel build¶
cmake --build build --parallel 4 cmake --build build -j 4 ```_
Erweiterte Nutzung¶
```bash
Configure with preset¶
cmake --preset=default
Build specific target¶
cmake --build build --target myapp
Install to custom prefix¶
cmake --install build --prefix /opt/myapp
Run specific test¶
cd build && ctest -R test_utils
Verbose output¶
cmake --build build --verbose ctest --verbose ```_
Langfristige Entwicklung¶
Plattform-Detektion¶
cmake
if(WIN32)
# Windows-specific code
target_compile_definitions(myapp PRIVATE PLATFORM_WINDOWS)
elseif(APPLE)
# macOS-specific code
target_compile_definitions(myapp PRIVATE PLATFORM_MACOS)
elseif(UNIX)
# Linux/Unix-specific code
target_compile_definitions(myapp PRIVATE PLATFORM_LINUX)
endif()
_
Toolchain Dateien¶
```cmake
toolchain-mingw.cmake¶
set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Usage¶
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain-mingw.cmake ```_
Best Practices¶
Projektstruktur¶
```cmake cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0.0 DESCRIPTION "My awesome project" LANGUAGES CXX )
Only do these if this is the main project¶
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(CMAKE_CXX_EXTENSIONS OFF) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
include(CTest)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
endif()
Add subdirectories¶
add_subdirectory(src) add_subdirectory(external) ```_
Moderne CMake Muster¶
```cmake
Use target-based approach¶
target_include_directories(mylib PUBLIC
\(<BUILD_INTERFACE:\)\\{CMAKE_CURRENT_SOURCE_DIR\\}/include>
$
Use imported targets¶
find_package(Threads REQUIRED) target_link_libraries(myapp PRIVATE Threads::Threads)
Use generator expressions¶
target_compile_features(myapp PRIVATE cxx_std_17)
Avoid global commands¶
Don't use: include_directories(), link_directories(), add_definitions()¶
Use target-specific commands instead¶
```_
Fehlerbehebung¶
```cmake
Check CMake version¶
cmake_minimum_required(VERSION 3.15)
Validate variables¶
if(NOT DEFINED PROJECT_VERSION) message(FATAL_ERROR "PROJECT_VERSION must be defined") endif()
Check for required files¶
if(NOT EXISTS "$\\{CMAKE_CURRENT_SOURCE_DIR\\}/src/main.cpp") message(FATAL_ERROR "main.cpp not found") endif()
Validate options¶
if(BUILD_TYPE AND NOT BUILD_TYPE MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)$") message(FATAL_ERROR "Invalid BUILD_TYPE: $\\{BUILD_TYPE\\}") endif() ```_
Debugging¶
Debütausgabe¶
```cmake
Print variables¶
message(STATUS "CMAKE_BUILD_TYPE: $\\{CMAKE_BUILD_TYPE\\}") message(STATUS "CMAKE_CXX_COMPILER: $\\{CMAKE_CXX_COMPILER\\}")
Print all variables¶
get_cmake_property(_variableNames VARIABLES) foreach(_variableName \(\\\\{_variableNames\\\\}) message(STATUS "\)\\{_variableName\\}=\(\\\\{\)\\{_variableName\\}\\}") endforeach()
Print target properties¶
get_target_property(MYAPP_SOURCES myapp SOURCES) message(STATUS "myapp sources: $\\{MYAPP_SOURCES\\}") ```_
Fehlerbehebung¶
```bash
Verbose makefile¶
cmake -S . -B build -DCMAKE_VERBOSE_MAKEFILE=ON
Debug find_package¶
cmake -S . -B build --debug-find
Trace execution¶
cmake -S . -B build --trace
Debug output¶
cmake -S . -B build --debug-output ```_
Ressourcen¶
- Offizielle Dokumentation: [cmake.org/documentation](LINK_4_
- CMake Tutorial: [cmake.org/cmake/help/latest/guide/tutorial](LINK_4_
- **Moderne CMake*: cliutils.gitlab.io/modern-cmake
- CMake Beispiele: [github.com/ttroy50/cmake-Beispiele](LINK_4