如何使用 CMake 检测编译器的 C++11 支持
How to detect C++11 support of a compiler with 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)
如果您使用的是 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 变量CMAKE_CXX_COMPILE_FEATURES。相反,有两种方法可以告诉CMake C++应该在哪个标准下编译您的C++文件,或者明确指定C++标准或通过指定所需的C++功能,让CMake诱导C++标准。CMake 将确保使用正确的命令行标志调用C++编译器(例如 -std=c++11)。
- 明确指定C++标准
可以通过设置 CMake 属性来显式指定C++标准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
$
- 指定所需的C++特征,让CMake诱导C++标准
可以使用 CMake 命令target_compile_features指定在 CMake 目标中使用的C++功能。从这个列表中,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()
例如,文件名为 main.cc 的这个C++程序利用了 C++11 功能:cxx_strong_enums、cxx_constexprcxx_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
项目类型尚不存在。在此之前,您可以使用两阶段技术:
- 确定编译器类型和版本
- 相应地调整构建标志。
例如,这是我用来支持 Clang 和 GCC 的 C++11 的内容:
# 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 ()
在撰写本文时(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()
这是来自 CMake 中的启用 C++11 (C++0x),稍作更改。
如果您使用的是 CMake 3.8 或更高版本,则可以使用请求 C++11 或更高版本的功能cxx_std_11
:
target_compile_features(Hello PUBLIC cxx_std_11)
在 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
它仍然是一个正在进行的工作,但我们正在将其用于许多针对Windows/Linux/Mac的Qt项目。 目前仅支持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()
将 Erik Sjölund 的答案原则发挥得更好:
对于 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 和非标准版本功能执行此操作。
- MSVC是否支持C++11样式的属性而不是__declspec
- 如何检测VS C++编译器是否支持C++11?
- 在 c++ 中连接字符串和整数,以便在 C++ 11 不支持计算机的情况下读取多个文件
- C++11 NVCC 不支持函数 iota()?
- 编译具有Contrib和C++11支持的OpenCV?
- OpenCV 4.x+ 需要启用 C++11 支持编译暗网致命错误
- 为什么 GCC 6.3 在没有显式 C++11 支持的情况下编译此大括号初始化列表代码
- 如何在 Eclipse 中启用 C++11 支持
- 在Apple llvm 4.1上使用libc++与libstc++时,c++11支持的确切区别是什么
- 升级到G 4.7(带有C 11支持):任何ABI不兼容
- 如何使用 CMake 检测编译器的 C++11 支持
- clang 的 c++11 支持可靠吗?
- Clang 3.1 和 C++11 支持状态
- 在每个Qt Creator项目中添加C++11支持
- 未在具有c++11支持的scopet中声明nullptr
- 通过cmake在VS 2013中启用c++ 11支持
- Android上启用c++ 11支持
- 将 C++11 支持添加到 Makefile
- 'for each'不是 std 的成员。 已启用 C++11 支持
- 在xcode 4.5.2中编译带有c++ 11支持的混合objective-C/ c++项目时出现链接错误