Reputation: 7705
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)
Upvotes: 88
Views: 62485
Reputation: 132202
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.
Upvotes: 0
Reputation: 11408
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).
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
$
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})
Upvotes: 111
Reputation: 19552
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.
Upvotes: 6
Reputation: 491
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.
Upvotes: 8
Reputation: 73295
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()
Upvotes: 0
Reputation: 314
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.
Upvotes: 9
Reputation: 12572
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:
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 ()
Upvotes: 39