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
orVisual 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 |
|
1 |
|
1 |
|
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.cppcreate a
CMakeLists.txt
under the same folder with source files and specify the name of cmake exctubale project asmyProject
1 |
|
In terminal run
cmake .
command. This will generate some new files, and the most important one ismaekfile
. In the following,make
command will run this file to build the project.1
2
3
4
5
6
7
8
9cmake_tutorial
┣ 📂CMakeFiles
┣ 📜CMakeCache.txt
┣ 📜CMakeLists.txt
┣ 📜Makefile
┣ 📜cmake_install.cmake
┣ 📜foo.cpp
┣ 📜foo.h
┗ 📜main.cppIn terminal run
make
command and new files are generated including a excutable file with the same name as the project (“myProject”) defined in theCMakeLists.txt
file. Now you can run./myProject
in the terminal. The output like1
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
ordebug
- run the follwing command in terminal
1 |
|
- now all files generated are put into the debug folder
1
2
3
4
5
6make_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 formain.cpp
andfoo.cpp
, we need to add a header file directory inCMakeLists.txt
:
1 |
|
now we have
CMakeLists.txt
as below1
2
3
4
5
6
7
8cmake_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 |
|
New
1 |
|
Pattern 4 - place .cpp files also in a seperate folder source
1 |
|
- The
CMakeLists.txt
modified accordingly as1
2
3
4
5
6
7
8
9
10
11cmake_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 holdfoo.h
andlib\src
to holdfoo.cpp
, instead oneCMakeLists.txt
, we create three of them as1
2
3
4
5
6
7
8
9
10
11
12MyCmakeTutorial
┣ app
┃ ┣ src
┃ ┃ ┗ main.cpp
┃ ┗ CMakeLists.txt
┣ lib
┃ ┣ include
┃ ┃ ┗ foo.h
┃ ┣ src
┃ ┃ ┗ foo.cpp
┃ ┗ CMakeLists.txt
┗ CMakeLists.txtThe
CMakeLists.txt
in the main direcory mainly subdirectories1
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 thelib
direcory adds library target1
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 theapp
direcory adds excutable target1
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