7

I have a small cmake-based C++11 library that could be improved by using some C++14 and some C++17 features.

To that end I want CMake to test whether cxx_std_14 and/or cxx_std_17is in the list CMAKE_CXX_COMPILE_FEATURES, as hinted at in the related SO question How to detect C++11 support of a compiler with CMake.

I can't quite figure out how to write this test, though. What I think should work, doesn't:

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

(Because the mimumum CMake version is 2.8.7 I have to use list(FIND ...) instead of the newer, more concise IN_LIST).

CMAKE_CXX_COMPILE_FEATURES seems to be a semicolon-separated string, so this ugly snippet works:

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

Surely, this isn't the proper way to do it... Any help would be appreciated.

mcmayer
  • 1,931
  • 12
  • 22
  • If it's a _library_, don't you want to cater to the target system's compiler rather than the library build system's compiler? e.g. why do this with CMake rather than with `#ifdef if __cplusplus > 201402L` and such? – einpoklum Jul 15 '20 at 09:00
  • 3
    `list` commands accept the **list name**, not its *content*. Correct usage is: `list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_str_14" _index)`. – Tsyvarev Jul 15 '20 at 09:02
  • @einpoklum As far as I understand, `__cplusplus` is not a sure thing (across platforms and compilers) for detecting C++14 or C++17. – mcmayer Jul 15 '20 at 09:02
  • @Tsyvarev Aah... Yes indeed. – mcmayer Jul 15 '20 at 09:05
  • @mcmayer: You are mistaken... this macro [is an official part of the standard](https://stackoverflow.com/q/26089319/1593077); if the compiler doesn't provide it, that means it doesn't reliably support the standard. Infinitely many libraries (probably including the standard libraries) rely on it. – einpoklum Jul 15 '20 at 10:01

1 Answers1

0

I don't know if it's a good or bad way, but I do it by enumerating the possible compilers I support:

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

Another possibility is to put all the C++11 features you use in a single example, and try to compile it with try_compile during the configuration.

Caduchon
  • 4,574
  • 4
  • 26
  • 67