Skip to content
Published On:
Dec 7, 2016
Last Updated:
Oct 17, 2024

cmake is a cross-platform tool for building applications. It is commonly used with C and C++. The program is configured through CMakeLists.txt files, which reside in the source directories of the corresponding code.

The CMake logo1.

The output of cmake is standard build/project files (e.g. Makefiles if targeting GNU make). These build files are then run using the standard build command to generate the final build files.

Child Pages

Quick Syntax Overview

One thing that cmake does different from other “languages” is enforce that all variables passed into a function are linked by naming, rather than their order.

cmake is commonly used to generate build files for:

  • make
  • Apple’s XCode
  • Eclipse
  • Microsoft Visual Studio
  • Ninja

cmake calls it’s specific modules that convert cmake code into these various build systems generators.

Setting Variables

Variables can be created and assigned in cmake with the set() function. e.g.

set(SOURCES foo.cpp)

This created a new variable called SOURCES.

set() may also be used to make a list variable. Each element in the list should be separated with a space.

set(SOURCES foo1.cpp foo2.cpp)

set() can make normal, cache or environment variables. All the above examples are setting normal variables (this is the default).

Normal variables are visible to the CMakeLists.txt file they are set in, and also everything called from there (add_subdirectory(), include(), macro() and function()).

You can also set properties.

Adding Sub-directories

Use add_subdirectory() to add a directory which contains another CMakeLists.txt and code that requires building. It has the following syntax:

add_subdirectory(<folder_path>)

If <folder_path> is relative, it will be relative to the CMakeLists.txt file which called this function. But, it can also be absolute (in which case add_subdirectory() is somewhat of a misnomer).

Adding Libraries

Libraries can be added with:

add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])

For example, the following command creates a static library called my_library from the source file src.cpp.

add_library(my_library STATIC src.cpp)

The library name must be a new name which is unique in the project. target_link_libraries() can be used after add_library() to specify what other libraries this newly created library needs linking to.

Linking Libraries

Once libraries have been added with add_library(), they need to be linked. This is normally done with target_link_libraries() or just link_libraries() (the former option is preferred).

link_libraries() causes all proceeding targets in the CMakeLists.txt to be linked to this library.

Copying Files

Files can be copied as part of the build process using the following syntax:

file(COPY files... DESTINATION <dir>)

You can specify glob or regex patterns to copy only certain files. The following example will only copy header files (.h):

install(DIRECTORY src/ DESTINATION include/myproj
FILES_MATCHING PATTERN "*.h")

Adding Preprocessor Definitions

Preprocessor definitions can be added by using the following cmake command:

add_definitions(-DMY_DEF_1 -DMY_DEF2)

The add_definitions command can actually be used to add any compiler flags, but is intended for adding definitions (flags that begin with -D) only.

This command add the flags to all sources in the current directory and below.

add_custom_target()

Custom targets are always built. Because there is no output file, they are considered always out-of-date, and are always re-built.

add_custom_command()

add_custom_command() is used specify how to make the defined OUTPUT files, based on command-line(s) COMMAND.

add_custom_target() is commonly used at the same time as add_custom_command().

The .stamp file extension is commonly used to create empty placeholder files as the OUTPUT of add_custom_command(). These files can then be used as dependents for other build targets.

Cache

cmake creates a global cache called CMakeCache.txt which is created at root level of the build folder.

The cache can be used to create and store variables which have global and persistent scope. This means they can be read/set by any CMakeLists.txt file in the project, and they keep their previous value between successive cmake calls.

Maths

Basic maths (addition, subtraction, e.t.c) can be done in a CMakeLists.txt file via the math() function. e.g. to increment a counter we would use the syntax:

math(EXPR count "${count} + 1")

EXPR is to tell cmake you wish to evaluate the expression. It is currently the only supported mathematical operation.

Adding .cmake Files

You can use the include() function to include .cmake file code into your CMakeLists.txt file. cmake will scan CMAKE_MODULE_PATH to look for .cmake files.

Running cmake

This completely depends on the structure of the source code you are building, but in general, something close to the example below will be followed.

Terminal window
$ mkdir build
$ cd build/
$ cmake ..
$ make

This is of course assuming an out-of-source build setup (the recommended approach!). This standard way of building is used by OpenCV.

Running OS Specific Code

You can run OS specific code in CMake by using the if(CMAKE_HOST_WIN32) and if(WIN32) expressions. CMAKE_HOST_WIN32 will be true if the machine cmake is running on is Windows. WIN32 will be true if you are compiling FOR windows (CMAKE_HOST_WIN32 can be true but WIN32 false if cross-compiling on Windows for a different architecture)2.

CMakeLists.txt
if(CMAKE_HOST_WIN32)
message(STATUS "Running on Windows.")
else()
message(STATUS "Not running on Windows.")
endif()
if(WIN32)
message(STATUS "Compiling for Windows.")
else()
message(STATUS "Not compiling for Windows.")
endif()

This can be useful when wanting to run OS-specific shell commands, for example when using the add_custom_command() function.

Footnotes

  1. Kitware. CMake Homepage. Retrieved 2024-10-17, from https://cmake.org/.

  2. StackOverflow. Platform detection in CMake [forum post]. Retrieved 2024-10-17, from https://stackoverflow.com/questions/9742003/platform-detection-in-cmake.