CLion 2023.1 Help

Quick CMake tutorial

This tutorial will guide you through the process of creating and developing a simple CMake project. Step by step, we will learn the basics of CMake as a build system, along with the CLion settings and actions for CMake projects.

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 automatically generated under the project root.

Let’s create a new CMake project in CLion.

  1. Select File | New Project from the main menu.

  2. Choose C++ Executable on the left-hand pane. In our example, the project name is cmake_testapp and the selected language standard in C++17.

    Creating a new CMake project
  3. We get the default project with a single source file main.cpp and the automatically created root CMakeLists.txt containing the following commands:

    CMakeLists.txt in a stub CMake project

    Command

    Description

    cmake_minimum_required(VERSION 3.24)

    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.

  4. In the CMake tool window, you can check the progress and status of project load. To access it, call View | Tool Windows | CMake or switch to it in the tool windows bar:

    CMake tool window

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:

Default configuration for a new CMake project

Click Edit Configurations in the switcher or select Run | Edit Configurations from the main menu to view the details. The target name and the executable name are the same as specified in CMakeLists.txt:

Details of the default configuration for a new CMake project

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. To learn more about various build actions available in CLion, check out Build actions.

3. Adding files to targets

Let’s create a new source file general.cpp and add it to our cmake_testapp target.

  1. Right-click the root folder in the Project tree and select New | C/C++ Source File:

    Adding a source file
  2. Set the Add to targets checkbox to automatically add the file to an existing target:

    Adding a file to an existing target
  3. Click OK, and the new file will be added to the add_executable command:

    Source file added to add_executable

4. Adding targets and reloading the project

Now let’s add another source file calc.cpp and create new targets for it: first an executable, and then a library target.

New executable target

  1. Right-click the root folder in the Project tree and select New | C/C++ Source File again.

  2. Since our goal now is to create a new target, we need to clear the Add to targets checkbox:

    Adding a new file without adding it to an existing target
  3. After we click OK, CLion opens the new file and notifies us that it does not belong to any target:

    File not belonging to any of the project targets
  4. Let's declare a new target manually in the CMakeLists.txt. Note that CLion treats CMake scripts as regular code files, so you can use code assistance features like syntax highlighting, auto-completion, and navigation (see CMake editing tips below).

    Code completion in CMake script
  5. When we make changes in CMakeLists.txt manually, CLion shows notification that the project needs to be reloaded:

    Reload the CMake project after adding a new target

    We can either reload the project once (Reload changes) or enable automatic reload to let CLion silently apply all the changes in CMakeLists.txt.

    The option for enabling/disabling auto-reload is also available in Settings | Build, Execution, Deployment | CMake.

    After reload, you can find a new configuration in the list:

    Configuration for the newly added target

New library target

Up to this point, the targets we added were executables, and we used add_executable to declare them. For library targets, we need another command: add_library. As an example, let's create a static library from the calc.cpp.

  1. Add the following line to the CMakeLists.txt script:

    add_library(test_library STATIC calc.cpp)
  2. Similarly to executable targets, CLion creates configurations for library targets:

    Configuration for the newly added library target

    However, this is a non-executable configuration, so if we attempt to run or debug it, we will get the App general balloon error Executable not specified error message:

    Executable not specified error
  3. To get the library file, we need to build the test_library target. For this, switch to the corresponding configuration and press App actions compile, or call Build | Build "test_library":

    Building a library target

    The libtest_library.a file will appear in the cmake-build-debug folder:

    Library artifact

5. 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.

      6. 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, to separate the Debug and Release builds, we can add App general inline add hover a new CMake profile in Settings | Build, Execution, Deployment | CMake and set its build type to Release:

      Adding a release CMake profile

      Notice 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 App actions menu open other locations of your choice.

      Now the Run/Debug configuration switcher shows two available profiles:

      CMake profiles in the configuration switcher

      7. Adding include directories

      In order to use additional headers located in separate directories, we need to add them either to all the targets or to some specific ones.

      1. As an example, create three directories under the project root: includes, includes/general, includes/math.

      2. Write the following commands in CMakeLists.txt:

        target_include_directories (cmake_testapp_calc PUBLIC includes/math) target_include_directories (cmake_testapp_calc PUBLIC includes/general)
      3. These two commands make the headers located in general and math available for including from the sources of the cmake_testapp_calc target.

        For example, if we place a header called header_math.h inside the includes/math folder, we can then include it from calc.cpp using #include "header_math.h":

        Including a header

      Static libraries

      On step 3, we created a static library called test_library (the default filename is libtest_library.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 the library.

      1. Create a lib directory under the project root.

      2. Copy libtest_library.a from its default location (which is cmake-build-debug) to the lib folder.

      3. We need two commands to link our static library to the cmake_testapp target:

        find_library(TEST_LIBRARY test_library lib) target_link_libraries(cmake_testapp LINK_PUBLIC ${TEST_LIBRARY})
        Linking a static library

      Dynamic libraries (Boost.Test example) and CMake subprojects

      To illustrate linking dynamic libraries, we will take an example of using the Boost.Test framework.

      Code to be tested

      Let's prepare a code piece to be tested using Boost.Test.

      1. In calc.cpp, add a simple function int add_values (int a, int b) { return a+b;}

      2. Create the associated header named calc.h and add the function declaration there: int add_values (int a, int b);

      Adding a function to be tested

      Add a subproject for tests

      As our project gets more complicated, the root CMakeLists.txt file can become difficult to maintain. To avoid this, and to build a transparent project structure, we will extract tests into a subproject with its own CMakeLists.txt.

      1. Create a new directory and call it test.

      2. In the test directory, create a new source file and call it tests.cpp.

      3. Right-click the test directory once again and select New | CMakeLists.txt.

        CMake subproject for tests

      Initially, the subdirectory test/CMakeLists.txt script is empty. We will start filling it up by inserting a live template for Boost with libs.

      1. Press Control+J or click Code | Insert Live Template, and choose boost_with_libs:

        Boost with libs template

        The inserted code will look like this:

        Boost with libs template code
      2. Manually adjust the inserted code to the following:

        set(Boost_USE_STATIC_LIBS OFF) #enable dynamic linking # search for unit_test_framework find_package(Boost REQUIRED COMPONENTS unit_test_framework) include_directories(${Boost_INCLUDE_DIR}) # create a cmake_testapp_boost target from test.cpp add_executable(cmake_testapp_boost tests.cpp) # link Boost libraries to the new target target_link_libraries(cmake_testapp_boost ${Boost_LIBRARIES}) # link Boost with code library target_link_libraries(cmake_testapp_boost test_library)

      3. To make the test target, cmake_testapp_boost, available for the main build, we need to place the add_subdirectory(test) command in the root CMakeLists.txt.

        This command, when placed in the root CMake script, declares a subproject test that has its own CMakeLists.txt.

        CMake subproject added

      Boost.Test run/debug configuration

      After reloading the changes in both CMakeLists.txt files, CLion creates a run/debug configuration for the cmake_testapp_boost target. However, this is a regular CMake configuration, and it does not cover test specifics.

      There is a dedicated configuration with test runner called Boost.Test. CLion creates this type of configuration when you run Boost tests using the gutter menu, or you can always create it manually.

      1. Click the gutter icon next to BOOST_AUTO_TEST_SUITE and select Run:

        Running Boost test using the gutter menu
      2. CLion will run the test suit and show the results in a tree view with the tests' output, status, and duration:

        Boost test runner

        Now there is a new temporary configuration in the list: Temporary Boost configuration

      3. We can save (App actions menu saveall) this temporary configuration and modify it Run | Edit Configurations:

        Boost.Test run/debug configuration

      9. 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.

      1. Place breakpoints in your CMakeLists.txt file or files.

      2. Open the top-level CMakeLists.txt, click the gutter icon next to the first command, and select Debug:

        Starting a CMake debug session from gutter
        Debug hint in CMake tool window
      3. CLion will start a CMake debug session:

        CMake debug session

        See CMake debug features.

      10. 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 Control+F12 (for the popup).

        CMake script structure
      • Code completion works for most of the elements in your CMakeLists.txt, including the arguments of commands like find_package():

        Completion for find_package
      • Quick Documentation popup helps you get more information on code elements. To invoke it, use mouse hover or press Control+Q.

        You can view quick documentation even for completion suggestions:

        Quick documentation for completion suggestions
      • You can adjust the color and font scheme for CMake files in Settings | Editor | Color Scheme | CMake:

        Color scheme settings for CMake

      11. 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. Find general description of the framework in CTest support.

      Add CTest to the sample project

      1. Create a subdirectory inside test and call it ctest.

      2. Add two source files, addvalues_zero.cpp and addvalues_negpos.cpp, a header file (where we will place the assertion macro) assert_macro.h, and a CMakeLists.txt script:

        Adding a folder for CTest
      3. Add the following lines to ctest/CMakeLists.txt:

        cmake_minimum_required(VERSION 3.24 FATAL_ERROR) add_executable(ctest_exe_addvalues_zero addvalues_zero.cpp) add_executable(ctest_example_addvalues_negpos addvalues_negpos.cpp) add_test(ctest_addvalues_zero ctest_exe_addvalues_zero) add_test(ctest_addvalues_negpos ctest_example_addvalues_negpos)

        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 our executables, ctest_exe_addvalues_zero and ctest_example_addvalues_negpos, with CTest.

      4. Now we can place the actual 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" int test_addvalues_zero() { int err_code = 0; assertEqual (0+0 == 0); assertEqual ((-5)+5 == 0); return err_code; } int main() { return test_addvalues_zero(); }
        • addvalues_negpos.cpp:

          #include "assert_macro.h" int test_addvalues_negpos() { int err_code = 0; assertEqual ((-5)+10 == 5); assertEqual ((-10)+5 == -5); assertEqual (5+(10) == 5); //test to fail return err_code; } int main() { return test_addvalues_negpos(); }
      5. Next, we need to enable CTest and declare the subproject in the top-level CMakeLists.txt:

        enable_testing() add_subdirectory(test/ctest)

        The enable_testing command creates a built-in target test which will execute CTest.

      6. Reload the project.

      After the reload, CLion detects the tests and creates a ready-to-go All CTest configuration:

      All CTest configuration in the switcher

      If we run this configuration, the results will be shown in the Test Runner window, similarly to other supported testing frameworks:

      CTest results

      We can also use the gutter menu next to the add_test commands in ctest/CMakeLists.txt to run or debug our tests:

      Gutter menu to ctests

      In case of running/debugging a test via the gutter menu, CLion creates a temporary configuration, so if we go to Edit Configuration, we will find two automatically generated configurations of the CTest Application type:

      Automatically created CTest configurations

      Let's check the All CTest configuration. Click the pen icon next to the Test list to run field. This opens the List of Available Tests dialog, where we can change the set of tests:

      List of the available tests in CTest configuration

      12. Useful links

      To dig deeper into CMake in CLion, learn how to:

      Last modified: 11 January 2023