如何使用 CMake 检测编译器对 C++11 的支持

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10984442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:42:23  来源:igfitidea点击:

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

c++c++11cmake

提问by tune2fs

Is there a way to let CMake detect automatically if a compiler supports C++11 or not?

有没有办法让 CMake 自动检测编译器是否支持 C++11?

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.

因为在 CMake 运行期间通知用户代码不会编译会很好,因为编译器不支持 C++11。目前我设置了 C++11 标志。但是,如果编译器不支持它,用户会在 CMake 运行期间收到编译错误而不是错误。

Perfect would be something that works like find_package(). However, I have not found any module or function which provides the functionality needed.

完美将是像find_package(). 但是,我还没有找到任何提供所需功能的模块或函数。

Additional it would be nice to have the feature to detect if the compiler needs the flags std=c++0xor std=c++11.

此外,如果能够检测编译器是否需要标志std=c++0xstd=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.

下面是我目前使用的一些代码,但它仅适用于 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)

回答by Erik Sj?lund

If you have CMake version 3.1.0 or later you can detect what C++ features your C++ compiler supports

如果您有 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()

But normally you don't need to use the CMake variable CMAKE_CXX_COMPILE_FEATURESin 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).

但通常您不需要在 CMake 脚本中使用 CMake 变量CMAKE_CXX_COMPILE_FEATURES。相反,有两种方法可以告诉 CMake 您的 C++ 文件应该在哪个 C++ 标准下编译,或者通过明确指定 C++ 标准,或者通过指定所需的 C++ 功能并让 CMake 引入 C++ 标准。CMake 将确保使用正确的命令行标志(例如 -std=c++11)调用 C++ 编译器。

1. Specifying the C++ standard explicitly

1. 明确指定 C++ 标准

You could specify the C++ standard explicitly, by setting the CMake properties CXX_STANDARDand CXX_STANDARD_REQUIREDfor your CMake target.

您可以通过为 CMake 目标设置 CMake 属性CXX_STANDARDCXX_STANDARD_REQUIRED来明确指定 C++ 标准 。

$ 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

2. 指定所需的 C++ 特性,让 CMake 引入 C++ 标准

You could use the CMake command target_compile_featuresto 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_FEATURESlists the C++ features you can choose from.

您可以使用 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()

For example, this C++ program with the filename main.ccmakes use of the C++11 features: cxx_strong_enums, cxx_constexpr, cxx_auto_type

例如,文件名为 main.cc 的C++ 程序利用了 C++11 特性: cxx_strong_enumscxx_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;
}

This CMakeLists.txt file would build it

这个 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})

回答by mavam

At this point, CMake does not have a convenient form to support C++11. Ideally, you would specify a C++11 project like this:

在这一点上,CMake 还没有一个方便的形式来支持 C++11。理想情况下,您可以像这样指定一个 C++11 项目:

project(foo CXX11)

at the beginning of your CMakeLists.txt. But the CXX11project type does not exist (yet). Until then, you may use a two-staged technique:

在您的CMakeLists.txt. 但是CXX11项目类型不存在(还)。在此之前,您可以使用两阶段技术:

  1. Determine the compiler type and version
  2. Adjust build flags accordingly.
  1. 确定编译器类型和版本
  2. 相应地调整构建标志。

For example, this is what I use to support C++11 with Clang and GCC:

例如,这是我使用 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 ()

回答by Matt McCormick

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.

在撰写本文时(GCC 4.8 之前),检测 C++11 标志并添加它们可能不是一个好主意。这是因为更改标准(至少对于 GCC)会破坏 ABI 兼容性,这会导致链接错误。

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.

因此,在项目初始 CMake 配置期间,应使用编译器设置明确指定 C++11 标准的使用,例如

CXX='g++ -std=c++11' cmake /path/to/source

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.

即 -std=c++11 的使用应该被当作一个单独的编译器来对待,不应在一个项目中混合或更改。

回答by nkout

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 CMakewith minor changes.

这是来自在 CMake 中启用 C++11 (C++0x) 的小改动。

回答by Levi Morrison

If you are using CMake 3.8 or newer, you can use the feature cxx_std_11, which requests C++11 or above:

如果您使用的是 CMake 3.8 或更高版本,则可以使用cxx_std_11要求C++11 或更高版本的功能

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_STANDARDproperty for a given target. For example, given this simple example using auto(named main.cpp):

在 CMake 3.1* 和更新版本中,正确、简单的方法是使用CXX_STANDARD给定目标的属性。例如,给出这个使用auto(named main.cpp) 的简单示例:

#include <iostream>

int main() {
    auto num = 10;
    std::cout << num << std::endl;
    return 0;
}

The following CMakeLists.txtwill enable C++11 support:

以下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
)

This will add any flags necessary such as -std=c++11. Note that the CXX_STANDARD_REQUIREDproperty will prevent the standard from decaying to an earlier version.

这将添加任何必要的标志,例如-std=c++11. 请注意,该CXX_STANDARD_REQUIRED属性将防止标准衰减到早期版本。



Another proper but not as simple way to specify the CMAKE_CXX_KNOWN_FEATURESthat you use, such as cxx_auto_type:

另一种适当但不那么简单的方法来指定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)


* I have not tried this on CMake 3.1, but have verified it works in CMake 3.3. The documentation for 3.1does document this so it should work.

* 我没有在 CMake 3.1 上尝试过这个,但已经验证它在 CMake 3.3 中有效。3.1文档确实记录了这一点,因此它应该可以工作。

回答by Nathan Osman

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

我们编写了一个用于检测和启用 C++11 支持的 CMake 模块,您可以在此处找到: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.

它仍在进行中,但我们正在将它用于许多面向 Windows/Linux/Mac 的 Qt 项目。目前仅支持 MSVC++、GCC 和 Clang。

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