CMake is a family of tools which mainly serves to build cross-platform applications and libraries written in any of C family languages (C, C++, C#, Objective-C, CUDA).

It is not a compiler, or a construction tool though. Its goal is to generate a solution which will be used to build it. It’s a template consisting information about source files, dependencies and compilation settings that should be used to build a project no matter a platform it is built for or IDE it is used.

The best way to use CMake is via terminal, but many IDEs like CLion or Visual Studio Code integrates CMake into their pipeline.

Does it sound like magic? Only at the beginning. After setting it up for the first time everything becomes extra clear! Let’s check the basics.

Hello, world!

Let’s create a directory and name it CMakeTut. This will be a directory where our new project will be placed. Then, create a main.cpp file inside:

Simple code, nothing crazy. Now, inside the same directory, create a CMakeLists.txt file:

– The first line is not required but it is a good practice to determine what is a minimum version of installed CMake required to generate this project.
– The second line creates a project named CMakeTut.
– The third line says that CMakeTut will be an executable project and adds main.cpp file to the list of source files.

That’s all! This short template is enough to generate a solution. Now it’s time to actually generate it and build a program!

Building on Linux.

For Linux we will use Makefiles. To generate a solution type the following commands to the console:

This will generate a Unix Makefiles solution inside a newly created build directory. Next, run make command:

And finally, you can run a program!

Building on Windows

For Windows, assuming there is a Visual Studio 2017 installed, type the following commands in the console:

This will generate a Visual Studio 2017 solution. You  can open this solution in Visual Studio and simply build a program in it. You can also build it with MSBuild from command line:

As you can see you can tell MSBuild for which platform you want to build and with what configuration. Finally, you can run a program!

Changing output

By default a final executable will be stored in a directory from which the cmake has been called (so in our case – in build directory). To change that add the following command to CMakeLists.txt BEFORE the add_executable:

If you want to change a name of an executable app to not be the same as a project name, add the following command AFTER the add_executable

Adding more files

This is nice, but we’d like to add more files to the project. How to do it? Let’s add two files: math.h and math.cpp to the project directory:

math.h

math.cpp

Let’s use a Sum function in main.cpp

To tell CMake to compile math.h and math.cpp files add them to the add_executable command:

For greater readability you can write it in a different manner, like this:

You can imagine that this will be tedious with a project with a huge amount of files! There is a solution for that. Use recursive search for files. First, just for a convenience, move all source files to a new directory, let’s call it src. Then modify the add_executable command to look like this:

The file command creates a list of files called SRC_FILES which includes all cpp and files in src directory. The search is recursive, so it will get all files from all directories inside the src directory. Finally, the list is passed to the add_executable command.

Trace log

Sometimes you want to log some data to the screen. CMake gives you a message command, so if you want, for example, to check the value of a SRC_FILES list add the following command:

Debug vs Release

When using IDEs like Visual Studio or XCode you select the build configuration in project properties, but when you generate a Makefile solution the configuration must be set during solution generation. To do it you must pass a proper value to CMake when calling it:

You can use Debug, Release, RelWithDebInfo and MinSizeRel configurations.

Because if the CMAKE_BUILD_TYPE is not explicitly defined CMake will not set any additional flags. It is a good practice to set it to some default value in CMakeLists.txt

Selecting compiler

On Linux there are usually multiple compilers we can use to build a solution. If not explicitly specified, CMake will use the best compiler it found. To use a compiler of your choice you must set CC (C compiler) and CXX (C++ compiler) flags before running cmake, for example:

It is possible, but not recommended, to set compiler inside the CMakeLists.txt file as different users might want to use different compilers.

Building libraries

But what if we don’t want our project to be an executable but a library? We simply replace add_executable command with an add_library command! Notice that setting output directory changes too!

This will build a static library. If you want to build a shared library use the following commands:

Linking with static libraries

Let’s say we want to link our project against a static library. Consider we have a library and it’s located as described in the following tree.

After the add_executable has been called we need to create a library object and set path to its original file:

Add include directories:

And finally tell CMake we want to link against it:

Adding macro definitions

You can pass macro definitions to the preprocessor using the target_compile_definitions command:

When compiling such code:

The result of running program will be:

Setting up C++ standard and options

You can tell the compiler which standard of C++ you want to be used. If we want to use C++11 standard add the following command:

or

Currently available versions of C++ are 98, 11, 14 and 17.

As you can see the target_compile_options command can be used to pass specific options to the compiler like -Wall-Werror for GCC or /MTd for MSVC.

Another way to set compiler options is to set specific values of CMAKE_C_FLAGS, CMAKE_CXX_FLAGS and CMAKE_EXE_LINKER_FLAGS. Do it if you need to define specific flags for C compiler, C++ compiler and Linker separately.

Other useful tips

Get project directory

If you want to get the full path to the project directory you can use the CMAKE_CURRENT_SOURCE_DIR value.

Organize Solution

If you generate a project for Visual Studio of XCode you might notice that all files in project explorer have the same depth. Information about their directories has gone. You can fix this by using the following function:

Further reading

I think this is enough for the beginning. Except documentation and StackOverflow there are some pages worth reading. I hope this article helped you start learning CMake and believe me, you can do a lot of magic with it!