Build Tools Testing
CMake Basics
Overview
CMake is a cross-platform build system generator. It doesn't build your code directlyβit generates native build files (Makefiles, Visual Studio projects, etc.) that then compile your code.
Learning Objectives
By the end of this section, you will understand:
- CMake basics and CMakeLists.txt structure
- Creating executables and libraries
- Managing dependencies
- Modern CMake practices (target-based)
- Using CMake with external libraries
Why CMake?
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CMake WORKFLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ β
β β CMakeLists.txt β β
β β (Platform- β β
β β Independent) β β
β ββββββββββ¬βββββββββ β
β β β
β βΌ β
β βββββββββββββββββββ β
β β CMake β β
β β Generator β β
β ββββββββββ¬βββββββββ β
β β β
β βββββββββΌββββββββ β
β βΌ βΌ βΌ β
β ββββββββ ββββββββ ββββββββ β
β βMake- β βVisualβ βNinja β ... other build systems β
β βfile β βStudioβ β β β
β ββββββββ ββββββββ ββββββββ β
β β
β Write once, build anywhere! β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Minimal CMakeLists.txt
# Minimum required CMake version
cmake_minimum_required(VERSION 3.16)
# Project name and version
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
# Create an executable
add_executable(my_app main.cpp)
Project Structure
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β TYPICAL CMAKE PROJECT STRUCTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β my_project/ β
β βββ CMakeLists.txt βββ Root CMake file β
β βββ src/ β
β β βββ CMakeLists.txt βββ Source directory CMake β
β β βββ main.cpp β
β β βββ utils.cpp β
β β βββ utils.hpp β
β βββ include/ β
β β βββ my_project/ β
β β βββ public_header.hpp β
β βββ tests/ β
β β βββ CMakeLists.txt βββ Test directory CMake β
β β βββ test_utils.cpp β
β βββ libs/ βββ Third-party libraries β
β βββ build/ βββ Build output (generated) β
β βββ Makefile β
β βββ ... β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Building with CMake
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BUILD COMMANDS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β # Step 1: Create build directory β
β mkdir build && cd build β
β β
β # Step 2: Generate build files β
β cmake .. β
β β
β # Step 3: Build the project β
β cmake --build . β
β β
β # Or use make directly (if Makefile generator) β
β make β
β β
β # Build with parallel jobs β
β cmake --build . -j4 β
β β
β # Build specific target β
β cmake --build . --target my_app β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CMake Commands
Creating Targets
# Executable
add_executable(app_name source1.cpp source2.cpp)
# Static library (.a / .lib)
add_library(mylib STATIC source1.cpp source2.cpp)
# Shared library (.so / .dll)
add_library(mylib SHARED source1.cpp source2.cpp)
# Header-only library (INTERFACE)
add_library(mylib INTERFACE)
Setting Properties
# C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Or per-target (modern way)
target_compile_features(my_app PRIVATE cxx_std_17)
# Compiler flags
target_compile_options(my_app PRIVATE -Wall -Wextra -Wpedantic)
# Definitions
target_compile_definitions(my_app PRIVATE DEBUG_MODE=1)
Include Directories
# Include paths
target_include_directories(my_app
PUBLIC ${PROJECT_SOURCE_DIR}/include # Propagates to dependents
PRIVATE ${PROJECT_SOURCE_DIR}/src # Only for this target
)
Linking
# Link libraries
target_link_libraries(my_app
PRIVATE mylib # Internal dependency
PUBLIC otherlib # Propagates to dependents
)
Visibility Keywords
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β TARGET PROPERTY VISIBILITY β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PRIVATE β β
β β Only affects the target itself β β
β β Example: Implementation details, internal includes β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PUBLIC β β
β β Affects target AND anything that links to it β β
β β Example: Public headers, API definitions β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β INTERFACE β β
β β Only affects things that link to the target β β
β β Example: Header-only libraries β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Example: β
β βββββββββββ PUBLIC βββββββββββ links βββββββββββ β
β β LibA βββββββββΊβ LibB ββββββββΊβ App β β
β βββββββββββ βββββββββββ βββββββββββ β
β β β β β
β ββββββββββββββββββββ΄βββββββββββββββββββ β
β App gets LibA's public properties! β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Finding Packages
# Find system-installed package
find_package(Threads REQUIRED)
# Find with components
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem system)
# Use the found package
target_link_libraries(my_app
PRIVATE
Threads::Threads
Boost::filesystem
Boost::system
)
Common Package Patterns
# OpenSSL
find_package(OpenSSL REQUIRED)
target_link_libraries(app PRIVATE OpenSSL::SSL OpenSSL::Crypto)
# CURL
find_package(CURL REQUIRED)
target_link_libraries(app PRIVATE CURL::libcurl)
# SQLite
find_package(SQLite3 REQUIRED)
target_link_libraries(app PRIVATE SQLite::SQLite3)
FetchContent (Download Dependencies)
include(FetchContent)
# Declare dependency
FetchContent_Declare(
json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.2
)
# Make it available
FetchContent_MakeAvailable(json)
# Use it
target_link_libraries(my_app PRIVATE nlohmann_json::nlohmann_json)
Variables and Cache
# Regular variable
set(MY_VAR "value")
# Cache variable (user-configurable)
set(MY_OPTION "default" CACHE STRING "Description of option")
# Boolean option
option(ENABLE_TESTS "Build tests" ON)
# Use variables
message(STATUS "MY_VAR = ${MY_VAR}")
# Conditional
if(ENABLE_TESTS)
add_subdirectory(tests)
endif()
Subdirectories
# Root CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(MyProject)
# Add subdirectories
add_subdirectory(src)
add_subdirectory(tests)
# src/CMakeLists.txt
add_library(mylib source.cpp)
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# tests/CMakeLists.txt
add_executable(tests test_main.cpp)
target_link_libraries(tests PRIVATE mylib)
Complete Example
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(Calculator VERSION 1.0.0 LANGUAGES CXX)
# Settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Options
option(BUILD_TESTS "Build unit tests" ON)
# Create library
add_library(calc_lib
src/calculator.cpp
src/operations.cpp
)
target_include_directories(calc_lib
PUBLIC ${PROJECT_SOURCE_DIR}/include
PRIVATE ${PROJECT_SOURCE_DIR}/src
)
target_compile_options(calc_lib PRIVATE
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra>
$<$<CXX_COMPILER_ID:MSVC>:/W4>
)
# Create executable
add_executable(calculator src/main.cpp)
target_link_libraries(calculator PRIVATE calc_lib)
# Tests
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
# Installation
install(TARGETS calculator DESTINATION bin)
install(DIRECTORY include/ DESTINATION include)
Generator Expressions
# Compiler-specific flags
target_compile_options(app PRIVATE
$<$<CXX_COMPILER_ID:GNU>:-Wall>
$<$<CXX_COMPILER_ID:MSVC>:/W4>
)
# Configuration-specific
target_compile_definitions(app PRIVATE
$<$<CONFIG:Debug>:DEBUG_MODE>
$<$<CONFIG:Release>:NDEBUG>
)
# Build interface vs install interface
target_include_directories(lib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
Recommended Conventions
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MODERN CMAKE BEST PRACTICES β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β β DO β DON'T β
β βββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββ β
β β’ Use target_* commands β’ Use include_directories() β
β β’ Use PRIVATE/PUBLIC/INTERFACE β’ Use link_libraries() β
β β’ Use generator expressions β’ Use CMAKE_CXX_FLAGS β
β β’ Use FetchContent for deps β’ Use file(GLOB ...) for sources β
β β’ Create IMPORTED targets β’ Hardcode paths β
β β’ Use cmake --build β’ Mix old and modern CMake β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β OLD (avoid): β β
β β include_directories(include) β β
β β link_libraries(mylib) β β
β β add_definitions(-DDEBUG) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MODERN (prefer): β β
β β target_include_directories(app PRIVATE include) β β
β β target_link_libraries(app PRIVATE mylib) β β
β β target_compile_definitions(app PRIVATE DEBUG) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Useful Commands
| Command | Description |
|---|---|
cmake -S . -B build |
Configure with source and build dirs |
cmake --build build |
Build the project |
cmake --build build -j |
Build with all CPU cores |
cmake --install build |
Install the project |
cmake --build build --target clean |
Clean build |
cmake -DCMAKE_BUILD_TYPE=Release .. |
Release build |
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. |
For IDE/tools |
Summary
| Concept | Purpose |
|---|---|
cmake_minimum_required |
Set minimum CMake version |
project() |
Define project name and languages |
add_executable() |
Create executable target |
add_library() |
Create library target |
target_* commands |
Modern, target-based configuration |
find_package() |
Locate installed dependencies |
FetchContent |
Download dependencies at configure time |
Next Steps
- Practice with
examples.cpp(a complete CMake project) - Complete the
exercises.cppchallenges - Try building real projects with CMake
- Explore CPack for packaging