64

GCC 4.x doesn't accept the --std=c++14 switch for C++14 code - it takes --std=c++1y instead. Later versions take --std=c++1z but (probably) not --std=c++17 which has not been set yet (writing this in 2016). Perhaps there are similar issues with C++11.

Does CMake have some facility (perhaps as a module) to pass the correct switch according to the GCC version?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    *"Perhaps there are similar issues with C++11."* That would be c++11 vs c++0x, the former being introduced in gcc4.7/8 or so. – Baum mit Augen Mar 16 '17 at 13:02
  • 1
    Btw, the old switches (0x, 1y, 1z) work just fine even on compilers that support the modern ones, so there is no *real* need to get this "right". – Baum mit Augen Mar 16 '17 at 13:04
  • 3
    There **is** a need to get this "right" since passing the raw compiler flags is a CMake anti-pattern and against the whole concept of a meta-build system/build system generator. – Florian Wolters Oct 18 '17 at 11:58

3 Answers3

109

When wanting to specify a particular C++ version, the recommended way to do this with CMake 3.1 and later is to use the CXX_STANDARD, CXX_STANDARD_REQUIRED and CXX_EXTENSIONS target properties, or their variable equivalents to specify target defaults. Full details can be found here, but the short version goes something like this:

cmake_minimum_required(VERSION 3.1)
project(Example)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# ... Define targets, etc. as usual

CMake should then select the appropriate compiler flag for the requested C++ standard based on what the compiler supports, or error out if it doesn't support the requested standard.

It should also be noted that CMake may upgrade the target to use a later language standard than the one specified by its CXX_STANDARD target property. The use of compile feature requirements (as mentioned in @FlorianWolters answer) can raise the language standard requirement. In fact, CMake will always pick the stronger language requirement specified by either the CXX_STANDARD target property or the compile feature requirements set on the target. Note also that earlier versions of the CMake documentation did not accurately reflect the way CXX_EXTENSIONS interacts with compile features. With CMake 3.21 or earlier, CXX_EXTENSIONS would only take effect if CXX_STANDARD was also specified, for most common compilers (since they are specified together with the one compiler flag). From CMake 3.22 onward, CXX_EXTENSIONS is honoured whether CXX_STANDARD is set or not.

Craig Scott
  • 9,238
  • 5
  • 56
  • 85
  • should I use all 3 properties together or only one of them is good enough? – Felix F Xu Jul 18 '23 at 01:57
  • 1
    I recommend setting all three. CMAKE_CXX_STANDARD on its own doesn't guarantee that you get that C++ standard. Without CMAKE_CXX_STANDARD_REQUIRED being set to true, CMake is allowed to fall back to an older C++ version if the one requested by CMAKE_CXX_STANDARD is not available. Setting CMAKE_CXX_EXTENSIONS to false ensures your project doesn't use non-standard C++, but just as importantly, it may affect which standard library your binaries link to. Policy CMP0128 is also relevant. – Craig Scott Jul 19 '23 at 01:12
39

Modern CMake code should use the target_compile_features command to request a specific C++ standard. This can be specified as build requirement only (PRIVATE), usage requirement only (INTERFACE) or build and usage requirement (PUBLIC).

Example:

cmake_minimum_required(VERSION 3.9.4)

project(cpp-snippets)
add_executable(cpp-snippets "main.cpp")
target_compile_features(cpp-snippets PRIVATE cxx_std_17)

Refer to the section Requiring Language Standards in the official CMake documentation for cmake-compile-features to learn more.

Florian Wolters
  • 3,820
  • 5
  • 35
  • 55
  • 2
    What are "build requirements" as opposed to "usage requirements"? – einpoklum Oct 18 '17 at 14:46
  • 6
    It should also be highlighted that support for the `cxx_std_YY` meta feature was also only added in CMake 3.8, whereas the `CXX_STANDARD` family of target properties have been around much longer and `cxx_std_YY` meta features alone don't control whether or not compiler extensions can be used. – Craig Scott Oct 18 '17 at 20:12
  • 3
    @einpoklum As used in the answer, _build requirements_ refer to things needed to build the target itself, whereas _usage requirements_ are things that anything linking against the target will inherit as a requirement. – Craig Scott Oct 18 '17 at 20:53
  • @einpoklum I should have used the terms *Build Specification* and *Usage Requirements* as used in the [official documentation](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-specification-and-usage-requirements). Craig Scott already explained it correctly. Another great explaination can be found in the talk [Effective CMake](https://www.youtube.com/watch?v=bsXLMQ6WgIk) by Daniel Pfeifer. I highly recommend watching the linked video. – Florian Wolters Oct 19 '17 at 17:34
11

Check if the compiler supports the flags? Perhaps something like

include(CheckCXXCompilerFlag)

# Check for standard to use
check_cxx_compiler_flag(-std=c++17 HAVE_FLAG_STD_CXX17)
if(HAVE_FLAG_STD_CXX17)
    # Have -std=c++17, use it
else()
    check_cxx_compiler_flag(-std=c++1z HAVE_FLAG_STD_CXX1Z)
    if(HAVE_FLAG_STD_CXX1Z)
        # Have -std=c++1z, use it
    else()
        # And so on and on...
    endif()
endif()
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621