Cmake
Cmake
Cmake
#cmake
Table of Contents
About 1
Remarks 2
Versions 2
Examples 3
CMake Installation 3
Syntax 8
Parameters 8
Examples 8
Introduction 9
Examples 9
Syntax 10
Examples 10
Executables 10
Libraries 10
Examples 12
Syntax 14
Examples 14
Introduction 16
Remarks 16
Examples 16
Examples 20
Introduction 21
Remarks 21
Examples 21
Remarks 24
Examples 24
Examples 26
Syntax 27
Remarks 27
Examples 27
Chapter 13: Search and use installed packages, libraries and programs 29
Syntax 29
Parameters 29
Remarks 29
Examples 29
Examples 32
Introduction 35
Syntax 35
Remarks 35
Examples 35
Introduction 37
Syntax 37
Remarks 37
Examples 37
Local Variable 37
Credits 41
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: cmake
It is an unofficial and free cmake ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official cmake.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ 1
Chapter 1: Getting started with cmake
Remarks
CMake is a tool for defining and managing code builds, primarily for C++.
CMake is a cross-platform tool; the idea is to have a single definition of how the project is built -
which translates into specific build definitions for any supported platform.
Build behavior is defined in CMakeLists.txt files - one in every directory of the source code. Each
directory's CMakeLists file defines what the buildsystem should do in that specific directory. It also
defines which subdirectories CMake should handle as well.
• Build a library or an executable out of some of the source files in this directory.
• Add a filepath to the include-path used during build.
• Define variables that the buildsystem will use in this directory, and in its subdirectories.
• Generate a file, based on the specific build configuration.
• Locate a library which is somewhere in the source tree.
The final CMakeLists files can be very clear and straightforward, because each is so limited in
scope. Each only handles as much of the build as is present in the current directory.
Versions
3.9 2017-07-18
3.8 2017-04-10
3.7 2016-11-11
3.6 2016-07-07
3.5 2016-03-08
3.4 2015-11-12
3.3 2015-07-23
https://riptutorial.com/ 2
Version Release Date
3.2 2015-03-10
3.1 2014-12-17
3.0 2014-06-10
2.8.12.1 2013-11-08
2.8.12 2013-10-11
2.8.11 2013-05-16
2.8.10.2 2012-11-27
2.8.10.1 2012-11-07
2.8.10 2012-10-31
2.8.9 2012-08-09
2.8.8 2012-04-18
2.8.7 2011-12-30
2.8.6 2011-12-30
2.8.5 2011-07-08
2.8.4 2011-02-16
2.8.3 2010-11-03
2.8.2 2010-06-28
2.8.1 2010-03-17
2.8 2009-11-13
2.6 2008-05-05
Examples
CMake Installation
Head over to CMake download page and get a binary for your operating system, e.g. Windows,
Linux, or Mac OS X. On Windows double click the binary to install. On Linux run the binary from a
terminal.
https://riptutorial.com/ 3
On Linux, you can also install the packages from the distribution's package manager. On Ubuntu
16.04 you can install the command-line and graphical application with:
On FreeBSD you can install the command-line and the Qt-based graphical application with:
On Mac OSX, if you use one of the package managers available to install your software, the most
notable being MacPorts (MacPorts) and Homebrew (Homebrew), you could also install CMake via
one of them. For example, in case of MacPorts, typing the following
will install CMake, while in case you use the Homebrew package manger you will type
Once you have installed CMake you can check easily by doing the following
cmake --version
CMake knows several build types, which usually influence default compiler and linker parameters
(such as debugging information being created) or alternative code paths.
• Debug: Usually a classic debug build including debugging information, no optimization etc.
• Release: Your typical release build with no debugging information and full optimization.
• RelWithDebInfo:: Same as Release, but with debugging information.
• MinSizeRel: A special Release build optimized for size.
How configurations are handled depends on the generator that is being used.
Some generators (like Visual Studio) support multiple configurations. CMake will generate all
configurations at once and you can select from the IDE or using --config CONFIG (with cmake --
build) which configuration you want to build. For these generators CMake will try its best to
https://riptutorial.com/ 4
generate a build directory structure such that files from different configurations do not step on each
other.
Generators that do only support a single configuration (like Unix Makefiles) work differently. Here
the currently active configuration is determined by the value of the CMake variable
CMAKE_BUILD_TYPE.
For example, to pick a different build type one could issue the following command line commands:
A CMake script should avoid setting the CMAKE_BUILD_TYPE itself, as it's generally considered the
users responsibility to do so.
For single-config generators switching the configuration requires re-running CMake. A subsequent
build is likely to overwrite object files produced by the earlier configuration.
Given a C++ source file main.cpp defining a main() function, an accompanying CMakeLists.txt file
(with the following content) will instruct CMake to generate the appropriate build instructions for
the current system and default C++ compiler.
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.4)
project(hello_world)
add_executable(app main.cpp)
2. project(hello_world) starts a new CMake project. This will trigger a lot of internal CMake
logic, especially the detection of the default C and C++ compiler.
3. With add_executable(app main.cpp) a build target app is created, which will invoke the
https://riptutorial.com/ 5
configured compiler with some default flags for the current setting to compile an executable
app from the given source file main.cpp.
> cmake .
...
> cmake --build .
cmake .does the compiler detection, evaluates the CMakeLists.txt in the given . directory and
generates the build environment in the current working directory.
The cmake --build . command is an abstraction for the necessary build/make call.
To keep your source code clean from any build artifacts you should do "out-of-source" builds.
Or CMake can also abstract your platforms shell's basic commands from above's example:
First we can specify the directories of header files by include_directories(), then we need to
specify the corresponding source files of the target executable by add_executable(), and be sure
there's exactly one main() function in the source files.
Following is a simple example, all the files are assumed placed in the directory PROJECT_SOURCE_DIR.
main.cpp
#include "foo.h"
int main()
{
foo();
return 0;
}
foo.h
void foo();
https://riptutorial.com/ 6
foo.cpp
#include <iostream>
#include "foo.h"
void foo()
{
std::cout << "Hello World!\n";
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.4)
project(hello_world)
include_directories(${PROJECT_SOURCE_DIR})
add_executable(app main.cpp foo.cpp) # be sure there's exactly one main() function in the
source files
We can follow the same procedure in the above example to build our project. Then executing app
will print
>./app
Hello World!
This example shows how to deploy the "Hello World" program as a library and how to link it with
other targets.
We modify CMakeLists.txt to
cmake_minimum_required(VERSION 2.4)
project(hello_world)
include_directories(${PROJECT_SOURCE_DIR})
add_library(applib foo.cpp)
add_executable(app main.cpp)
target_link_libraries(app applib)
and following the same steps, we'll get the same result.
https://riptutorial.com/ 7
Chapter 2: Add Directories to Compiler
Include Path
Syntax
• include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
Parameters
Parameter Description
(optional) whether to add the given directories to the front or end of the current
AFTER,
BEFORE list of include paths; default behaviour is defined by
CMAKE_INCLUDE_DIRECTORIES_BEFORE
(optional) tells the compiler to tread the given directories as system include dirs,
SYSTEM
which might trigger special handling by the compiler
Examples
Add a Project's Subdirectory
include\
myHeader.h
src\
main.cpp
CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/include)
adds the include directory to the include search path of the compiler for all targets defined in this
directory (and all its subdirectories included via add_subdirectory()).
Thus, the file myHeader.h in the project's include subdirectory can be included via #include
"myHeader.h" in the main.cpp file.
https://riptutorial.com/ 8
Chapter 3: Build Configurations
Introduction
This topic shows the uses of different CMake configurations like Debug or Release, in different
environments.
Examples
Setting a Release/Debug configuration
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
SET(PROJ_NAME "myproject")
PROJECT(${PROJ_NAME})
# Configuration types
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
IF(DEFINED CMAKE_BUILD_TYPE AND CMAKE_VERSION VERSION_GREATER "2.8")
SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES})
ENDIF()
# Install
#---------------------------------------------------#
INSTALL(TARGETS ${PROJ_NAME}
DESTINATION "${${PROJ_NAME}_PATH_INSTALL}/lib/${CMAKE_BUILD_TYPE}/"
)
$ cd /myproject/build
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
$ make
$ sudo make install
$ cmake _DCMAKE_BUILD_TYPE=Release ..
$ make
$ sudo make install
https://riptutorial.com/ 9
Chapter 4: Build Targets
Syntax
• add_executable(target_name [EXCLUDE_FROM_ALL] source1 [source2...])
• add_library(lib_name [STATIC|SHARED|MODULE] [EXCLUDE_FROM_ALL] source1
[source2 ...])
Examples
Executables
To create a build target producing an executable, one should use the add_executable command:
add_executable(my_exe
main.cpp
utilities.cpp)
This creates a build target, e.g. make my_exe for GNU make, with the appropriate invocations of the
configured compiler to produce an executable my_exe from the two source files main.cpp and
utilities.cpp.
By default, all executable targets are added to the builtin all target (all for GNU make, BUILD_ALL
for MSVC).
To exclude an executable from being built with the default all target, one can add the optional
parameter EXCLUDE_FROM_ALL right after the target name:
Libraries
To create an build target that creates an library, use the add_library command:
add_library(my_lib lib.cpp)
The CMake variable BUILD_SHARED_LIBS controls whenever to build an static (OFF) or an shared (ON)
library, using for example cmake .. -DBUILD_SHARED_LIBS=ON. However, you can explicitly set to build
an shared or an static library by adding STATIC or SHARED after the target name:
The actual output file differs between systems. For example, an shared library on Unix systems is
usually called libmy_shared_library.so, but on Windows it would be my_shared_library.dll and
my_shared_library.lib.
https://riptutorial.com/ 10
Like add_executable, add EXCLUDE_FROM_ALL before the list of source files to exclude it from the all
target:
Libraries, that are designed to be loaded at runtime (for example plugins or applications using
something like dlopen), should use MODULE instead of SHARED/STATIC:
For example, on Windows, there won't be a import (.lib) file, because the symbols are directly
exported in the .dll.
https://riptutorial.com/ 11
Chapter 5: CMake integration in GitHub CI
tools
Examples
Configure Travis CI with stock CMake
language: cpp
compiler:
- gcc
before_script:
# create a build folder for the out-of-source build
- mkdir build
# switch to build directory
- cd build
# run cmake; here we assume that the project's
# top-level CMakeLists.txt is located at '..'
- cmake ..
script:
# once CMake has done its job we just build using make as usual
- make
# if the project uses ctest we can run the tests like this
- make test
The CMake version preinstalled on Travis is very old. You can use the official Linux binaries to
build with a newer version.
language: cpp
compiler:
- gcc
# the install step will take care of deploying a newer cmake version
install:
# first we create a directory for the CMake binaries
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir ${DEPS_DIR} && cd ${DEPS_DIR}
# we use wget to fetch the cmake binaries
- travis_retry wget --no-check-certificate https://cmake.org/files/v3.3/cmake-3.3.2-Linux-
x86_64.tar.gz
https://riptutorial.com/ 12
# this is optional, but useful:
# do a quick md5 check to ensure that the archive we downloaded did not get compromised
- echo "f3546812c11ce7f5d64dc132a566b749 *cmake-3.3.2-Linux-x86_64.tar.gz" > cmake_md5.txt
- md5sum -c cmake_md5.txt
# extract the binaries; the output here is quite lengthy,
# so we swallow it to not clutter up the travis console
- tar -xvf cmake-3.3.2-Linux-x86_64.tar.gz > /dev/null
- mv cmake-3.3.2-Linux-x86_64 cmake-install
# add both the top-level directory and the bin directory from the archive
# to the system PATH. By adding it to the front of the path we hide the
# preinstalled CMake with our own.
- PATH=${DEPS_DIR}/cmake-install:${DEPS_DIR}/cmake-install/bin:$PATH
# don't forget to switch back to the main build directory once you are done
- cd ${TRAVIS_BUILD_DIR}
before_script:
# create a build folder for the out-of-source build
- mkdir build
# switch to build directory
- cd build
# run cmake; here we assume that the project's
# top-level CMakeLists.txt is located at '..'
- cmake ..
script:
# once CMake has done its job we just build using make as usual
- make
# if the project uses ctest we can run the tests like this
- make test
https://riptutorial.com/ 13
Chapter 6: Compile features and C/C++
standard selection
Syntax
• target_compile_features(target PRIVATE|PUBLIC|INTERFACE feature1 [feature2 ...])
Examples
Compile Feature Requirements
add_library(foo
foo.cpp
)
target_compile_features(foo
PRIVATE # scope of the feature
cxx_constexpr # list of features
)
In the example, the features are declared PRIVATE: the requirements will be added to the target, but
not to its consumers. To automatically add the requirements to a target building against foo, PUBLIC
or INTERFACE should be used instead of PRIVATE:
target_compile_features(foo
PUBLIC # this time, required as public
cxx_constexpr
)
add_executable(bar
main.cpp
)
target_link_libraries(bar
foo # foo's public requirements and compile flags are added to bar
)
Wanted version for C and C++ can be specified globally using respectively variables
CMAKE_C_STANDARD (accepted values are 98, 99 and 11) and CMAKE_CXX_STANDARD (accepted values are
98, 11 and 14):
https://riptutorial.com/ 14
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
These will add the needed compile options on targets (e.g. -std=c++11 for gcc).
The variables must be set before target creation. The version can also be specified per-target:
set_target_properties(foo PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
)
https://riptutorial.com/ 15
Chapter 7: Configure file
Introduction
configure_file is a CMake function for copying a file to another location and modify its contents.
This function is very useful for generating configuration files with paths, custom variables, using a
generic template.
Remarks
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.
Examples
https://riptutorial.com/ 16
Generate a c++ configure file with CMake
If we have a c++ project that uses a config.h configuration file with some custom paths or
variables, we can generate it using CMake and a generic file config.h.in.
The config.h.in can be part of a git repository, while the generated file config.h will never be added,
as it is generated from the current environment.
#CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
SET(PROJ_NAME "myproject")
PROJECT(${PROJ_NAME})
SET(${PROJ_NAME}_DATA "" CACHE PATH "This directory contains all DATA and RESOURCES")
SET(THIRDPARTIES_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../thirdparties CACHE PATH "This
directory contains thirdparties")
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/common/config.h.in"
"${CMAKE_CURRENT_SOURCE_DIR}/include/config.h" )
If you have a cmake module . You can create a folder called in to store all config files.
For example,you have a project called FOO, you can create a FOO_config.h.in file like:
//===================================================================================
// CMake configuration file, based on SDL 2 version header
// ===================================================================================
#pragma once
#include <string>
#include <sstream>
namespace yournamespace
{
/**
* \brief Information the version of FOO_PROJECT in use.
*
* Represents the library's version as three levels: major revision
* (increments with massive changes, additions, and enhancements),
* minor revision (increments with backwards-compatible changes to the
https://riptutorial.com/ 17
* major revision), and patchlevel (increments with fixes to the minor
* revision).
*
* \sa FOO_VERSION
* \sa FOO_GetVersion
*/
typedef struct FOO_version
{
int major; /**< major version */
int minor; /**< minor version */
int patch; /**< update version */
} FOO_version;
/**
* \brief Macro to determine FOO version program was compiled against.
*
* This macro fills in a FOO_version structure with the version of the
* library you compiled against. This is determined by what header the
* compiler uses. Note that if you dynamically linked the library, you might
* have a slightly newer or older version at runtime. That version can be
* determined with GUCpp_GetVersion(), which, unlike GUCpp_VERSION(),
* is not a macro.
*
* \param x A pointer to a FOO_version struct to initialize.
*
* \sa FOO_version
* \sa FOO_GetVersion
*/
#define FOO_VERSION(x) \
{ \
(x)->major = FOO_MAJOR_VERSION; \
(x)->minor = FOO_MINOR_VERSION; \
(x)->patch = FOO_PATCHLEVEL; \
}
/**
* This macro turns the version numbers into a numeric value:
* \verbatim
(1,2,3) -> (1203)
\endverbatim
*
* This assumes that there will never be more than 100 patchlevels.
*/
#define FOO_VERSIONNUM(X, Y, Z) \
((X)*1000 + (Y)*100 + (Z))
/**
* This is the version number macro for the current GUCpp version.
*/
#define FOO_COMPILEDVERSION \
FOO_VERSIONNUM(FOO_MAJOR_VERSION, FOO_MINOR_VERSION, FOO_PATCHLEVEL)
/**
* This macro will evaluate to true if compiled with FOO at least X.Y.Z.
*/
https://riptutorial.com/ 18
#define FOO_VERSION_ATLEAST(X, Y, Z) \
(FOO_COMPILEDVERSION >= FOO_VERSIONNUM(X, Y, Z))
// Paths
#cmakedefine FOO_PATH_MAIN "@FOO_PATH_MAIN@"
This file will create a FOO_config.h in the install path, with a variable defined in c FOO_PATH_MAIN from
cmake variable. To generate it you need to include in file in your CMakeLists.txt,like this (set paths
and variables):
That file will contain the data from template, and variable with your real path, for example:
// Paths
#define FOO_PATH_MAIN "/home/YOUR_USER/Respositories/git/foo_project"
https://riptutorial.com/ 19
Chapter 8: Create test suites with CTest
Examples
Basic Test Suite
The macro enable_testing() does a lot of magic. First and foremost, it creates a builtin target test
(for GNU make; RUN_TESTS for VS), which, when run, executes CTest.
The call to add_test() finally registers an arbitrary executable with CTest, thus the executable gets
run whenever we call the test target.
Now, build the project as usual and finally run the test target
https://riptutorial.com/ 20
Chapter 9: Custom Build-Steps
Introduction
Custom build steps are useful to run custom targets in your project build or for easily copying files
so you don't have to do it manually (maybe dlls?). Here I'll show you two examples, the first is for
copying dlls (in particular Qt5 dlls) to your projects binary directory (either Debug or Release) and
the second is for running a custom target (Doxygen in this case) in your solution (if you're using
Visual Studio).
Remarks
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.
Examples
Qt5 dll copy example
So let's say you have a project that depends on Qt5 and you need to copy the relevant dlls to your
build directory and you don't want to do it manually; you can do the following:
cmake_minimum_required(VERSION 3.0)
project(MyQtProj LANGUAGES C CXX)
find_package(Qt5 COMPONENTS Core Gui Widgets)
#...set up your project
So now everytime you build your project, if the target dlls have changed that you want to copy,
https://riptutorial.com/ 21
then they will be copied after your target (in this case the main executable) is built (notice the
copy_if_different command); otherwise, they will not be copied.
Additionally, note the use of generator expressions here. The advantage with using these is that
you don't have to explicitly say where to copy dlls or which variants to use. To be able to use these
though, the project you're using (Qt5 in this case) must have imported targets.
If you're building in debug, then CMake knows (based on the imported target) to copy the
Qt5Cored.dll, Qt5Guid.dll, and Qt5Widgetsd.dll to the Debug folder of you build folder. If you're
building in release, then the release versions of the .dlls will be copied to the release folder.
You can also create a custom target to run when you want to perform a particular task. These are
typically executables that you run to do different things. Something that may be of particular use is
to run Doxygen to generate documentation for your project. To do this you can do the following in
your CMakeLists.txt (for the sake of simplicity we'll contiue our Qt5 project example):
cmake_minimum_required(VERSION 3.0)
project(MyQtProj LANGUAGES C CXX)
find_package(Qt5 COMPONENTS Core Gui Widgets)
#...set up your project
if(DOXYGEN_FOUND)
# create the output directory where the documentation will live
file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR})
# configure our Doxygen configuration file. This will be the input to the doxygen
# executable
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
# now add the custom target. This will create a build target called 'DOCUMENTATION'
# in your project
ADD_CUSTOM_TARGET(DOCUMENTATION
COMMAND ${CMAKE_COMMAND} -E echo_append "Building API Documentation..."
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR}
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
https://riptutorial.com/ 22
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E echo "Done."
WORKING_DIRECTORY ${DOXYGEN_OUTPUT_DIR})
endif(DOXYGEN_FOUND)
Now when we create our solution (again assuming you're using Visual Studio), you'll have a build
target called DOCUMENTATION that you can build to regenerate your project's documentation.
https://riptutorial.com/ 23
Chapter 10: Functions and Macros
Remarks
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.
Examples
Simple Macro to define a variable based on input
macro(set_my_variable _INPUT)
if("${_INPUT}" STREQUAL "Foo")
set(my_output_variable "foo")
else()
set(my_output_variable "bar")
endif()
endmacro(set_my_variable)
set_my_variable("Foo")
message(STATUS ${my_output_variable})
will print
-- foo
while
set_my_variable("something else")
message(STATUS ${my_output_variable})
will print
-- bar
macro(set_custom_variable _OUT_VAR)
set(${_OUT_VAR} "Foo")
endmacro(set_custom_variable)
Use it with
https://riptutorial.com/ 24
set_custom_variable(my_foo)
message(STATUS ${my_foo})
-- Foo
https://riptutorial.com/ 25
Chapter 11: Hierarchical project
Examples
Simple approach without packages
Example that builds an executable (editor) and links a library (highlight) to it. Project structure is
straightforward, it needs a master CMakeLists and a directory for each subproject:
CMakeLists.txt
editor/
CMakeLists.txt
src/
editor.cpp
highlight/
CMakeLists.txt
include/
highlight.h
src/
highlight.cpp
The master CMakeLists.txt contains global definitions and add_subdirectory call for each
subproject:
cmake_minimum_required(VERSION 3.0)
project(Example)
add_subdirectory(highlight)
add_subdirectory(editor)
CMakeLists.txt for the library assigns sources and include directories to it. By using
target_include_directories() instead of include_directories() the include dirs will be propagated to
library users:
cmake_minimum_required(VERSION 3.0)
project(highlight)
add_library(${PROJECT_NAME} src/highlight.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC include)
CMakeLists.txt for the application assigns sources and links the highlight library. Paths to
hightlighter's binary and includes are handled automaticaly by cmake:
cmake_minimum_required(VERSION 3.0)
project(editor)
add_executable(${PROJECT_NAME} src/editor.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC highlight)
https://riptutorial.com/ 26
Chapter 12: Packaging and Distributing
Projects
Syntax
• # Package a build directory
pack [PATH]
• # Use a specific generator
cpack -G [GENERATOR] [PATH]
• # Provide optional overrides
• cpack -G [GENERATOR] -C [CONFIGURATION] -P [PACKAGE NAME] -R [PACKAGE
VERSION] -B [PACKAGE DIRECTORY] --vendor [PACKAGE VENDOR]
Remarks
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.
# Required headers
cmake(3.0)
Examples
Creating a package for a built CMake project
To create a redistributable package (e.g. a ZIP archive or setup program), it's usually enough to
simply invoke CPack using a syntax very similar to calling CMake:
cpack path/to/build/directory
https://riptutorial.com/ 27
Depending on the environment this will gather all required/installed files for the project and put
them into a compressed archive or self-extracting installer.
To create a package using a specific format, it is possible to pick the Generator to be used.
cpack -G 7Z .
Using this command line would package the built project in the current directory using the 7-Zip
archive format.
At the time of writing, CPack version 3.5 supports the following generators by default:
If no explicit generator is provided, CPack will try to determine the best available depending on the
actual environment. For example, it will prefer creating a self-extracting executable on Windows
and only create a ZIP archive if no suitable toolset is found.
https://riptutorial.com/ 28
Chapter 13: Search and use installed
packages, libraries and programs
Syntax
• find_package(pkgname [version] [EXACT] [QUIET] [REQUIRED])
• include(FindPkgConfig)
• pkg_search_module(prefix [REQUIRED] [QUIET] pkgname [otherpkg...])
• pkg_check_modules(prefix [REQUIRED] [QUIET] pkgname [otherpkg...])
Parameters
Parameter Details
version Minimum version of the package defined by a major number and optionally
(optional) a minor, patch and tweak number, in the format major.minor.patch.tweak
EXACT
Specify that the version specified in version is the exact version to be found
(optional)
REQUIRED Automatically throws an error and stop the process if the package is not
(optional) found
QUIET
The function won't send any message to the standard output
(optional)
Remarks
• The find_package way is compatible on all platform, whereas the pkg-config way is available
only on Unix-like platforms, like Linux and OSX.
• A full description of the find_package numerous parameters and options can be found in the
manual.
• Even though it is possible to specify many optional parameters such as the version of the
package, not all Find modules properly uses all those parameters. If any undefined
behaviour occur, it could be necessary to find the module in CMake's install path and fix or
understand its behaviour.
Examples
Use find_package and Find.cmake modules
https://riptutorial.com/ 29
The default way to find installed packages with CMake is the use the find_package function in
conjunction with a Find<package>.cmake file. The purpose of the file is to define the search rules for
the package and set different variables, such as <package>_FOUND, <package>_INCLUDE_DIRS and
<package>_LIBRARIES.
Many Find<package>.cmake file are already defined by default in CMake. However, if there is no file
for the package you need, you can always write your own and put it inside
${CMAKE_SOURCE_DIR}/cmake/modules (or any other directory if CMAKE_MODULE_PATH was overridden)
A list of default modules can be found in the manual (v3.6). It is essential to check the manual
according to the version of CMake used in the project or else there could be missing modules. It is
also possible to find the installed modules with cmake --help-module-list.
cmake_minimum_required(2.8 FATAL_ERROR)
project("SDL2Test")
include_directories(${SDL2_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES})
On Unix-like operating systems, it is possible to use the pkg-config program to find and configure
packages that provides a <package>.pc file.
• pkg_search_module, which checks for the package and uses the first available.
• pkg_check_modules, which check for all the corresponding packages.
Here's a basic CMakeLists.txt that uses pkg-config to find SDL2 with version above or equal to
2.0.1:
cmake_minimum_required(2.8 FATAL_ERROR)
project("SDL2Test")
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2>=2.0.1)
include_directories(${SDL2_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES})
Read Search and use installed packages, libraries and programs online:
https://riptutorial.com/ 30
https://riptutorial.com/cmake/topic/6752/search-and-use-installed-packages--libraries-and-
programs
https://riptutorial.com/ 31
Chapter 14: Test and Debug
Examples
General approach to debug when building with Make
$ make
Launch it instead with make VERBOSE=1 to see the commands executed. Then directly run the linker
or compiler command that you'll see. Try to make it work by adding necessary flags or libraries.
Then figure out what to change, so CMake itself can pass correct arguments to the compiler/linker
command:
• what to change in the system (what libraries to install, which versions, versions of CMake
itself)
• if previous fails, what environment variables to set or parameters to pass to CMake
• otherwise, what to change in the CMakeLists.txt of the project or the library detection scripts
like FindSomeLib.cmake
To help in that, add message(${MY_VARIABLE}) calls into CMakeLists.txt or *.cmake to debug variables
that you want to inspect.
Once a CMake project is initialized via project(), the output verbosity of the resulting build script
can be adjusted via:
CMAKE_VERBOSE_MAKEFILE
This variable can be set via CMake's command line when configuring a project:
For GNU make this variable has the same effect as running make VERBOSE=1.
Note: The shown CMake error messages already include the fix for "non-standard" library/tool
installation paths. The following examples just demonstrate more verbose CMake find_package()
outputs.
https://riptutorial.com/ 32
CMake internally supported Package/Module
If the following code (replace the FindBoost module with your module in question)
cmake_minimum_required(VERSION 2.8)
project(FindPackageTest)
find_package(Boost REQUIRED)
Unable to find the Boost header files. Please set BOOST_ROOT to the root
directory containing Boost or BOOST_INCLUDEDIR to the directory containing
Boost's headers.
And you're wondering where it tried to find the library, you can check if your package has an _DEBUG
option like the Boost module has for getting more verbose output
$ cmake -D Boost_DEBUG=ON ..
cmake_minimum_required(VERSION 2.8)
project(FindPackageTest)
find_package(Xyz REQUIRED)
Could not find a package configuration file provided by "Xyz" with any of
the following names:
XyzConfig.cmake
xyz-config.cmake
And you're wondering where it tried to find the library, you can use the undocumented
https://riptutorial.com/ 33
CMAKE_FIND_DEBUG_MODE global variable for getting a more verbose output
$ cmake -D CMAKE_FIND_DEBUG_MODE=ON ..
https://riptutorial.com/ 34
Chapter 15: Using CMake to configure
preproccessor tags
Introduction
The use of CMake in a C++ project if used correctly can allow the programmer to focus less on the
platform, program version number and more on the actual program itself. With CMake you can
define preprocessor tags that allow for easy checking of which platform or any other preprocessor
tags you might need in the actual program. Such as the version number which could be leveraged
in a log system.
Syntax
• #define preprocessor_name "@cmake_value@"
Remarks
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.
Examples
Using CMake to define the version number for C++ usage
The possibilities are endless. as you can use this concept to pull the version number from your
build system; such as git and use that version number in your project.
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(project_name VERSION "0.0.0")
...
config.h.in
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
https://riptutorial.com/ 35
#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VER "@PROJECT_VERSION@"
#define PROJECT_VER_MAJOR "@PROJECT_VERSION_MAJOR@"
#define PROJECT_VER_MINOR "@PROJECT_VERSION_MINOR@"
#define PTOJECT_VER_PATCH "@PROJECT_VERSION_PATCH@"
#endif // INCLUDE_GUARD
main.cpp
#include <iostream>
#include "config.h"
int main()
{
std::cout << "project name: " << PROJECT_NAME << " version: " << PROJECT_VER << std::endl;
return 0;
}
output
https://riptutorial.com/ 36
Chapter 16: Variables and Properties
Introduction
The simplicity of basic CMake variables belies the complexity of the full variable syntax. This page
documents the various variable cases, with examples, and points out the pitfalls to avoid.
Syntax
• set(variable_name value [CACHE type description [FORCE]])
Remarks
Variable names are case-sensitive. Their values are of type string. The value of a variable is
referenced via:
${variable_name}
"${variable_name}/directory"
Examples
Cached (Global) Variable
In case a cached variable is already defined in the cache when CMake processes the respective
line (e.g. when CMake is rerun), it is not altered. To overwrite the default, append FORCE as the last
argument:
set(my_global_overwritten_string "foo"
CACHE STRING "this is overwritten each time CMake is run" FORCE)
Local Variable
By default, a local variable is only defined in the current directory and any subdirectories added
https://riptutorial.com/ 37
through the add_subdirectory command.
2. use PARENT_SCOPE, which will make it available in the parent scope. The parent scope is either
the CMakeLists.txt file in the parent directory or caller of the current function.
Technically the parent directory will be the CMakeLists.txt file that included the current file via
the add_subdirectory command.
It's important to know how CMake distinguishes between lists and plain strings. When you write:
you create a string with the value "a b c". But when you write this line without quotes:
set(VAR a b c)
You create a list of three items instead: "a", "b" and "c".
Lists can be operated on with the list() command, which allows concatenating lists, searching
them, accessing arbitrary elements and so on (documentation of list()).
set(VAR a b c)
is equivalent to
set(VAR "a;b;c")
Therefore, to concatenate lists one can also use the set() command:
set(NEW_LIST "${OLD_LIST1};${OLD_LIST2})"
set(VAR TRUE)
set(VAR "main.cpp")
set(VAR1 ${VAR2})
But CMake does also know global "cached variables" (persisted in CMakeCache.txt). And if normal
and cached variables of the same name exist in the current scope, normal variables do hide the
cached ones:
https://riptutorial.com/ 38
cmake_minimum_required(VERSION 2.4)
project(VariablesTest)
set(VAR "NORMAL")
message("VAR = ${VAR}")
VAR = CACHED-init
VAR = NORMAL
VAR = CACHED
VAR = CACHED
VAR = NORMAL
VAR = CACHED
Note: The FORCE option does also unset/remove the normal variable from the current scope.
1. An value in your code should be modifiable from your project's user e.g. with the cmakegui,
ccmake or with cmake -D ... option:
CMakeLists.txt / MyToolchain.cmake
Command Line
$ cmake -D LIB_A_PATH:PATH="/some/other/path" ..
This does pre-set this value in the cache and the above line will not modify it.
CMake GUI
In the GUI the user first starts the configuration process, then can modify any cached value
https://riptutorial.com/ 39
and finishes with starting the build environment generation.
2. Additionally CMake does cache search/test/compiler identification results (so it does not
need to do it again whenever re-running the configuration/generation steps)
That must add flags to compile and link, and use after execute the program:
gprof ./my_exe
https://riptutorial.com/ 40
Credits
S.
Chapters Contributors
No
Add Directories to
2 Compiler Include kiki, Torbjörn
Path
CMake integration in
5 ComicSansMS
GitHub CI tools
Compile features
6 and C/C++ standard wasthishelpful
selection
Functions and
10 Torbjörn
Macros
Packaging and
12 Mario, Meysam, Neui
Distributing Projects
Using CMake to
15 JVApen, Matthew
configure
https://riptutorial.com/ 41
preproccessor tags
https://riptutorial.com/ 42