cmake

Topics related to cmake:

Getting started with cmake

Hierarchical project

CMake integration in GitHub CI tools

Variables and Properties

Variable names are case-sensitive. Their values are of type string. The value of a variable is referenced via:

${variable_name}

and is evaluated inside a quoted argument

"${variable_name}/directory"

Functions and Macros

The main difference between macros and functions is, that macros are evaluated within the current context, while functions open a new scope within the current one. Thus, variables defined within functions are not known after the function has been evaluated. On the contrary, variables within macros are still defined after the macro has been evaluated.

Build Targets

Test and Debug

Create test suites with CTest

Packaging and Distributing Projects

CPack is an external tool allowing the fast packaging of built CMake projects by gathering all the required data straight from the CMakeLists.txt files and the utilized installation commands like install_targets().

For CPack to properly work, the CMakeLists.txt must include files or targets to be installed using the install build target.

A minimal script could look like this:

# Required headers
cmake(3.0)

# Basic project setup
project(my-tool)

# Define a buildable target
add_executable(tool main.cpp)

# Provide installation instructions
install_targets(tool DESTINATION bin)

Compile features and C/C++ standard selection

Add Directories to Compiler Include Path

Search and use installed packages, libraries and programs

Configure file

Copy a file to another location and modify its contents.

configure_file(<input> <output>
           [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
           [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])

Copies a file to file and substitutes variable values referenced in the file content. If is a relative path it is evaluated with respect to the current source directory. The must be a file, not a directory. If is a relative path it is evaluated with respect to the current binary directory. If names an existing directory the input file is placed in that directory with its original name.

If the file is modified the build system will re-run CMake to re-configure the file and generate the build system again.

This command replaces any variables in the input file referenced as ${VAR} or @VAR@ with their values as determined by CMake. If a variable is not defined, it will be replaced with nothing. If COPYONLY is specified, then no variable expansion will take place. If ESCAPE_QUOTES is specified then any substituted quotes will be C-style escaped. The file will be configured with the current values of CMake variables. If @ONLY is specified, only variables of the form @VAR@ will be replaced and ${VAR} will be ignored. This is useful for configuring scripts that use ${VAR}.

Input file lines of the form “#cmakedefine VAR ...” will be replaced with either “#define VAR ...” or /* #undef VAR */ depending on whether VAR is set in CMake to any value not considered a false constant by the if() command. (Content of ”...”, if any, is processed as above.) Input file lines of the form “#cmakedefine01 VAR” will be replaced with either “#define VAR 1” or “#define VAR 0” similarly.

With NEWLINE_STYLE the line ending could be adjusted:

'UNIX' or 'LF' for \n, 'DOS', 'WIN32' or 'CRLF' for \r\n.

COPYONLY must not be used with NEWLINE_STYLE.

Build Configurations

Custom Build-Steps

As you can see, you can do a lot with custom build targets and steps in cmake, but you should be careful in using them, especially when copying dlls. While it is convinient to do so, it can at times result in what is affectionately called "dll hell".

Basically this means you can get lost in which dlls your executable actually depends on, which ones its loading, and which ones it needs to run (maybe because of your computer's path variable).

Other than the above caveat, feel free to make custom targets do whatever you want! They're powerful and flexible and are an invaluable tool to any cmake project.

Using CMake to configure preproccessor tags

It is important to understand not every preprocessor should be defined in the config.h.in. Preprocessor tags are generally used only to make the programmers life easier and should be used with discretion. You should research if a preprocessor tag already exists before defining it as you may run into undefined behavior on different system.