ChatGPT解决这个技术问题 Extra ChatGPT

How do I activate C++ 11 in CMake?

When I try to run a CMake generated makefile to compile my program, I get the error that

range based for loops are not supported in C++ 98 mode.

I tried adding add_definitions(-std=c++0x) to my CMakeLists.txt, but it did not help.

I tried this too:

if(CMAKE_COMPILER_IS_GNUCXX)
    add_definitions(-std=gnu++0x)
endif()

When I do g++ --version, I get:

g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

I have also tried SET(CMAKE_CXX_FLAGS "-std=c++0x"), which also does not work.

I do not understand how I can activate C++ 11 features using CMake.

The SET(CMAKE_CXX_FLAGS "-std=c++0x") works fine for me, so there is probably a problem somewhere else in the CMakeLists file. Make sure you don't accidentally overwrite the contents of CMAKE_CXX_FLAGS later on.
add_definitions(-std=c++11) works for me with CMake 2.8.8
For CMake ≥3.1, set(CMAKE_CXX_STANDARD 11) (before defining the target) is the best way.
@tuple_cat You can do it target-based as well. But be aware that CXX_STANDARD does not work on MSVC, so basically you have to fall back to target_compile_features if you want something that works cross-platform.
Questions about CMake get stale very fast here on SO. In 2020, you should absolutely not be fiddling with compiler flags in your CMakeLists.txt to do this. See MateuszL's answer if you just want to build with C++11, 14, etc. See eyelash's answer if you additionally want propagating behavior (ie. users of your library must compile with that C++ version)

D
David Grayson

CMake 3.1 introduced the CMAKE_CXX_STANDARD variable that you can use. If you know that you will always have CMake 3.1 or later available, you can just write this in your top-level CMakeLists.txt file, or put it right before any new target is defined:

set (CMAKE_CXX_STANDARD 11)

If you need to support older versions of CMake, here is a macro I came up with that you can use:

macro(use_cxx11)
  if (CMAKE_VERSION VERSION_LESS "3.1")
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
      set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
    endif ()
  else ()
    set (CMAKE_CXX_STANDARD 11)
  endif ()
endmacro(use_cxx11)

The macro only supports GCC right now, but it should be straight-forward to expand it to other compilers.

Then you could write use_cxx11() at the top of any CMakeLists.txt file that defines a target that uses C++11.

CMake issue #15943 for clang users targeting macOS

If you are using CMake and clang to target macOS there is a bug that can cause the CMAKE_CXX_STANDARD feature to simply not work (not add any compiler flags). Make sure that you do one of the following things:

Use cmake_minimum_required to require CMake 3.0 or later, or

Set policy CMP0025 to NEW with the following code at the top of your CMakeLists.txt file before the project command: # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. if (POLICY CMP0025) cmake_policy(SET CMP0025 NEW) endif ()


This should be the accepted answer. It does not require touching each target's properties individually, and works cross-platform.
Agreed, this should be the accepted answer as of CMake 3.1+. It doesn't seem to work for me on the mac though. You can force it to give you --std=c++11 with --stdlib=libc++, the default on the Mac. Instead CMAKE_CXX_STANDARD always includes the gnu extensions if they are supported, and the result doesn't seem to build against --stdlib=libc++. Instead you have to switch to gnu's --stdlib=libstdc++. The Mac is the special case though. For Linux, choosing gnu++11 with libstdc++ is the norm. Of course, that is easily corrected with a if(APPLE) add_compile_options() to tack on the flags.
One problem of this approach is that gnu++11 is enforced, even when these variables are defined set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). For me the only viable way was the classic set (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Does not work for me on macOS (CMake 3.9.4, homebrew-clang). Saving others the despair. Not sure why it works for @EvanMoran but not me.
@Unapiedra: It's a CMake bug but you can work around it, see gitlab.kitware.com/cmake/cmake/issues/15943
C
Community

The CMake command target_compile_features() is used to specify the required C++ feature cxx_range_for. CMake will then induce the C++ standard to be used.

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(foobar CXX)
add_executable(foobar main.cc)
target_compile_features(foobar PRIVATE cxx_range_for)

There is no need to use add_definitions(-std=c++11) or to modify the CMake variable CMAKE_CXX_FLAGS, because CMake will make sure the C++ compiler is invoked with the appropriate command line flags.

Maybe your C++ program uses other C++ features than cxx_range_for. The CMake global property CMAKE_CXX_KNOWN_FEATURES lists the C++ features you can choose from.

Instead of using target_compile_features() you can also specify the C++ standard explicitly by setting the CMake properties CXX_STANDARD and CXX_STANDARD_REQUIRED for your CMake target.

See also my more detailed answer.


It seems the edit from today is misleading. CMake 3.0.0 does not contain target_compile_features. Correct me if I'm wrong. I think the command is only present in the nightly builds of CMake.
I'd say this is the most accurate answer
I think this is how it is supposed to do. The other answers just manually add flags and therefore introduce incompatibilities. However this seems to be only available in CMake 3.1+
@UliKöhler this is actually still not available, and may possibly turn up for some compilers in 3.2. Don't use this method in the short term; its completely not portable.
Any idea how to do this in CMake 2.6?
K
KoKuToru

I am using

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

But if you want to play with C++11, g++ 4.6.1 is pretty old. Try to get a newer g++ version.


This is, for me, the only right and nice answer to this question, with current (rolled out) cmake on most recent Linux' using g++.
Copied and pasted this and it worked perfectly. I am on Cygwin using CMAKE 2.8.9. I know about most of the approaches I'm reading here because I follow the CMAKE mailing list and I've ported WebKit to a variety of compilers. The thing we had done for WebKit ports was to install CMake 2.8.12. However because I know Cygwin's CMAKE is old, I wanted something that applied to that version. (Not porting WebKit to Cygwin, sorry)
Great, this is a drop-in for old CMake and g++ 4.6 (and future-proof). I also upvoted the CXX_STANDARD-based answers, but this was the only answer useful in my situation.
This is exactly what I was looking for, however it's not clear what is the minimum cmake version needed to use that module. cmake --help-module doesn't help much about it.
@JanSegre the module first appeared in 2.4, cmake.org/…
P
Peter Mortensen

The easiest way to set the Cxx standard is:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

See the CMake documentation for more details.


Yes, this definitely looks like one of the best ways to do it in modern CMake (3.1+)
Or you can just set(CMAKE_CXX_STANDARD 11) to define the default property for all targets created after that.
This is also the solution you need if you want to set different C++ standards on different targets, because the set command suggested by @emlai is global and affects all subsequent targets.
S
Subhamoy S.

As it turns out, SET(CMAKE_CXX_FLAGS "-std=c++0x") does activate many C++11 features. The reason it did not work was that the statement looked like this:

set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")

Following this approach, somehow the -std=c++0x flag was overwritten and it did not work. Setting the flags one by one or using a list method is working.

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")

I always just use: SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # for gcc >= 4.7, or c++0x for 4.6
I once did a little script for that (not complete though): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
-1. If you specify any CMAKE_CXX_FLAGS from the command line, the second method will produce a semicolon in the build command (and repeat the original CMAKE_CXX_FLAGS twice).
instead of manually adding the -g flag you should set the CMAKE_BUILD_TYPE variable to debug: voices.canonical.com/jussi.pakkanen/2013/03/26/…
The CXX_STANDARD property is better as it is compiler-agnostic.
P
Peter Mortensen

On modern CMake (>= 3.1) the best way to set global requirements is:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

It translates to "I want C++11 for all targets, it's not optional, I don’t want to use any GNU or Microsoft extensions." As of C++17, this still is IMHO the best way.

Source: Enabling C++11 And Later In CMake


This way is not ideal for newest versions of C++ if you don't have the latest CMake. E.g. you can't enable C++2a this way until CMake 3.12.
No reason not to have the latest CMake, though. Chocolatey, Homebrew, and Snap all have up-to-date packages.
Note that these have to be set before defining any targets; failing to do this leads to only targets defined after setting them to get affected. This is understandable since they're the defaults.
Not any more in "more modern cmake = 3.12"... prefer target_compile_options(project_name PRIVATE option1 ...) or target_compile_definitions or still target_compile_features(ao-project_name PRIVATE some_feature) if you target between C++11 and C++17 but not above.
@Sandburg why would I prefer to specify multiple features for multiple targets separately? Do you think this is common to have various expectations for various targets in single project? I knew about this feature but honestly can't think of single use-case when this is desirable as primary approach. In any case: according to linked article it worked in 3.1
l
legends2k

For CMake 3.8 and newer you can use

target_compile_features(target PUBLIC cxx_std_11)

If you want the generation step to fail if the toolchain cannot adhere to this standard, you can make this required.

set_target_properties(target PROPERTIES CXX_STANDARD_REQUIRED ON)

If you want strict adherence to standard C++ i.e. avoid C++ extensions offered by your compiler (like GCC's -std=gnu++17), additionally set

set_target_properties(target PROPERTIES CXX_EXTENSIONS OFF)

This is documented in detail at An Introduction to Modern CMake -> Adding Features -> C++11 and Beyond. It also offers advice on how to achieve this on older versions of CMake if you're constrained to those.


this is the way recommended of latest version of CMake
What is the function of PUBLIC here?
@RotsiserMho PUBLIC means that other targets that depend on your target will use C++11 as well. For example if your target is a library then all targets that link against your library with target_link_libraries will be compiled with C++11 support.
As of now, this is technically the best way to define the standard version and should be the accepted answer (although Erik's still stands, should one need fine grained settings).
Is there a way to set global/CMAKE_ default target features? Or does it mean we have to repeat setting language standard for every target?
a
alvarez

The easiest way:

add_compile_options(-std=c++11)


Only available from cmake 3.0
This causes warning and errors when compiling C files in the same project.
Absolutely do not do this. It will break compiling plain C programs. It glues your CMakeLists.txt to a particular compiler and there's built-in support for this, anyway.
This fails for the Visual Studio compiler. See my answer for the better answer that works for all the compilers: stackoverflow.com/a/69804542/7910299
H
Hindol

This is another way of enabling C++11 support,

ADD_DEFINITIONS(
    -std=c++11 # Or -std=c++0x
    # Other flags
)

I have encountered instances where only this method works and other methods fail. Maybe it has something to do with the latest version of CMake.


That will only work if you are ONLY using C++ compiler. If you're also using the CC compiler it will fail.
add_definitions is only supposed to used for adding DEFINITIONS, i.e. -D SOMETHING. And as @Emmanuel said, it does not work in many cases.
I used that before but had problems when I included a C file because add_definitions was not made for setting flags.
R
RAM

Modern cmake offers simpler ways to configure compilers to use a specific version of C++. The only thing anyone needs to do is set the relevant target properties. Among the properties supported by cmake, the ones that are used to determine how to configure compilers to support a specific version of C++ are the following:

CXX_STANDARD sets the C++ standard whose features are requested to build the target. Set this as 11 to target C++11.

CXX_EXTENSIONS, a boolean specifying whether compiler specific extensions are requested. Setting this as Off disables support for any compiler-specific extension.

To demonstrate, here is a minimal working example of a CMakeLists.txt.

cmake_minimum_required(VERSION 3.1)

project(testproject LANGUAGES CXX )

set(testproject_SOURCES
    main.c++
    )

add_executable(testproject ${testproject_SOURCES})

set_target_properties(testproject
    PROPERTIES
    CXX_STANDARD 11
    CXX_EXTENSIONS off
    )

E
E_net4 - Mr Downvoter

In case you want to always activate the latest C++ standard, here's my extension of David Grayson's answer, in light of the recent (CMake 3.8 and CMake 3.11) additions of values of 17 and 20 for CMAKE_CXX_STANDARD):

IF (CMAKE_VERSION VERSION_LESS "3.8")
    SET(CMAKE_CXX_STANDARD 14)
ELSEIF (CMAKE_VERSION VERSION_LESS "3.11")
    SET(CMAKE_CXX_STANDARD 17)
ELSE()
    SET(CMAKE_CXX_STANDARD 20)
ENDIF()

# Typically, you'll also want to turn off compiler-specific extensions:
SET(CMAKE_CXX_EXTENSIONS OFF)

(Use that code in the place of set (CMAKE_CXX_STANDARD 11) in the linked answer.)


K
Kevin Katzke

What works for me is to set the following line in your CMakeLists.txt:

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

Setting this command activates the C++11 features for the compiler and after executing the cmake .. command, you should be able to use range based for loops in your code and compile it without any errors.


This is in the end the best answer if you want exactly -std=c++11, as set (CMAKE_CXX_STANDARD 11) will use the flag -std=gnu++11, which might be undesirable.
@Antonio set (CMAKE_CXX_EXTENSIONS OFF)
P
Pang

I think just these two lines are enough.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

This makes sense when all targets in a project use the same C++ standard (all compiled libraries and executables use C++11, for example). Otherwise, the Cmake target_compile_features function, applied for each individual target, as shown in other answers, is a more recommended approach.
Given the first line there is absolutely no need for the second, which does nothing but add a redundant flag on compatible compilers and break the build on others (like MSVC).
A
Amin

You can use the following. This automatically modifies the feature based on your environment.

target_compile_features(your_target INTERFACE cxx_std_20)

For example,

on Gnu/Linux the following adds -std=gnu++20

on Windows with Clang/Ninja it becomes -std=c++20

on Windows with MSVC it becomes /std=c++20

So you support as many as environments possible.


S
SpacePotatoes

The modern way is to specify the minimum required standard to C++11 with:

target_compile_features(foo PUBLIC cxx_std_11)

This way:

CMake can honor default C++ standard of the compiler if it's greater than C++11

You can clearly specify whether C++ standard is required at build time, consume time, or both. This is nice for libraries.

Public compile features are propagated to downstream targets, so it comes for free in those targets even if they don't directly use this feature.

Users can externally set another C++ standard (more recent basically), with CMAKE_CXX_STANDARD, either from command line or CMake presets. If you hardcode CMAKE_CXX_STANDARD in a CMakeLists, nobody can override the C++ standard without editing your CMakeLists, which is not very pleasant.

It requires CMake >= 3.8


P
Peter Mortensen

OS X and Homebrew LLVM related:

Don't forget to call cmake_minimum_required(VERSION 3.3) and project() after it!

Or CMake will insert project() implicitly before line 1, causing trouble with Clang version detection and possibly other sorts of troubles. Here is a related issue.


The question is not OSX or LVVM related, specifically. Also, there's no reason to require CMake v3.x for C++11 development. As for clang version detection - that's not what OP asked about.