Zum Inhalt

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

CMakeLists.txt # Configuration file Target # Executable, library, or custom target Generator # Tool that creates build files Cache # Stored configuration variables Out-of-source # Build directory separate from source


### Projektstruktur

project/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ └── utils.cpp ├── include/ │ └── utils.h └── build/ # Out-of-source build directory ```_

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 $<$:DEBUG_MODE> $<$:RELEASE_MODE> )

Platform specific

target_compile_definitions(myapp PRIVATE $<$:WINDOWS_BUILD> $<$:LINUX_BUILD> )

Compiler specific

target_compile_options(myapp PRIVATE $<$:-Wall> $<$:/W4> ) ```_

Erweiterte Generatorausdrücke

```cmake

Target properties

target_include_directories(myapp PRIVATE $ )

Conditional linking

target_link_libraries(myapp $<$:$\\{CMAKE_DL_LIBS\\}> )

File operations

target_sources(myapp PRIVATE $<$:windows_main.cpp> $<$:linux_main.cpp> ) ```_

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 $ $ )

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](https://__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