Как определить поддержку C++11 компилятора с CMake
Есть ли способ позволить CMake автоматически определять, поддерживает ли компилятор C++11 или нет?
Как было бы хорошо сообщить пользователям во время запуска CMake, что код не будет компилироваться, так как компилятор не поддерживает C++11. На данный момент я установил флаги C++11. Однако, если компилятор не поддерживает его, пользователь получает ошибки компиляции вместо ошибки во время запуска CMake.
Идеальным было бы то, что работает как find_package()
, Однако я не нашел ни одного модуля или функции, которые бы обеспечивали необходимую функциональность.
Дополнительно было бы неплохо иметь возможность определять, нужны ли компилятору флаги std=c++0x
или же std=c++11
,
Есть ли что-то доступное или мне нужно разработать это самостоятельно?
Ниже приведен код, который я использую до сих пор, однако он работает только с компиляторами GCC GNU'C. Было бы неплохо, если бы было более общее решение.
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)
8 ответов
Если у вас 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
хоть.
На момент написания этой статьи (до 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()
Чтобы добиться большего эффекта, Эрика Шёлунда user757777 принцип ответа
Для версий CMake 3.3 и более поздних используйте:
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()
Нет необходимости использоватьforeach
и тому подобное.
Примечание. Естественно, вы можете сделать это с помощью функций C++17, C++20 и нестандартных версий.