Quick CMake tutorial
This tutorial will guide you through the process of creating and developing a simple CMake project in CLion. Step by step, you will learn the basics of CMake as a build system, along with CMake-specific IDE settings and actions.
1. Simple CMake project
CMake is a meta build system that uses scripts called CMakeLists to generate build files for a specific environment (for example, makefiles on Unix machines).
When you create a new CMake project in CLion, a CMakeLists.txt file is generated automatically under the project root.
Start a sample CMake project
Select
from the main menu.Select C++ Executable on the left-hand pane.
In our example, the project name is cmake_testapp and the selected language standard in C++17.
Click Create.
CLion will generate a stub project with a single source file main.cpp and a CMakeLists.txt script under the root.
The automatically generated CMakeLists.txt contains the following commands:
Command
Description
cmake_minimum_required(VERSION 3.26)
Specifies the minimum required version of CMake, as set in the default toolchain. For most cases, if CMake executable was not changed intentionally, this is the bundled CMake version.
project(cmake_testapp)
Defines the project name according to what we provided during project creation.
set(CMAKE_CXX_STANDARD 17)
Sets the CMAKE_CXX_STANDARD variable to the value of 17, as we selected when creating the project.
add_executable(cmake_testapp main.cpp)
Adds the cmake_testapp executable target to be built from main.cpp. We'll get into targets further below.
Click on the left-hand toolbar of the IDE to open the CMake tool window, where you can check the progress and status of project load:
2. CMake targets and CLion configurations
Target is an executable or a library to be built using a CMake script. You can define multiple build targets in a single script.
For now, our test project has only one build target, cmake_testapp
. Upon the first project loading, CLion automatically adds a run/debug configuration associated with this target:
In the switcher, click Edit Configurations to view the details. The target name and the executable name are the same as specified in CMakeLists.txt:
Notice the Before launch area of this dialog. Build is set as a before launch step by default. So we can use this configuration not only to debug or run our target, but also to perform the build. For more information about various build actions available in CLion, check out Build actions.
3. Adding files to existing targets
Let’s create a new source file general.cpp and add it to the cmake_testapp
target.
Right-click the root folder in the Project tree and select New | C/C++ Source File:
Set the Add to targets checkbox:
Click OK, and the new file will be added to the
add_executable
command:
4. Adding new targets
Now let's add two more files and create an executable and a library target for them.
New executable target
Right-click the root folder in the Project tree and select New | C/C++ Source File again.
Set the file name (calc in our example).
In the Add to targets field, clear the cmake_testapp checkbox.
Click the Add new target link:
Specify the target name (
cmake_testapp_calc
) and click Add:The newly created target will appear in the list.
Make sure that only the
cmake_testapp_calc
target is selected:Click OK.
CLion will add a new
add_executable
command to CMakeLists.txt and reload the project:After reload, a new configuration will appear in the configuration switcher:
New library target
Right-click the root folder in the Project tree and select New | C/C++ Source File again.
Provide the file name (calc_lib).
Clear the checkboxes in the Add to targets field.
Click Add new target.
In the drop-down list, select
add_library
:Set the target name (
cmake_testapp_lib
) and click Add.The newly created target will appear in the list.
Make sure that other targets' checkboxes are cleared.
Set the Create an associated header checkbox to also add a header file, calc_lib.h.
Click OK.
CLion will add a
add_library
command to CMakeLists.txt and reload the project:Similarly to the case of executable targets, CLion automatically creates configurations for library targets:
However, this is a non-executable configuration, so if you try to run or debug it, you will get the Executable not specified error message:
To obtain the library file, you need to build this configuration. Select it in the switcher and press Ctrl+F9 or click the build icon:
As the result, the libcmake_testapp_lib.a file will appear in the cmake-build-debug folder.
5. Reloading the project
Let's introduce some changes in CMakeLists.txt manually. For example, add STATIC
to the declaration of the library target:
When we make changes in CMakeLists.txt, CLion shows the icon suggesting to reload the project. Click it or press the shortcut:
6. CMake presets and CLion CMake profiles
To configure and share CMake options for your project, you can use CMake presets, CLion's CMake profiles, or both.
CMake Profiles have many settings in common with CMake Presets and are also shareable via VCS. The major difference is that profiles reference CLion toolchains, which contain information that is not present and not needed in CMake presets (like the debugger or environment settings).
CMake presets
CMake Presets are a way to configure and share CMake options using two files:
CMakePresets.json for project-wise builds. This file can be shared via VCS.
CMakeUserPresets.json for developers' own local builds. This file should not be checked into VCS.
Both of these files have the same format and should be located in the project's root directory.
CMake profiles
A profile includes toolchain and build type, as well as CMake options such as generators and environment variables. You can configure multiple profiles for your project in order to, for example, use different compilers or to build targets with differing settings.
See the next chapter for an example of adding a profile for Release build.
7. Build types
All the Run/Debug configurations created so far were Debug configurations, which is the default build type of the CMake profile that was automatically configured for our project.
For example, let's separate the Debug and Release builds. For this, add () a new CMake profile in Release:
and set its build type toNotice the Build directory field that specifies the location of build results. The default folders are cmake-build-debug for Debug profiles and cmake-build-release for Release profiles. You can always set other locations of your choice.
Save the profile, and it will appear in the switcher:
8. Adding include directories
To use additional headers located in separate directories, you need to add them either to all targets or to some specific ones.
As an example, let's create three directories under the project root: includes, includes/general, and includes/math. Use the option in the project tree context menu.
Open CMakeLists.txt and add the following commands:
target_include_directories (cmake_testapp_lib PUBLIC includes/math) target_include_directories (cmake_testapp_lib PUBLIC includes/general)These two commands make the headers located in general and math available from the sources of the
cmake_testapp_lib
target.For example, if we place a header called header_math.h inside the includes/math folder, we can then include it from calc_lib.cpp using
#include "header_math.h"
.
9. Linking libraries
Static libraries
On step 4, we created a static library called cmake_testapp_lib
(the default filename is libcmake_testapp_lib.a).
Now let's see how this library can be linked to our project. For convenience, we will create and use a separate folder for it.
Create a lib directory under the project root.
Copy libcmake_testapp_lib.a from its default location, which is cmake-build-debug, to the lib folder.
Add the following commands to link this library to the cmake_testapp target:
find_library(TEST_LIBRARY cmake_testapp_lib lib) target_link_libraries(cmake_testapp LINK_PUBLIC ${TEST_LIBRARY})find_library provides the full path to the library,
which we then pass directly into the target_link_libraries command via the
${TEST_LIBRARY}
variable.
Dynamic libraries
To illustrate the case of shared (dynamic) libraries, we will take the example of using LibPNG, a C library for reading and writing Portable Network Graphics (PNG) files.
Install the library package using vcpkg
CLion integrates with vcpkg, a package manager for C/C++. We will use it to quickly install the library right from the IDE.
Follow this instruction to install vcpkg.
In the vcpkg tool window, search for libpng:
Click Install in the right-hand pane and wait for installation to complete.
Add the library to CMakeLists.txt
Open the CMakeLists.txt file and add the following commands:
find_package(PNG REQUIRED) include_directories(${PNG_INCLUDE_DIR}) target_link_libraries(cmake_testapp PRIVATE ${PNG_LIBRARY})To check whether the library is linked correctly, try including one of the library headers to main.cpp:
For example, include png.h. You can then press Ctrl+B to to open this file:
10. CMake debug
In case there are errors or unwanted behaviour during CMake configuration, you can debug the CMake script similarly to other code in your project.
Place breakpoints in your CMakeLists.txt file or files.
Open the top-level CMakeLists.txt, click the gutter icon next to the first command, and select Debug:
CLion will start a CMake debug session:
For further information, refer to CMake debug features.
11. Tips on editing CMakeLists.txt
CLion provides code insight features to help you work with CMake scripts effectively. For example:
Structure view for CMake shows variables, functions, macros, and targets used your script. To open it, press Alt+7 (for the tool window) or Ctrl+F12 (for the popup).
Code completion works for most of the elements in your CMakeLists.txt, including the arguments of commands like
find_package()
:Quick Documentation popup helps you get more information on code elements. To invoke it, use mouse hover or press Ctrl+Q.
You can view quick documentation even for completion suggestions:
You can adjust the color and font scheme for CMake files in
:
12. Working with CTest
This chapter gives a simple example of how to use CTest, a framework for compiling and running tests as part of the CMake build process. You can find a general description of the framework in CTest support.
Add CTest to the sample project
Create a ctest directory under the project root.
Add the following files to the ctest directory:
A source file addvalues_zero.cpp. Don't link this file with any CMake target for now.
A header file assert_macro.h. Don't link this file with any CMake target for now.
A CMakeLists.txt script.
Add the following lines to ctest/CMakeLists.txt:
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) add_executable(ctest_exe_addvalues_zero addvalues_zero.cpp) target_link_libraries(ctest_exe_addvalues_zero LINK_PUBLIC cmake_testapp_lib) add_test(NAME ctest_addvalues_zero COMMAND ctest_exe_addvalues_zero) set_tests_properties(ctest_addvalues_zero PROPERTIES PASS 0)The first line states the minimum supported version of CTest, which corresponds to the version of CMake, 3.14.
We are using the add_test command here to register the
ctest_exe_addvalues_zero
executable with CTest.Next, we need to enable CTest and declare the subproject in the top-level CMakeLists.txt:
enable_testing() add_subdirectory(ctest)The enable_testing command creates a built-in target
test
which will execute CTest.Reload the project.
Add the code to be tested
Let's prepare a code piece to be tested with CTest.
In calc_lib.cpp, add a simple function
int add_values (int a, int b) { return a+b;}In the associated header, calc_lib.h, add the function declaration:
int add_values (int a, int b);
Add the code inside the test sources
assert_macro.h:
#include <iostream> #include <sstream> #define assertEqual( ... ) \ do { \ if( !( __VA_ARGS__ ) ) { \ std::cerr << "Unit test assert [ " \ << ( #__VA_ARGS__ ) \ << " ] failed in line [ " \ << __LINE__ \ << " ] file [ " \ << __FILE__ << " ]" \ << std::endl; \ err_code = 1; \ } \ } while( false )addvalues_zero.cpp:
#include "assert_macro.h" #include "../calc_lib.h" int test_addvalues_zero() { int err_code = 0; assertEqual (add_values(0, 0) == 0); assertEqual (add_values(-5, 5) == 0); return err_code; } int main() { return test_addvalues_zero(); }
Edit the CTest configuration
In the main menu, go to
.Under the CTest Application node, you will find the automatically created All CTest configuration.
Since the code to be tested is located in the
ctest_exe_addvalues_zero
executable, we need to select that executable as a build target in the configuration settings:Let's also check the Test list to run field. Click the pen icon to open the List of Available Tests dialog, where we can view and adjust the set of tests:
Run the CTest configuration and explore the results
Select All CTest in the configuration switcher and click or press Shift+F10.
Find results in the Test Runner window:
13. Useful links
To dig deeper into CMake in CLion, learn how to: