Как определить поддержку C++11 компилятора С помощью CMake
есть ли способ позволить CMake автоматически определять, поддерживает ли компилятор C++11 или нет?
как было бы неплохо сообщить пользователям во время выполнения CMake, что код не будет компилироваться, поскольку компилятор не поддерживает C++11. На данный момент я установил флаги C++11. Однако, если компилятор не поддерживает его, пользователь получает ошибки компиляции вместо ошибки во время выполнения CMake.
идеально было бы что-то, что работает как find_package()
. Однако, я не нашел ни одного модуль или функция, которая обеспечивает необходимую функциональность.
дополнительно было бы неплохо иметь функцию для обнаружения, если компилятору нужны флаги std=c++0x
или std=c++11
.
есть ли что-то доступное или мне нужно разработать это самостоятельно?
Ниже приведен некоторый код, который я использую до сих пор, однако он работает только с компиляторами GNU'c GCC. Было бы неплохо, если бы было более общее решение.
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)
7 ответов:
если у вас есть CMake версии 3.1.0 или более поздней, вы можете определить, какие функции C++ ваш компилятор C++ поддерживает
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()
но обычно вам не нужно использовать переменную CMake CMAKE_CXX_COMPILE_FEATURES в ваших сценариях CMake. Вместо этого есть два способа, как сказать CMake, под которым стандарт C++ ваши файлы C++ должны быть скомпилированы, либо указание стандарта C++ явно или путем указания необходимых функций C++ и пусть CMake индуцирует стандарт C++. CMake будет убедиться, что компилятор C++ вызывается с правильными флагами командной строки (например,- std=c++11).
1. Указание стандарта C++ явно
вы можете указать стандарт C++ явно, установив свойства CMake CXX_STANDARD и CXX_STANDARD_REQUIRED для вашей цели CMake.
$ 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. Указание необходимых функций C++ и пусть CMake индуцирует C++ стандарт
вы можете использовать команду CMake target_compile_features чтобы указать функции C++, которые используются в вашей цели CMake. Из этого списка с CMake будет стимулировать стандарт C++, чтобы быть использованы. В случае с CMake глобальной собственность CMAKE_CXX_KNOWN_FEATURES список функций C++, которые вы можете выбрать.
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()
например, эта программа на C++ с именем main.cc использует Особенности C++11: 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; }
Это CMakeLists.txt файл будет строить его
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})
на данный момент CMake не имеет удобной формы для поддержки C++11. В идеале, вы должны указать проект C++11 вроде этого:
project(foo CXX11)
в начале
CMakeLists.txt
. Но этоCXX11
тип проекта не существует (пока). До тех пор вы можете использовать двухэтапную технику:
- Определите тип и версию компилятора
- отрегулируйте флаги сборки соответственно.
например, это то, что я использую для поддержки C++11 с Clang и 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 ()
нашел этот сценарий CMake который утверждает, что делает именно то, что вам нужно. Он также может проверить наличие отдельных функций C++11. Я не думаю, что он может решить между
std=C++0x
иstd=C++11
хотя.
на момент написания этой статьи (pre-GCC 4.8), возможно, не стоит обнаруживать флаги C++11 и добавлять их. Это связано с изменением стандарта (по крайней мере, для GCC) нарушает совместимость ABI, что может привести к ошибкам связи.
поэтому использование стандарта C++11 должно быть явно указано с помощью параметра компилятора во время начальная конфигурация CMake проекта, например,
CXX='g++ -std=c++11' cmake /path/to/source
то есть использование-std=c++11 должно рассматриваться как отдельный компилятор, который не должен быть смешан или изменен в проекте.
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()
от http://www.guyrutenberg.com/2014/01/05/enabling-c11-c0x-in-cmake/ с незначительными изменениями
в CMake 3.1 * правильный, простой способ сделать это-использовать
CXX_STANDARD
свойство для заданной цели. Например, учитывая этот простой пример с помощьюauto
(названиеmain.cpp
):#include <iostream> int main() { auto num = 10; std::cout << num << std::endl; return 0; }
следующее
CMakeLists.txt
включит поддержку C++11: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 )
это добавит любые необходимые флаги, такие как
-std=c++11
. Обратите внимание, чтоCXX_STANDARD_REQUIRED
свойство предотвратит распад стандарта на более раннюю версию.
правильный, не такой простой способ чтобы указать
CMAKE_CXX_KNOWN_FEATURES
что вы используете, например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)
* я не пробовал это на CMake 3.1, но проверил, что он работает в CMake 3.3. Элемент документация 3.1 документирует это, поэтому он должен работать.
мы написали модуль CMake для обнаружения и включения поддержки C++11, который вы можете найти здесь:
https://github.com/NitroShare/CXX11-CMake-MacrosЭто все еще незавершенная работа, но мы используем ее для ряда проектов Qt, которые нацелены на Windows/Linux/Mac. В настоящее время поддерживаются только MSVC++, GCC и Clang.
пример:
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()