How to Detect C++11 Support of a Compiler With Cmake

How to detect C++11 support of a compiler with CMake

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
$

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

How do I activate C++ 11 in CMake?

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

check if a c++11 feature is enabled in compiler with CMAKE

You can use target_compile_features to require a C++11(/14/17) feature:

target_compile_features(target PRIVATE|PUBLIC|INTERFACE feature1 [feature2 ...])

With feature1 being a feature listed in CMAKE_CXX_KNOWN_FEATURES. For example, if you want to use constexpr in your public API, you can use:

add_library(foo ...)
target_compile_features(foo PUBLIC cxx_constexpr)

You should also take a look at the WriteCompilerDetectionHeader module which allows to detect features as options, and provides a backward compatibility implementation for some features if the compiler does not support them:

write_compiler_detection_header(
FILE foo_compiler_detection.h
PREFIX FOO
COMPILERS GNU MSVC
FEATURES cxx_constexpr cxx_nullptr
)

Here a file foo_compiler_detection.h will be generated with FOO_COMPILER_CXX_CONSTEXPR defined if the keyword constexpr is available:

#include "foo_compiler_detection.h"

#if FOO_COMPILER_CXX_CONSTEXPR

// implementation with constexpr available
constexpr int bar = 0;

#else

// implementation with constexpr not available
const int bar = 0;

#endif

Moreover, FOO_CONSTEXPR will be defined and will expand to constexpr if the feature exists for the current compiler. It will be empty otherwise.

FOO_NULLPTR will be defined and will expand to nullptr if the feature exists for the current compiler. It will expand to a compatibility implementation otherwise (e.g. NULL).

#include "foo_compiler_detection.h"

FOO_CONSTEXPR int bar = 0;

void baz(int* p = FOO_NULLPTR);

See CMake documentation.

cmake will not compile to C++ 11 standard

In CMake versions earlier than 3.1, we use

 add_compile_options(-std=c++11) # CMake 2.8.12 or newer

to add compile options to the compiler call as described in the CMake Docs.

That's propably not as portable as the one in Alvaro's answer, but it's more readable and since you are on you RasPi, I guess, GCC and Clang as target compilers will do.

Edit: For the sake of completeness: In CMake version 3.1 and newer, if you want to force C++11, you need the following lines:

set(CMAKE_CXX_STANDARD 11) # C++11...
set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required...
set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11

This enables the options for all targets following this declaration during compilation. If you want to control this more fine-grained, see Alvaro's answer or the CMake Docs of set_taget_properties(), which then looks something like this:

set_target_properties(myTarget PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)

Edit: But beware that C++11 support in GCC 4 is not complete and there might be things that behave differently from the defined standard.

The C++ compiler does not support C++11 (e.g. std::unique_ptr). building OpenWRT

I paste my solution here so that someone might get my hint (or it might not because of this reason)

after search millions of pages and people just talk about why but not how, my solution is simply:

copied cmake source code to my system drive. if you make cmake on a remote hardrive it will fail and error just like above



Related Topics



Leave a reply



Submit