Build types: Debug, Release and multi-config

CMake · Practical · 10 min

Benchmarking a Debug build or shipping one is a classic, costly mistake.

CMake knows four standard build types:

  • Debug: no optimisation, debug info (-O0 -g with GCC/Clang, /Od /Zi with MSVC).
  • Release: optimised, -O3 -DNDEBUG (so assert is disabled).
  • RelWithDebInfo: optimised with debug info, -O2 -g -DNDEBUG; good for profiling and for production with symbols.
  • MinSizeRel: optimise for size, -Os.

How you choose depends on the generator:

  • Single-config generators (Ninja, Makefiles) build one type per build tree: cmake -B build -DCMAKE_BUILD_TYPE=Release. If you set nothing, the type is empty, meaning no optimisation flags at all; many projects default it in their CMakeLists when the user didn't choose.
  • Multi-config generators (Visual Studio, Xcode, Ninja Multi-Config) hold all types in one tree, and you pick at build time: cmake --build build --config Release. There CMAKE_BUILD_TYPE is ignored.

So if(CMAKE_BUILD_TYPE STREQUAL "Debug") is wrong for multi-config builds. Express per-configuration settings with generator expressions such as $<$<CONFIG:Debug>:...> (covered later), which work for both kinds.

A common layout is one build directory per type, build/debug and build/release, which presets make convenient.

Example

# default to Release for single-config generators when nothing was chosen
get_property(multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT multi AND NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

message(STATUS "Release flags: ${CMAKE_CXX_FLAGS_RELEASE}")   # -O3 -DNDEBUG (GCC)
message(STATUS "Debug flags:   ${CMAKE_CXX_FLAGS_DEBUG}")     # -g

# single-config (Ninja, Makefiles): one type per build tree
#   cmake -S . -B build/debug   -G Ninja -DCMAKE_BUILD_TYPE=Debug
#   cmake -S . -B build/release -G Ninja -DCMAKE_BUILD_TYPE=Release
#   cmake --build build/release
# multi-config (Visual Studio, Ninja Multi-Config): choose when building
#   cmake -S . -B build -G "Ninja Multi-Config"
#   cmake --build build --config Release

Remember

  • Debug, Release, RelWithDebInfo and MinSizeRel set optimisation and debug flags
  • Single-config: -DCMAKE_BUILD_TYPE; multi-config: --config at build time
  • An empty build type means no optimisation

Watch out for

  • Benchmarking a build configured without CMAKE_BUILD_TYPE, which compiles with no optimisation at all.

Check yourself

  1. You configured with -G "Visual Studio 17 2022" -DCMAKE_BUILD_TYPE=Release, then ran cmake --build build. What do you get?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations