This document describes configuring a development environment for modern C++. Some of the flags and warnings in this document are not common knowledge, or found in the documentation of the respective toolchain.
Below is the compiler configuration we'll use
We can start by definining a set of common DEFINE
s and compiler flags for C/C++.
{
"COMMON_DEFINES": "-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CHAR8_T -D__USE_GNU",
"COMMON_C_FLAGS": " $env{COMMON_DEFINES} -Wall -Wextra -Werror -pipe -ftrivial-auto-var-init=zero",
"COMMON_CXX_FLAGS": "$env{COMMON_C_FLAGS}",
"CLANG_CXX_FLAGS": "-Wthread-safety -Wthread-safety-beta -Wthread-safety-verbose"
}
Explaining the above:
GLIBCXX_ASSERTIONS
enables assertions in the standard library. This is useful for debugging, but should be disabled in production.GLIBCXX_USE_CHAR8_T
enables thechar8_t
type, which is a UTF-8 character type._USE_GNU
enables GNU extensions-Wall -Wextra -Werror
enables all warnings, and treats them as errors.-pipe
enables piped compilation mode, which is faster than the default mode.-ftrivial-auto-var-init=zeros
will zero-initialize all automatic variables, providing default behavior similar to other languages.thread-safety
flags enables thread safety analysis in Clang.
All following configurations will build on top of the COMMON
flags and configuration.
{
"DEBUG_DEFINES": "-DDEBUG -D_GLIBCXX_DEBUG",
"DEBUG_C_FLAGS": "$env{DEBUG_DEFINES} -O0 -g -ggdb3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer",
"DEBUG_CXX_FLAGS": "$env{DEBUG_C_FLAGS}"
}
Exaplaining the above:
DEBUG
enables debug mode in the code.GLIBCXX_DEBUG
enables debug mode in the standard library.O0
disables optimizations.g
enables debug symbols.ggdb3
enables maximum debug information for the GDB debugger.fno-omit-frame-pointer
disables frame pointer omission, which is useful for debugging (and required for e.g. ASAN to work)mno-omit-leaf-frame-pointer
disables frame pointer omission for leaf functions, which is useful for debugging
{
"RELEASE_DEFINES": "-DNDEBUG -D_FORTIFY_SOURCE=3",
"RELEASE_C_FLAGS": "$env{RELEASE_DEFINES} -O3 -march=native -mtune=native -flto",
"RELEASE_CXX_FLAGS": "$env{RELEASE_C_FLAGS}"
}
Explaining the above:
NDEBUG
disables debug mode in the code.FORTIFY_SOURCE=3
enables additional security checks.O3
enables maximum optimizations (that are still standard-compliant).Ofast
is also an option, but is not standard-compliant.march=native
enables architecture-specific optimizations.mtune=native
enables architecture-specific optimizations.flto
enables link-time optimization.
{
"COMMON_SANITIZE_DEFINES": "-D_GLIBCXX_SANITIZE_STD_ALLOCATOR -D_GLIBCXX_SANITIZE_VECTOR",
"COMMON_SANITIZER_FLAGS": "$env{COMMON_SANITIZE_DEFINES} -fsanitize=address,undefined -fsanitize-address-use-after-scope",
"GCC_SANITIZER_FLAGS": "$env{COMMON_SANITIZER_FLAGS}",
"LLVM_SANITIZER_FLAGS": "$env{COMMON_SANITIZER_FLAGS} -fsanitize=function,integer,nullability"
}
Explaining the above:
GLIBCXX_SANITIZE_STD_ALLOCATOR
enables allocator debugging in the standard library.GLIBCXX_SANITIZE_VECTOR
enables vector debugging in the standard library.fsanitize=address,undefined
enables address and undefined behavior sanitizers.fsanitize-address-use-after-scope
enables use-after-scope detection in the address sanitizer.fsanitize=function,integer,nullability
enables function, integer and nullability sanitizers (LLVM only).
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 23,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default Config",
"description": "Default build using Ninja generator",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/default",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_COLOR_DIAGNOSTICS": "ON",
"CMAKE_C_STANDARD": "23",
"CMAKE_CXX_STANDARD": "23",
"CMAKE_CXX_EXTENSIONS": "ON",
"CMAKE_CXX_STANDARD_REQUIRED": "OFF",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_LINK_WHAT_YOU_USE": "ON"
},
"environment": {
"COMMON_DEFINES": "-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CHAR8_T -D__USE_GNU",
"COMMON_C_FLAGS": " $env{COMMON_DEFINES} -Wall -Wextra -Werror -Wno-unused-variable -pipe -ftrivial-auto-var-init=zero",
"COMMON_CXX_FLAGS": "$env{COMMON_C_FLAGS}",
"DEBUG_DEFINES": "-DDEBUG -D_GLIBCXX_DEBUG",
"DEBUG_C_FLAGS": "$env{DEBUG_DEFINES} -O0 -g -ggdb3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer",
"DEBUG_CXX_FLAGS": "$env{DEBUG_C_FLAGS}",
"RELEASE_DEFINES": "-D_FORTIFY_SOURCE=3",
"RELEASE_C_FLAGS": "$env{RELEASE_DEFINES} -Ofast -march=native -mtune=native -flto",
"RELEASE_CXX_FLAGS": "$env{RELEASE_C_FLAGS}",
"COMMON_SANITIZER_DEFINES": "-D_GLIBCXX_SANITIZE_STD_ALLOCATOR -D_GLIBCXX_SANITIZE_VECTOR",
"COMMON_SANITIZER_FLAGS": "$env{COMMON_SANITIZER_DEFINES} -fsanitize=address,undefined -fsanitize-address-use-after-scope",
"GCC_SANITIZER_FLAGS": "$env{COMMON_SANITIZER_FLAGS}",
"LLVM_SANITIZER_FLAGS": "$env{COMMON_SANITIZER_FLAGS} -fsanitize=function,integer,nullability",
"CLANG_ONLY_C_FLAGS": "",
"CLANG_ONLY_CXX_FLAGS": "$env{CLANG_ONLY_C_FLAGS} -Wthread-safety -Wthread-safety-beta -Wthread-safety-verbose"
},
"vendor": {}
},
{
"name": "debug",
"displayName": "Debug Build",
"description": "Debug build using Ninja generator",
"generator": "Ninja",
"inherits": "default",
"binaryDir": "${sourceDir}/build/debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_FLAGS": "$env{COMMON_C_FLAGS} $env{DEBUG_C_FLAGS}",
"CMAKE_CXX_FLAGS": "$env{COMMON_CXX_FLAGS} $env{DEBUG_CXX_FLAGS}"
}
},
{
"name": "debug-gcc-fanalyzer",
"displayName": "Debug GCC with -fanalyzer",
"description": "Debug build with GCC and -fanalyzer",
"inherits": "debug",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_FLAGS": "$env{COMMON_C_FLAGS} $env{DEBUG_C_FLAGS} $env{COMMON_SANITIZER_FLAGS} -fanalyzer",
"CMAKE_CXX_FLAGS": "$env{COMMON_CXX_FLAGS} $env{DEBUG_CXX_FLAGS} $env{COMMON_SANITIZER_FLAGS} -fanalyzer"
}
},
{
"name": "release",
"displayName": "Release Build",
"description": "Release build using Ninja generator",
"inherits": "default",
"binaryDir": "${sourceDir}/build/release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_C_FLAGS": "$env{COMMON_C_FLAGS} $env{RELEASE_C_FLAGS}",
"CMAKE_CXX_FLAGS": "$env{COMMON_CXX_FLAGS} $env{RELEASE_CXX_FLAGS}"
}
},
{
"name": "sanitize",
"displayName": "Sanitize Build",
"description": "Sanitize build using Ninja generator",
"inherits": "debug",
"binaryDir": "${sourceDir}/build/sanitize",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_C_FLAGS": "$env{COMMON_C_FLAGS} $env{DEBUG_C_FLAGS} $env{LLVM_SANITIZER_FLAGS} $env{CLANG_ONLY_C_FLAGS}",
"CMAKE_CXX_FLAGS": "$env{COMMON_CXX_FLAGS} $env{DEBUG_CXX_FLAGS} $env{LLVM_SANITIZER_FLAGS} $env{CLANG_ONLY_CXX_FLAGS}",
"CMAKE_EXE_LINKER_FLAGS": "$env{LLVM_SANITIZER_FLAGS} -fuse-ld=lld",
"CMAKE_SHARED_LINKER_FLAGS": "$env{LLVM_SANITIZER_FLAGS} -fuse-ld=lld"
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default"
}
],
"testPresets": [
{
"name": "default",
"configurePreset": "default",
"output": {
"outputOnFailure": true
},
"execution": {
"noTestsAction": "error",
"stopOnFailure": true
}
}
],
"vendor": {}
}