Modern CMake Tutorial

Resources

  • Modern CMake. book on Github
  • Modern Cmake chinese version. book on github
  • More Modern CMake - Deniz Bahadir- Meeting C++ 2018&2019
    • More Modern CMake: A great presentation from Meeting C++ 2018 that recommends CMake 3.12+. This talk makes calls CMake 3.0+ “Modern CMake” and CMake 3.12+ “More Modern CMake” Youtube Video
    • Oh No! More Modern CMake: The sequel to More Modern CMake. Youtube Video
    • Examples from slides is found here
  • This note is made based on the video in the link

Basic Knowledge

  • Build System Generators CMake parses a configuration file (CMakeLists.txt), but instead of directly build a project, it’ll generate another configuration file (makefile)
  • ** Build Systems**, like Make or Visual studio c++ will parse a configuration file (Makefile) that contains all the commands required to build a project based on the source files and other resources inside the project.

Some C++ files invoved in the tutorial

1
2
3
4
5
6
// file: main.cpp 
#include "foo.h"
int main(){
Foo foo;
foo.print();
}
1
2
3
4
5
6
// file: foo.h
#pragma once
class Foo{
public:
void print();
};
1
2
3
4
5
6
// file: foo.cpp
#include "foo.h"
#include <iostream>
void Foo::print(){
std::cout << "hello foo!"<<std::endl;
}

Pattern 1 - For a simple project

  • place all .h and .cpp files directly under the same folder (e.g. cmake_tutorial)

    1
    2
    3
    4
    📦cmake_tutorial
    ┣ 📜foo.cpp
    ┣ 📜foo.h
    ┗ 📜main.cpp
  • create a CMakeLists.txt under the same folder with source files and specify the name of cmake exctubale project as myProject

1
2
3
4
5
6
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(myProject VERSION 1.0)
add_executable(myProject main.cpp foo.cpp)
  • In terminal run cmake .command. This will generate some new files, and the most important one is maekfile. In the following, make command will run this file to build the project.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    cmake_tutorial
    ┣ 📂CMakeFiles
    ┣ 📜CMakeCache.txt
    ┣ 📜CMakeLists.txt
    ┣ 📜Makefile
    ┣ 📜cmake_install.cmake
    ┣ 📜foo.cpp
    ┣ 📜foo.h
    ┗ 📜main.cpp
  • In terminal run make command and new files are generated including a excutable file with the same name as the project (“myProject”) defined in the CMakeLists.txt file. Now you can run ./myProject in the terminal. The output like

    1
    2
    $ ./myProject
    hello foo!

Pattern 2 - move generated files to a debug folder

A better practice is to put all generated file into a folder like build or debug

  • run the follwing command in terminal
1
2
3
4
5
$ mkdir debug
$ cd debug
$ cmake ../
$ make
$ ./myProject
  • now all files generated are put into the debug folder
    1
    2
    3
    4
    5
    6
    make_tutorial
    ┣ 📂debug
    ┣ 📜CMakeLists.txt
    ┣ 📜foo.cpp
    ┣ 📜foo.h
    ┗ 📜main.cpp

Pattern 3 - Place header files in a seperate folder

  • The files are arranged like follow, debug folder is empty now.
    1
    2
    3
    4
    5
    6
    7
    📦cmake_tutorial
    ┣ 📂debug
    ┣ 📂include
    ┃ ┗ 📜foo.h
    ┣ 📜CMakeLists.txt
    ┣ 📜foo.cpp
    ┗ 📜main.cpp
  • In order to let foo.h known for main.cpp and foo.cpp, we need to add a header file directory in CMakeLists.txt:
1
target_include_directories(myProject PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
  • now we have CMakeLists.txt as below

    1
    2
    3
    4
    5
    6
    7
    8
    cmake_minimum_required(VERSION 3.10)
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    project(myProject VERSION 1.0)
    add_executable(myProject main.cpp foo.cpp)
    target_include_directories(myProject PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

  • run the follwing command in terminal

classical usage

1
2
3
$ cd debug
$ cmake ../ && make && ./myproject

New

1
2
$ cmake -S . -B debug
$ camke --build debug

Pattern 4 - place .cpp files also in a seperate folder source

1
2
3
4
5
6
7
8
📦cmake_tutorial
┣ 📂debug
┣ 📂include
┃ ┗ 📜foo.h
┣ 📂source
┃ ┣ 📜foo.cpp
┃ ┗ 📜main.cpp
┗ 📜CMakeLists.txt
  • The CMakeLists.txt modified accordingly as
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    cmake_minimum_required(VERSION 3.10)
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    project(myProject VERSION 1.0)

    file(GLOB_RECURSE SRC_FILES source/*.cpp)
    add_executable(myProject ${SRC_FILES})

    target_include_directories(myProject PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

Pattern 5 - With Library

  • create a lib/include folder to hold foo.h and lib\src to hold foo.cpp, instead one CMakeLists.txt, we create three of them as

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    MyCmakeTutorial
    ┣ app
    ┃ ┣ src
    ┃ ┃ ┗ main.cpp
    ┃ ┗ CMakeLists.txt
    ┣ lib
    ┃ ┣ include
    ┃ ┃ ┗ foo.h
    ┃ ┣ src
    ┃ ┃ ┗ foo.cpp
    ┃ ┗ CMakeLists.txt
    ┗ CMakeLists.txt
  • The CMakeLists.txt in the main direcory mainly subdirectories

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #./CMakeLists.txt 

    # Requires CMake 3.12, but also works with 3.13 policies set.
    cmake_minimum_required( VERSION 3.12...3.13 )

    project( Example_4_CMake
    VERSION 3.12
    DESCRIPTION "Example project for More Modern CMake (using CMake 3.12 or newer)." )

    # Always use '-fPIC'/'-fPIE' option.
    set( CMAKE_POSITION_INDEPENDENT_CODE ON )

    # Create targets for building the (local) libraries.
    add_subdirectory( lib )

    # Create the targets for the entire example-app.
    add_subdirectory( app )
  • The CMakeLists.txt under the lib direcory adds library target

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # ./lib/CMakeLists.txt 
    cmake_minimum_required( VERSION 3.12...3.13 )

    project( localLib
    VERSION 1.0.0
    DESCRIPTION "The local library" )

    # # A shared library
    add_library( myLib SHARED )
    target_sources( myLib PRIVATE "src/foo.cpp")
    target_include_directories( myLib
    PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )

  • The CMakeLists.txt under the app direcory adds excutable target

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # ./app/CMakeLists.txt
    cmake_minimum_required( VERSION 3.12...3.13 )

    project( FooApp
    VERSION 1.0
    DESCRIPTION "My foo app." )
    # exctuble target: PrintFoo
    add_executable( PrintFoo )
    target_sources( PrintFoo PRIVATE "src/main.cpp" )
    target_link_libraries( PrintFoo PRIVATE myLib)
  • Run the following command to compile/link/run the app

    1
    2
    3
    $cmake -S . -B build
    $cmake --build build # equivalent to make command
    $ ./build/app/FooPrint

Modern CMake Tutorial
https://just1ngh.github.io/2022/06/20/camke/
Author
Juquan Justin Mao
Posted on
June 20, 2022
Licensed under