Skip to content

Introduction to CMake

Alexis Masson edited this page Aug 18, 2022 · 4 revisions

Trivia

CMake is a meta build system: it generates configuration files for an actual build system to use. Historically, that second tool has been make; we now encourage using ninja or your IDE's internal.

CMake configuration files are always named "CMakeLists.txt" (case-sensitively). They should be put along the actual source files of the project to build, and treated in the same way.

CMake also handles modules, whose name end in ".cmake"; these are usually put in a separate folder, often /cmake at the root of the project. They do not describe the build, but provide additional functionalities to be used in the build description.

Both these kinds of files are written using CMake's own language; cf. below.

Using CMake

Whatever the user interface (system shell, cmake-gui, IDE, ...), there always are two main steps: configuration and build.

  • In the configuration step, CMake reads the build description (CMakeLists.txt) and generates files for the build tool to use (e.g., Makefile or build.ninja).
  • In the build step, the build tool is called, either directly or indirectly, to perform the build and generate the required build artifacts. In case CMake needs to be re-run (maybe because one of the CMakeLists.txt has been edited), this is handled automatically without requiring the user to go through another configuration step. This means the configuration step needs only to be invoked once explicitely, even when rebuilding an updated project.

CMake projects are usually built "out-of-source", meaning the build artifacts end up in a parallel directory tree, as opposed to "in-source" builds, where they are mixed with the source files.

Using a system shell, the full process looks like the following :

# configuration step
cmake -S /path_to_source/ -B /path_to_source/build -G Ninja # -G denotes the build tool, default to `make`

# build step
cmake --build /path_to_source/build
# Alternatively, cd /path_to_source/build, then:
make # if you are using `make`
ninja # if you are using `ninja`

CMake language

The syntax of the CMake language is very simple: the only statement is the function call, the only value type is the string. You may want to read the CMake tutorial to get a comprehensive overview of the features CMake offers.

For a detailed list of the functions this project provides, please refer to Functions reference. Below is an introduction to general-purpose CMake; most of it is abstracted away in said funtions.

Here are some key points about the structure of a CMakeLists.txt (Also read the documentation):

  • The main file must start with a call to cmake_minimum_required(), to make sure the version of CMake meets the expectations;

  • A call to project() must occur before tackling any file or target;

  • You can include a subpart of your project by calling add_subdirectory(). This will run the CMakeLists.txt in the target subdirectory. Modularizing your project in this way is highly encouraged!

  • Projects are structured into logical "targets":

    These logical targets can have dependencies on one another. Except for the interface libraries, they are visible to the build tool, and can be build independently. (Illustration: when running make clean ; make all ; make install, clean, all, install are targets)

    All these targets have build settings that can, optionally, be propagated to the targets depending on them:

    These commands make use of the PUBLIC, INTERFACE or PRIVATE keywords.

    • PUBLIC and INTERFACE will apply the setting to all the dependers of the target in question;
    • INTERFACE and PRIVATE also apply the setting to the target itself.

Further readings

Official from Kitware (CMake doc)

Third-party

The links below are not endorsed by STMicroelectonics nor Kitware, but have proven useful in practice for users learning to use CMake "sanely".