Benchmarking a Debug build or shipping one is a classic, costly mistake.
CMake knows four standard build types:
Debug: no optimisation, debug info (-O0 -gwith GCC/Clang,/Od /Ziwith MSVC).Release: optimised,-O3 -DNDEBUG(soassertis 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. ThereCMAKE_BUILD_TYPEis 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 ReleaseRemember
- 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.