A first CMakeLists.txt

CMake · Essentials · 10 min

These four lines are the start of every CMake project you'll write or read.

A minimal CMakeLists.txt:

cmake_minimum_required(VERSION 3.25)
project(hello VERSION 1.0 LANGUAGES CXX)
add_executable(hello main.cpp)
target_compile_features(hello PRIVATE cxx_std_20)
  • cmake_minimum_required must come first. It states the oldest CMake you support and switches on the behaviour (policies) of that version. CMake 4 refuses projects that declare a minimum below 3.5.
  • project names the project, optionally gives a version, and enables languages, which triggers compiler detection. LANGUAGES CXX avoids also searching for a C compiler.
  • add_executable(name sources...) creates a target: a thing to build, with its own sources and settings.
  • target_compile_features(... cxx_std_20) requires C++20 for that target; CMake adds the right flag for each compiler.

Pass settings at configure time with -D: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release. They are stored in the build tree's cache, so later configures remember them.

List source files explicitly rather than using file(GLOB ...). A glob is evaluated only at configure time, so a newly added file isn't compiled until someone reruns CMake. Explicit lists also make reviews show exactly what's built.

Command names are case-insensitive (ADD_EXECUTABLE works) but lower case is the modern convention.

Example

cmake_minimum_required(VERSION 3.25)
project(hello VERSION 1.0 LANGUAGES CXX)

add_executable(hello main.cpp greet.cpp)
target_compile_features(hello PRIVATE cxx_std_20)

# main.cpp:
#   #include <print>   // or <iostream> before C++23
#   int main() { std::puts("hello"); }
#
# $ cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
# $ cmake --build build
# [3/3] Linking CXX executable hello
# $ ./build/hello
# hello

Remember

  • cmake_minimum_required first, then project(), then targets
  • add_executable creates a target from a list of sources
  • Prefer explicit source lists over file(GLOB)

Watch out for

  • Globbing sources and wondering why a new .cpp file isn't compiled until CMake is rerun.

Check yourself

  1. Why list source files explicitly instead of using file(GLOB SRC *.cpp)?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: cmake.org/cmake/help/latest/guide/tutorial/index.html