Přeskočit na obsah

Build Systems: CMake & Package Management

Master CMake fundamentals, modern target-based CMake, FetchContent for dependencies, vcpkg and Conan package managers, and compiler flags for safe, optimized builds.

Why Build Systems Matter

As C++ projects grow beyond a single file, you need a build system to manage compilation, linking, dependencies, and platform differences. Manually runningg++ *.cppdoesn't scale: you need incremental builds (recompile only changed files), library detection, cross-platform support, and reproducible builds. CMake has become the de facto standard build system generator for C++. It doesn't compile code itself — it generates native build files (Makefiles, Ninja files, Visual Studio projects) for your platform.

CMake Basics

ACMakeLists.txtfile describes your project structure. Modern CMake (3.12+) uses a target-based approach where everything is attached to targets (executables or libraries):

CMakeLists.txt
# CMakeLists.txt — minimum viable project
cmake_minimum_required(VERSION 3.20)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)

# Set C++ standard for the entire project
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)  # use -std=c++20, not -std=gnu++20

# Create an executable target
add_executable(myapp
    src/main.cpp
    src/engine.cpp
    src/utils.cpp
)

# Add include directories for this target
target_include_directories(myapp PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Create a library target
add_library(mathlib STATIC
    src/math/vector.cpp
    src/math/matrix.cpp
)

target_include_directories(mathlib PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include/math
)

# Link the library to the executable
target_link_libraries(myapp PRIVATE mathlib)

# Compiler warnings — essential for quality code
target_compile_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic -Werror>
    $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
)

Building with CMake

CMake uses a two-step process: configure (generate build files) and build (compile). Always use out-of-source builds to keep the source tree clean:

terminal
# Configure — generate build files in a 'build' directory
cmake -B build -DCMAKE_BUILD_TYPE=Release

# Build — compile the project
cmake --build build --parallel $(nproc)

# Install (optional)
cmake --install build --prefix /usr/local

# Common build types:
# Debug          — -O0 -g (full debug symbols, no optimization)
# Release        — -O3 -DNDEBUG (max optimization, no asserts)
# RelWithDebInfo — -O2 -g -DNDEBUG (optimized with debug info)
# MinSizeRel     — -Os -DNDEBUG (optimize for size)

# Run with sanitizers (add to CMakeLists.txt or command line)
cmake -B build-asan -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"

FetchContent: Dependency Management

CMake'sFetchContentmodule downloads and builds dependencies at configure time, making it easy to pull in libraries without manual setup:

CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(MyApp LANGUAGES CXX)

include(FetchContent)

# Fetch GoogleTest
FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG        v1.14.0
)

# Fetch fmt (formatting library)
FetchContent_Declare(
    fmt
    GIT_REPOSITORY https://github.com/fmtlib/fmt.git
    GIT_TAG        10.2.1
)

# Download and make available
FetchContent_MakeAvailable(googletest fmt)

add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt)

# Test executable
enable_testing()
add_executable(tests tests/test_main.cpp)
target_link_libraries(tests PRIVATE GTest::gtest_main)
add_test(NAME unit_tests COMMAND tests)

vcpkg and Conan

For larger projects with many dependencies, dedicated C++ package managers provide better dependency resolution and caching:

vcpkg (Microsoft) — integrates directly with CMake via a toolchain file. Install packages globally or in "manifest mode" with avcpkg.jsonfile:

{
 "dependencies": ["fmt", "spdlog", "nlohmann-json", "catch2"]
}

Use with: cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake

Conan — uses a conanfile.txt or conanfile.py to declare dependencies. Supports multiple build configurations and binary caching:

[requires]
fmt/10.2.1
spdlog/1.13.0

[generators]
CMakeDeps
CMakeToolchain

Both package managers maintain repositories of thousands of C++ libraries with tested, pre-built binaries.

Osvědčený postup

Follow these rules for maintainable CMake:

1. Always use target-based commands:target_include_directories,target_compile_options,target_link_libraries— neverinclude_directoriesoradd_definitions(which pollute the global scope).
2. Understand PRIVATE/PUBLIC/INTERFACE:PRIVATE= only for this target,PUBLIC= for this target and its consumers,INTERFACE= only for consumers.
3. Set the C++ standard per-target or project-wide, never via raw flags like-std=c++20.
4. Enable maximum warnings:-Wall -Wextra -Wpedantic(GCC/Clang) or/W4(MSVC). Consider-Werror//WXin CI.
5. Usecmake --preset for reproducible builds (CMakePresets.json).
6. Never hardcode paths — usefind_package,FetchContent, or package managers.

Úskalí

Usingfile(GLOB ...)to collect sources:file(GLOB SOURCES src/*.cpp)does NOT re-run when files are added or removed. New files won't be compiled until you manually re-configure. Always list source files explicitly.

ForgettingCMAKE_CXX_EXTENSIONS OFF: Without this, GCC uses-std=gnu++20instead of-std=c++20, enabling non-standard extensions that break portability.

Mixingadd_subdirectoryandFetchContent: Both bring in external projects, but they interact differently with the build cache. Choose one approach per dependency.

Not settingCMAKE_EXPORT_COMPILE_COMMANDS ON: This generatescompile_commands.json, which is needed by clang-tidy, clangd (LSP), and many IDE integrations. Always enable it.

Klíčové poznatky
  • CMake je standardní generátor sestavovacího systému C++ – naučte se jeho cílové API
  • Použijte příkazytarget_*(nikoli globální rozsah) s viditelností PRIVATE/PUBLIC/INTERFACE
  • FetchContent stahuje a vytváří závislosti v době konfigurace – ideální pro malé sady závislostí
  • vcpkg (režim manifestu) a Conan zpracovávají větší grafy závislostí pomocí binárního ukládání do mezipaměti
  • Always enable warnings (-Wall -Wextra -Wpedantic) and use out-of-source builds
  • Generatecompile_commands.jsonfor IDE and static analysis tooling

Kvíz — Otestujte své znalosti

(15 XP)

1. What does`target_link_libraries(myapp PRIVATE mathlib)`do?

2. Proč je`file(GLOB SOURCES src/*.cpp)`považován za špatný postup v CMake?

3. Jaký je účel`CMAKE_CXX_EXTENSIONS OFF`?