377

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Subhamoy S.
  • 5,973
  • 8
  • 32
  • 49
  • 13
    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. – ComicSansMS Jun 01 '12 at 14:11
  • 8
    add_definitions(-std=c++11) works for me with CMake 2.8.8 – kyku Jun 02 '12 at 08:49
  • @ComicSansMS: You are totally right! I overwrote it, which was my own mistake. I have corrected it, and now it is working fine! C++11 stuff is very cool! I wanted to loop on a vector of structures, which would require iterator and needless coding noise if I did not have range based for loops. I guess I could use BOOST_FOREACH though, but oh well... – Subhamoy S. Jun 03 '12 at 10:31
  • 37
    For CMake ≥3.1, [__`set(CMAKE_CXX_STANDARD 11)`__](http://www.cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_STANDARD.html) (before defining the target) is the best way. – emlai Jun 13 '15 at 02:26
  • 1
    @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. – Ela782 Dec 09 '16 at 20:21
  • 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](https://stackoverflow.com/a/52382437/2137996) if you just want to build with C++11, 14, etc. See [eyelash's answer](https://stackoverflow.com/a/49597621/2137996) if you additionally want propagating behavior (ie. users of your library must compile with that C++ version) – Alex Reinking Jun 18 '20 at 09:37

14 Answers14

429

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 ()
    
David Grayson
  • 71,301
  • 23
  • 136
  • 171
  • 14
    This should be the accepted answer. It does not require touching each target's properties individually, and works cross-platform. – DevSolar Jan 20 '16 at 12:49
  • 4
    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. – Atifm May 23 '16 at 18:40
  • This works for me for CMake 3.5 on macOS. Big props to David for putting together the macro as well. – Evan Moran Jul 31 '16 at 20:34
  • This should not be used, the good way to do it now is to specify properties per target, and not per directory. Especially if you're writing a library: use the accepted answer ! – Synxis Jan 06 '17 at 14:18
  • I think that for most people it is more convenient to specify the language you are using in just one place. But this is starting to get very opinion-based. – David Grayson Jan 06 '17 at 14:37
  • 3
    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}")` – Antonio May 31 '17 at 10:11
  • GroovyCakes, hey good catch. Recent versions of GCC don't care if you use two dashes but some old versions were picky, so I changed it. – David Grayson Aug 02 '17 at 22:19
  • 2
    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 Oct 23 '17 at 16:20
  • 2
    @Unapiedra: It's a CMake bug but you can work around it, see https://gitlab.kitware.com/cmake/cmake/issues/15943 – David Grayson Nov 01 '17 at 15:34
  • 2
    As @Antonio hinted, always append flags, never set directly as that might overwrite any other set upstream (or passed from command line). Correct: `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")`. – helmesjo Dec 29 '17 at 14:50
  • The CMake version check makes things worse. I have CMake 3.3 with intel c compiler and `CMAKE_CXX_STANDARD` does not work. Simply `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")` works. – fchen Apr 23 '19 at 17:17
187

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.

Community
  • 1
  • 1
Erik Sjölund
  • 9,109
  • 7
  • 34
  • 60
  • 4
    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. – Erik Sjölund Sep 14 '14 at 22:16
  • Urgh, it appears you are correct. My bad. I looked it up but must have landed [here](http://www.steveire.com/cmake-future/command/target_compile_features.html) thinking I was on the main CMake documentation page. I've submitted an edit to revert my changes. Sorry for the noise! – sdt Sep 16 '14 at 01:08
  • 4
    I'd say this is the most accurate answer – Michał Walenciak Jan 07 '15 at 13:38
  • 9
    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+ – Uli Köhler Mar 14 '15 at 18:32
  • 2
    @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. – Doug Mar 20 '15 at 03:37
  • 2
    Any idea how to do this in CMake 2.6? – nuzzolilo Dec 31 '15 at 03:29
  • What to do when a feature is not listed such as `std::future`? – Lenar Hoyt Jun 13 '16 at 12:00
  • See my comment to the answer, be aware `CXX_STANDARD` does not work on MSVC. – Ela782 Dec 09 '16 at 20:22
  • 2
    There are `cxx_std_XX` features now which make it possible to set standard easily. That's great! – val is still with Monica May 25 '19 at 19:33
93

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.

KoKuToru
  • 3,965
  • 2
  • 17
  • 20
  • 4
    This is, for me, the only right and nice answer to this question, with current (rolled out) cmake on most recent Linux' using g++. – Patrick B. Oct 19 '14 at 20:18
  • 1
    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) – cardiff space man Jan 22 '15 at 00:28
  • 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. – Tomasz Gandor Jan 30 '15 at 14:20
  • 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. – Jan Segre Mar 31 '15 at 18:12
  • 1
    @JanSegre the module first appeared in 2.4, http://www.cmake.org/gitweb?p=cmake.git;a=commitdiff;h=72b38e3aa7ba5fa4a70144e05de36bc99fda173a – KoKuToru Apr 01 '15 at 06:00
  • Thank, it works very good. Just a note for anyone using GCC 4.6, most code that I tried and depends on C++11 throws errors with it. – Elias Kouskoumvekakis Jan 04 '17 at 04:47
57

The easiest way to set the Cxx standard is:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

See the CMake documentation for more details.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Luckyrand
  • 579
  • 5
  • 2
42

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")
Subhamoy S.
  • 5,973
  • 8
  • 32
  • 49
  • 36
    I always just use: SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # for gcc >= 4.7, or c++0x for 4.6 – David Doria Sep 21 '12 at 16:42
  • I once did a little script for that (not complete though): https://github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake – Morwenn Feb 15 '13 at 14:08
  • 9
    -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). – Nikolai May 29 '13 at 14:26
  • instead of manually adding the -g flag you should set the CMAKE_BUILD_TYPE variable to debug: http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ – bames53 Nov 24 '14 at 20:52
  • 1
    The `CXX_STANDARD` property is better as it is compiler-agnostic. – jaskmar Aug 14 '18 at 10:13
29

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

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
MateuszL
  • 2,212
  • 19
  • 31
  • 1
    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. – Ruslan Jan 29 '19 at 11:41
  • 1
    No reason not to have the latest CMake, though. Chocolatey, Homebrew, and Snap all have up-to-date packages. – Alex Reinking Jun 18 '20 at 09:33
  • 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. – legends2k Aug 05 '20 at 10:49
  • 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 Jan 07 '21 at 08:29
  • @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 – MateuszL Jan 18 '21 at 13:13
25

For CMake 3.8 and newer you can use

target_compile_features(target PUBLIC cxx_std_11)
eyelash
  • 2,197
  • 20
  • 26
  • 2
    this is the way recommended of latest version of CMake – camino May 19 '18 at 17:36
  • 1
    What is the function of `PUBLIC` here? – Rotsiser Mho Jun 12 '18 at 03:16
  • 3
    @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. – eyelash Jun 12 '18 at 07:05
  • 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). – Razakhel Dec 26 '20 at 11:59
22

The easiest way:

add_compile_options(-std=c++11)

alvarez
  • 658
  • 7
  • 17
16

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.

Hindol
  • 2,661
  • 1
  • 23
  • 39
  • 9
    That will only work if you are ONLY using C++ compiler. If you're also using the CC compiler it will fail. – Emmanuel Nov 13 '13 at 16:45
  • 5
    `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. – xuhdev Nov 07 '14 at 00:26
  • I used that before but had problems when I included a C file because `add_definitions` was not made for setting flags. – Jan Segre Mar 31 '15 at 18:15
6

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.)

codeling
  • 9,289
  • 4
  • 36
  • 61
5

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.

Kevin Katzke
  • 2,836
  • 3
  • 31
  • 42
  • 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 May 31 '17 at 10:08
  • 2
    @Antonio `set (CMAKE_CXX_EXTENSIONS OFF)` – mloskot Aug 29 '17 at 15:14
4

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
    )
RAM
  • 1,483
  • 1
  • 10
  • 27
3

I think just these two lines are enough.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Pang
  • 8,605
  • 144
  • 77
  • 113
  • 1
    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. – Allan Aug 06 '18 at 10:45
-5

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
senz
  • 1,482
  • 1
  • 14
  • 14
  • 2
    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. – einpoklum Jun 03 '16 at 19:52