Skip to the content.

cmake-start-project

Information

CMake is a cross-platform build system generator. It does not build code directly but generates native build files (Makefiles, Ninja build files, Visual Studio projects, etc.) from a CMakeLists.txt description. It is the de-facto standard for C and C++ projects.

Preparations

Minimal Project Structure

my-project/
├── CMakeLists.txt
├── src/
│   └── main.cpp
├── include/
│   └── my-project/
│       └── my_lib.h
├── tests/
│   └── test_main.cpp
└── cmake/
    └── FindSomeDep.cmake

Minimal CMakeLists.txt (executable)

cmake_minimum_required(VERSION 3.20)
project(my-project VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(my-project src/main.cpp)
target_include_directories(my-project PRIVATE include)

Minimal CMakeLists.txt (library + executable)

cmake_minimum_required(VERSION 3.20)
project(my-project VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(my-lib src/my_lib.cpp)
target_include_directories(my-lib PUBLIC include)

add_executable(my-project src/main.cpp)
target_link_libraries(my-project PRIVATE my-lib)

Build and Run

mkdir build
cd build
cmake ..
cmake --build .
./my-project

Release build:

cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .

Using Ninja (faster builds):

cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
ninja

Installation

Rocky Linux / Fedora

sudo dnf install -y cmake gcc gcc-c++ ninja-build
cmake --version

Debian / Ubuntu

sudo apt-get install -y cmake g++ ninja-build
cmake --version

FreeBSD

pkg install -y cmake ninja

Windows

Install via winget:

winget install Kitware.CMake
winget install Ninja-build.Ninja

Or install via Visual Studio Installer which bundles CMake and Ninja.

Configuration

CMakePresets.json (CMake 3.20+)

Presets allow sharing standard configure/build/test options without passing flags manually:

{
    "version": 3,
    "configurePresets": [
        {
            "name": "debug",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/build/debug",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Debug"
            }
        },
        {
            "name": "release",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/build/release",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Release"
            }
        }
    ]
}

Use with:

cmake --preset debug
cmake --build --preset debug

Dependency Management with vcpkg

git clone https://github.com/microsoft/vcpkg.git
./vcpkg/bootstrap-vcpkg.sh

Add to CMakeLists.txt before project():

set(CMAKE_TOOLCHAIN_FILE "${CMAKE_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake")

Declare dependencies in vcpkg.json:

{
    "name": "my-project",
    "version": "0.1.0",
    "dependencies": ["fmt", "spdlog"]
}

Dependency Management with Conan

pip install conan
conan profile detect

conanfile.txt:

[requires]
spdlog/1.13.0

[generators]
CMakeDeps
CMakeToolchain
conan install . --output-folder=build --build=missing
cmake -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build

Usage, tips and tricks

CTest — Unit Testing

Add tests to CMakeLists.txt:

enable_testing()
find_package(GTest REQUIRED)

add_executable(test_main tests/test_main.cpp)
target_link_libraries(test_main PRIVATE my-lib GTest::gtest_main)

include(GoogleTest)
gtest_discover_tests(test_main)

Run tests:

cd build
ctest --output-on-failure

Install Rules

install(TARGETS my-project DESTINATION bin)
install(TARGETS my-lib DESTINATION lib)
install(DIRECTORY include/ DESTINATION include)

Install to a local prefix:

cmake --install build --prefix /opt/my-project

Compiler Warnings

target_compile_options(my-project PRIVATE -Wall -Wextra -Wpedantic)

See also