使用CMake检测支持的C++标准

7

我有一个基于CMake的小型C++11库,可以通过使用一些C++14和C++17功能来改进。

为此,我希望CMake测试是否在列表CMAKE_CXX_COMPILE_FEATURES中包含cxx_std_14和/或cxx_std_17,正如相关SO问题如何使用CMake检测编译器对C++11支持中所示。

然而,我无法完全弄清楚如何编写此测试。我认为应该可行的方法并不奏效:

list (FIND ${CMAKE_CXX_COMPILE_FEATURES} "cxx_std_14" _index)
if (${_index} GREATER -1)
   message("YAY 14")
else()
   message("NAY 14")
endif()

# -> CMake Error .... (list):
#      list sub-command FIND requires three arguments

因为最低CMake版本是2.8.7,所以我必须使用list(FIND ...)而不是更新、更简洁的IN_LIST

CMAKE_CXX_COMPILE_FEATURES看起来像是由分号分隔的字符串,因此这个丑陋的代码片段可以正常工作:

if ("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_14")
    message("YAY 14")
else()
    message("NAY 14")
endif()

当然,这不是正确的做法......如有帮助,将不胜感激。

如果这是一个库,难道你不想迎合目标系统的编译器而不是库构建系统的编译器吗?例如,为什么不使用 #ifdef if __cplusplus > 201402L 等方式,而要使用 CMake 呢? - einpoklum
3
list 命令接受 列表名称,而不是其内容。正确的用法是:list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_str_14" _index) - Tsyvarev
据我了解,在跨平台和编译器上检测C++14或C++17,__cplusplus并不是一种可靠的方法。 - mcmayer
@Tsyvarev 啊... 是的确实。 - mcmayer
@mcmayer:您错了……这个宏是标准的正式部分;如果编译器没有提供它,那就意味着它不可靠地支持标准。无数的库(可能包括标准库)都依赖于它。 - einpoklum
1个回答

0

我不知道这是好的还是坏的方式,但我通过枚举我支持的可能编译器来实现它:

set(CompilerName_tmp "${CMAKE_CXX_COMPILER_ID}")
string(TOLOWER "${CompilerName_tmp}" CompilerName_tmp)
set(CompilerVersion_tmp "${CMAKE_CXX_COMPILER_VERSION}")
if(LINUX)
    if("${CompilerName_tmp}" STREQUAL "gnu")
        set(CompilerName_tmp "gcc")
        endif()
        if("${CompilerVersion_tmp}" VERSION_LESS "4.8.1")
            set(Cxx11Available FALSE CACHE INTERNAL "")
        else()
            set(Cxx11Available TRUE CACHE INTERNAL "")
        endif()
    else()
        message(FATAL_ERROR "Unexpected compiler: ${CMAKE_CXX_COMPILER}")
    endif()
elseif(WINDOWS)
    if("${CompilerName_tmp}" STREQUAL "intel")
        if("${CompilerVersion_tmp}" VERSION_LESS "15.0.0")
            set(Cxx11Available FALSE CACHE INTERNAL "")
        else()
            set(Cxx11Available TRUE CACHE INTERNAL "")
        endif()
    else()
        message(FATAL_ERROR "Unexpected compiler: ${CMAKE_CXX_COMPILER}")
    endif()
endif()

另一种可能性是将您使用的所有C++11功能放在一个示例中,并在配置期间尝试使用try_compile进行编译。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接