Every project needs consistent language settings and warnings, set in a way that works on GCC, Clang and MSVC.
Two ways to request a language standard:
- Per target:
target_compile_features(core PUBLIC cxx_std_20). As a usage requirement it propagates, so anything usingcore's headers is compiled as C++20 or newer. - Project-wide defaults:
set(CMAKE_CXX_STANDARD 20),set(CMAKE_CXX_STANDARD_REQUIRED ON)(fail instead of silently falling back) andset(CMAKE_CXX_EXTENSIONS OFF)(use-std=c++20, not-std=gnu++20). Set them before creating targets.
Warnings are compiler-specific, so branch on the compiler. Keep them PRIVATE: your warnings shouldn't be forced on your users.
if(MSVC)
target_compile_options(core PRIVATE /W4 /permissive-)
else()
target_compile_options(core PRIVATE -Wall -Wextra -Wpedantic)
endif()Treating warnings as errors is great in CI but annoying for people building your release with a newer compiler; CMake's COMPILE_WARNING_AS_ERROR property (3.24+) can be switched off from the command line with --compile-no-warning-as-error.
Definitions become preprocessor macros: target_compile_definitions(core PRIVATE APP_VERSION="${PROJECT_VERSION}"). For many values, configure_file(version.h.in version.h) generates a header from a template with @PROJECT_VERSION@ placeholders, and a changed value rebuilds only what includes it.
Example
cmake_minimum_required(VERSION 3.25)
project(app VERSION 2.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # compile_commands.json for clangd etc.
add_executable(app main.cpp)
if(MSVC)
target_compile_options(app PRIVATE /W4 /permissive-)
else()
target_compile_options(app PRIVATE -Wall -Wextra -Wpedantic)
endif()
set_target_properties(app PROPERTIES COMPILE_WARNING_AS_ERROR ON)
configure_file(version.h.in version.h) # contains: #define APP_VERSION "@PROJECT_VERSION@"
target_include_directories(app PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_compile_definitions(app PRIVATE APP_NAME="${PROJECT_NAME}")
# compile line: c++ -DAPP_NAME="app" -I.../build -std=c++20 -Wall -Wextra -Wpedantic -Werror ...Remember
- cxx_std_20 per target, or CMAKE_CXX_STANDARD with _REQUIRED ON and EXTENSIONS OFF
- Branch on MSVC for warning flags and keep them PRIVATE
- configure_file generates headers from templates with project values
Watch out for
- Setting CMAKE_CXX_STANDARD after add_executable; it only applies to targets created afterwards.