89

Is there a way to let CMake detect automatically if a compiler supports C++11 or not?

As it would be nice to inform the users during the CMake run that the code will not compile as the compiler does not support C++11. At the moment I set the C++11 flags. However, if a compiler does not support it the user gets compile errors instead of an error during the CMake run.

Perfect would be something that works like find_package(). However, I have not found any module or function which provides the functionality needed.

Additional it would be nice to have the feature to detect if the compiler needs the flags std=c++0x or std=c++11.

Is there something available or do I need to develop this on my own?

Below is some code I use so far, however it works only with GNU'c GCC compilers. It would be nice if there would be a more general solution.

if(CMAKE_COMPILER_IS_GNUCXX) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7) message(STATUS "C++11 activated.") add_definitions("-std=gnu++11") elseif(GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3) message(WARNING "C++0x activated. If you get any errors update to a compiler which fully supports C++11") add_definitions("-std=gnu++0x") else () message(FATAL_ERROR "C++11 needed. Therefore a gcc compiler with a version higher than 4.3 is needed.") endif() else(CMAKE_COMPILER_IS_GNUCXX) add_definitions("-std=c++0x") endif(CMAKE_COMPILER_IS_GNUCXX) 
1
  • Why use add_definitions command instead of setting CMAKE_CXX_FLAGS to set compiler options? Commented Mar 4, 2014 at 3:20

7 Answers 7

111

If you have CMake version 3.1.0 or later you can detect what C++ features your C++ compiler supports

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) project(foobar CXX) message("Your C++ compiler supports these C++ features:") foreach(i ${CMAKE_CXX_COMPILE_FEATURES}) message("${i}") endforeach() 

But normally you don't need to use the CMake variable CMAKE_CXX_COMPILE_FEATURES in your CMake scripts. Instead there are two ways of how to tell CMake under which C++ standard your C++ files should be compiled, either by specifying the C++ standard explicitly or by specifying the required C++ features and let CMake induce the C++ standard. CMake will make sure the C++ compiler is invoked with the correct command line flags (e.g. -std=c++11).

  1. Specifying the C++ standard explicitly

You could specify the C++ standard explicitly, by setting the CMake properties CXX_STANDARD and CXX_STANDARD_REQUIRED for your CMake target.

$ cat /tmp/src/CMakeLists.txt project(foobar CXX) cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) add_executable(prog main.cc) set_property(TARGET prog PROPERTY CXX_STANDARD 11) set_property(TARGET prog PROPERTY CXX_STANDARD_REQUIRED ON) $ cat /tmp/src/main.cc int main() { return 0; } $ mkdir /tmp/build $ cd /tmp/build $ cmake /tmp/src -- The CXX compiler identification is GNU 4.8.2 -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /tmp/build $ make VERBOSE=1 | grep main.cc | grep -- "-c" /usr/bin/c++ -std=gnu++11 -o CMakeFiles/prog.dir/main.cc.o -c /tmp/src/main.cc $ 
  1. Specifying the required C++ features and let CMake induce the C++ standard

You could use the CMake command target_compile_features to specify the C++ features that are made use of in your CMake target. From this list CMake will induce the C++ standard to be used. The CMake global property CMAKE_CXX_KNOWN_FEATURES lists the C++ features you can choose from.

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) message("Your CMake version supports these C++ features:") get_property(known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) foreach(i ${known_features}) message("${i}") endforeach() 

For example, this C++ program with the filename main.cc makes use of the C++11 features: cxx_strong_enums, cxx_constexpr, cxx_auto_type

#include <cstdlib> int main(int argc, char *argv[]) { enum class Color { Red, Orange, Yellow, Green, Blue, Violet }; constexpr float a = 3.1415f; auto b = a; return EXIT_SUCCESS; } 

This CMakeLists.txt file would build it

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) project(foobar CXX) add_executable(foobar main.cc) set(needed_features cxx_strong_enums cxx_constexpr cxx_auto_type) target_compile_features(foobar PRIVATE ${needed_features}) 
Sign up to request clarification or add additional context in comments.

11 Comments

It is a bit painful that this has to be done per target. It would be convenient to say "just use C++11 everywhere" and be done with it.
Seems like CXX_STANDARD 11 does not work with GLOBAL property scope, which totally sucks.
@MarcGlisse @abergmeier To define it in the current CMake scope, you can set(CMAKE_CXX_STANDARD 11)
I still got some problems with this approach since it adds -std=gnu++11 and enables non-standard extensions. I'd really only like std=c++11 and get an error if I try to use one of these non standard extensions, portability first.
@RaphaelMiedl I asked this question and got an answer. see link. Basically you use SET( CMAKE_CXX_EXTENSIONS OFF ).
|
39

At this point, CMake does not have a convenient form to support C++11. Ideally, you would specify a C++11 project like this:

project(foo CXX11) 

at the beginning of your CMakeLists.txt. But the CXX11 project type does not exist (yet). Until then, you may use a two-staged technique:

  1. Determine the compiler type and version
  2. Adjust build flags accordingly.

For example, this is what I use to support C++11 with Clang and GCC:

# Initialize CXXFLAGS. set(CMAKE_CXX_FLAGS "-Wall -std=c++11") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") # Compiler-specific C++11 activation. if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") endif () elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") else () message(FATAL_ERROR "Your C++ compiler does not support C++11.") endif () 

6 Comments

It has now been more than six months since your answer, do you know of any updates? It seems strange that this issue isn't resolved yet.
Unfortunately I am still not aware of any better solution. Maybe it helps to raise this concern on the CMake mailing list.
Hi Jack and Matthias, I know this comment is very late, but it looks like some C++11 support was finally added to CMake: public.kitware.com/Bug/view.php?id=13842 My understanding is that this will be a part of CMake 3.1, which is scheduled for release in the beginning of November.
Cool, once this becomes more mainstream I'll update the answer. It looks like one can now associate the C++ version with a CMake target via set_property(TARGET tgt PROPERTY CXX_STANDARD 11).
@LucasB, true that, but Eric already provides a much nicer answer, which the OP should probably accept at this point.
|
9

At the time of this writing (pre-GCC 4.8), it may not be a good idea to detect C++11 flags and add them. This is because changing the standard (at least for GCC) breaks ABI compatibility, which can result in link errors.

Therefore, the use of the C++11 standard should explicitly specified with the compiler setting during the initial CMake configuration of the project, e.g.

CXX='g++ -std=c++11' cmake /path/to/source

That is, the use of -std=c++11 should be treated like a separate compiler, which should not be mixed or changed in a project.

2 Comments

Now that we are post-GCC 4.8, is the situation the same?
Essentially, yes. Or a compiler definition may need to be added, etc. More information for GCC 5 is here: developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi
8

Use:

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(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER} has no C++11 support.") endif() 

This is from Enabling C++11 (C++0x) in CMake with minor changes.

1 Comment

Hello! Unfortunately, your solution only works for compilers that support specified flags for setting C++ standard version. In case of a compiler that supports C++11 but does not support those flags, your solution will give a false negative. For example, MS VS 2015 will not pass.
6

If you are using CMake 3.8 or newer, you can use the feature cxx_std_11, which requests C++11 or above:

target_compile_features(Hello PUBLIC cxx_std_11) 

In CMake 3.1* and newer, the proper, simple way to do this is to use the CXX_STANDARD property for a given target. For example, given this simple example using auto (named main.cpp):

#include <iostream> int main() { auto num = 10; std::cout << num << std::endl; return 0; } 

The following CMakeLists.txt will enable C++11 support:

cmake_minimum_required(VERSION 3.3) project(Hello CXX) set(SOURCE_FILES main.cpp) add_executable(Hello ${SOURCE_FILES}) set_property(TARGET Hello PROPERTY CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON ) 

This will add any flags necessary such as -std=c++11. Note that the CXX_STANDARD_REQUIRED property will prevent the standard from decaying to an earlier version.


Another proper but not as simple way to specify the CMAKE_CXX_KNOWN_FEATURES that you use, such as cxx_auto_type:

cmake_minimum_required(VERSION 3.3) project(Hello CXX) set(SOURCE_FILES main.cpp) add_executable(Hello ${SOURCE_FILES}) target_compile_features(Hello PRIVATE cxx_auto_type) 

* I have not tried this on CMake 3.1, but have verified it works in CMake 3.3. The documentation for 3.1 does document this so it should work.

Comments

1

Putting the principle of Erik Sjölund's answer to better effect:

For CMake versions 3.3 and later, use:

cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(foo CXX) if("cxx_std_11" IN_LIST CMAKE_CXX_COMPILE_FEATURES) # Do something assuming C++11 can be used endif() 

No need to use foreach and such.

Note: Naturally, you can do this with C++17, C++20 and non-standard-version features.

Comments

0

We've written a CMake module for detecting and enabling C++11 support which you can find here:
https://github.com/NitroShare/CXX11-CMake-Macros

It's still a work-in-progress, but we are using it for a number of Qt projects that target Windows/Linux/Mac. Currently only MSVC++, GCC, and Clang are supported.

Example:

include(CXX11) check_for_cxx11_compiler(CXX11_COMPILER) # If a C++11 compiler is available, then set the appropriate flags if(CXX11_COMPILER) enable_cxx11() endif() 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.