James Smith
Jun. 15th, 2023
Put simply, a build system is a set of programs and companion text files that collectively build a software code base.
- Onorato Vaticone
For a more complete discussion see: hacking C++ blog.
*Technically, CMake is a build system generator, but I'll use the terms interchangably here.
We'll be doing a side-by-side presentation from now, check out the examples:
https://github.com/jamesETsmith/2023-06-15-cmake-intro
cmake -S . -B build
cmake --build build
cmake --build build --target test
Old school procedure (avoid if possible)
mkdir -p build
cd build
cmake ..
make
make test
⚠Use build directory, don't do in-source builds⚠
Verbose builds
cmake --build build --verbose # Option 1
cd build && VERBOSE=1 make # Option 2
Setting options (-DOPTION
)
cmake -S . -B build -DCMAKE_CXX_COMPILER=clang++
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake -S . -B build -DBUILD_SHARED_LIBS=ON
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$(pwd)/install
--verbose
flagcmake -LH
vim build/CMakeCache.txt
02-simple-exec/CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(project_name)
add_executable(simple_target simple.cpp)
cmake_minimum_required(VERSION 3.20)
See "More Modern CMake" for details
project(project_name)
project(
project_name
VERSION 1.0
DESCRIPTION "Very nice project"
LANGUAGES CXX)
add_executable(simple_target simple.cpp)
add_exectuable
)
or library (add_library
)
add_library(simple_lib STATIC simple.cpp)
STATIC
SHARED
INTERFACE
(fictional target with no compilation)ALIAS
(alias for existing target)MODULE
(libraries loaded dynamically at runtime)02-simple-app/CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(simple_app)
add_library(simple_lib STATIC simple_lib.cpp)
target_include_directories(simple_lib PUBLIC include)
add_executable(simple_app simple_app.cpp)
target_link_libraries(simple_app PUBLIC simple_lib)
PUBLIC
: Used by current target and dependenciesPRIVATE
: Used by just current targetINTERFACE
: Used by just dependenciesKey points:
cmake_minimum_required
,
project
, and add_library
-DBUILD_TESTING=ON
include(CTest)
enable_testing()
add_subdirectory
# Run serially
cmake --build build --target test
ctest --test-dir build
cmake --build build --target test --parallel 12
# Run in parallel
CTEST_PARALLEL_LEVEL=12 cmake --build build --target test
ctest --test-dir build --parallel 12
# Select subset of tests with RegEx
ctest --test-dir build -R filter
In the next few examples, the directory structure will start to look more realistic, i.e.:
.
├── cmake
│ └── FindProject.cmake
├── CMakeLists.txt
├── include
│ └── project
│ └── lib.hpp
├── src
│ ├── CMakeLists.txt
│ └── lib.cpp
└── test
├── CMakeLists.txt
├── test_1.cpp
└── test_2.cpp
03-test-simple/CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(simple_lib)
# src/CMakeLists.txt creates library target
add_subdirectory(src)
enable_testing()
# test/CMakeLists.txt creates test targets and registers them
add_subdirectory(test)
03-test-simple/src/CMakeLists.txt
add_library(simple_lib STATIC simple_lib.cpp)
target_include_directories(simple_lib PUBLIC ${CMAKE_SOURCE_DIR}/include)
03-test-simple/test/CMakeLists.txt
add_executable(test_1 ${CMAKE_CURRENT_SOURCE_DIR}/test_1.cpp)
target_link_libraries(test_1 PUBLIC simple_lib)
add_test(NAME test_1_fancy_name COMMAND test_1)
# This test is written to fail
add_executable(test_2 ${CMAKE_CURRENT_SOURCE_DIR}/test_2.cpp)
target_link_libraries(test_2 PUBLIC simple_lib)
add_test(NAME test_2_fancy_name COMMAND test_2)
link_directories
or
link_libraries
PUBLIC
requirements where it's not needed
cmake -S . -B build -DCMAKE_C_FLAGS="-O2 -ftree-vectorize"
Note that these flags may interact with those set by CMAKE_BUILD_TYPE