TryAppendCXXFlags.cmake raw

   1  # Copyright (c) 2023-present The Bitcoin Core developers
   2  # Distributed under the MIT software license, see the accompanying
   3  # file COPYING or https://opensource.org/license/mit/.
   4  
   5  include_guard(GLOBAL)
   6  include(CheckCXXSourceCompiles)
   7  
   8  #[=[
   9  Add language-wide flags, which will be passed to all invocations of the compiler.
  10  This includes invocations that drive compiling and those that drive linking.
  11  
  12  Usage examples:
  13  
  14    try_append_cxx_flags("-Wformat -Wformat-security" VAR warn_cxx_flags)
  15  
  16  
  17    try_append_cxx_flags("-Wsuggest-override" VAR warn_cxx_flags
  18      SOURCE "struct A { virtual void f(); }; struct B : A { void f() final; };"
  19    )
  20  
  21  
  22    try_append_cxx_flags("-fsanitize=${SANITIZERS}" TARGET core_interface
  23      RESULT_VAR cxx_supports_sanitizers
  24    )
  25    if(NOT cxx_supports_sanitizers)
  26      message(FATAL_ERROR "Compiler did not accept requested flags.")
  27    endif()
  28  
  29  
  30    try_append_cxx_flags("-Wunused-parameter" TARGET core_interface
  31      IF_CHECK_PASSED "-Wno-unused-parameter"
  32    )
  33  
  34  
  35  In configuration output, this function prints a string by the following pattern:
  36  
  37    -- Performing Test CXX_SUPPORTS_[flags]
  38    -- Performing Test CXX_SUPPORTS_[flags] - Success
  39  
  40  ]=]
  41  function(try_append_cxx_flags flags)
  42    cmake_parse_arguments(PARSE_ARGV 1
  43      TACXXF                            # prefix
  44      "SKIP_LINK"                       # options
  45      "TARGET;VAR;SOURCE;RESULT_VAR"    # one_value_keywords
  46      "IF_CHECK_PASSED"                 # multi_value_keywords
  47    )
  48  
  49    set(flags_as_string "${flags}")
  50    separate_arguments(flags)
  51  
  52    string(MAKE_C_IDENTIFIER "${flags_as_string}" id_string)
  53    string(TOUPPER "${id_string}" id_string)
  54  
  55    set(source "int main() { return 0; }")
  56    if(DEFINED TACXXF_SOURCE AND NOT TACXXF_SOURCE STREQUAL source)
  57      set(source "${TACXXF_SOURCE}")
  58      string(SHA256 source_hash "${source}")
  59      string(SUBSTRING ${source_hash} 0 4 source_hash_head)
  60      string(APPEND id_string _${source_hash_head})
  61    endif()
  62  
  63    # This avoids running a linker.
  64    set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
  65    set(CMAKE_REQUIRED_FLAGS "${flags_as_string} ${working_compiler_werror_flag}")
  66    set(compiler_result CXX_SUPPORTS_${id_string})
  67    check_cxx_source_compiles("${source}" ${compiler_result})
  68  
  69    if(${compiler_result})
  70      if(DEFINED TACXXF_IF_CHECK_PASSED)
  71        if(DEFINED TACXXF_TARGET)
  72          target_compile_options(${TACXXF_TARGET} INTERFACE ${TACXXF_IF_CHECK_PASSED})
  73        endif()
  74        if(DEFINED TACXXF_VAR)
  75          list(JOIN TACXXF_IF_CHECK_PASSED " " flags_if_check_passed_as_string)
  76          string(STRIP "${${TACXXF_VAR}} ${flags_if_check_passed_as_string}" ${TACXXF_VAR})
  77        endif()
  78      else()
  79        if(DEFINED TACXXF_TARGET)
  80          target_compile_options(${TACXXF_TARGET} INTERFACE ${flags})
  81        endif()
  82        if(DEFINED TACXXF_VAR)
  83          string(STRIP "${${TACXXF_VAR}} ${flags_as_string}" ${TACXXF_VAR})
  84        endif()
  85      endif()
  86    endif()
  87  
  88    if(DEFINED TACXXF_VAR)
  89      set(${TACXXF_VAR} "${${TACXXF_VAR}}" PARENT_SCOPE)
  90    endif()
  91  
  92    if(DEFINED TACXXF_RESULT_VAR)
  93      set(${TACXXF_RESULT_VAR} "${${compiler_result}}" PARENT_SCOPE)
  94    endif()
  95  
  96    if(NOT ${compiler_result} OR TACXXF_SKIP_LINK)
  97      return()
  98    endif()
  99  
 100    # This forces running a linker.
 101    set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE)
 102    set(CMAKE_REQUIRED_FLAGS "${flags_as_string}")
 103    set(CMAKE_REQUIRED_LINK_OPTIONS ${working_linker_werror_flag})
 104    set(linker_result LINKER_SUPPORTS_${id_string})
 105    check_cxx_source_compiles("${source}" ${linker_result})
 106  
 107    if(${linker_result})
 108      if(DEFINED TACXXF_IF_CHECK_PASSED)
 109        if(DEFINED TACXXF_TARGET)
 110          target_link_options(${TACXXF_TARGET} INTERFACE ${TACXXF_IF_CHECK_PASSED})
 111        endif()
 112      else()
 113        if(DEFINED TACXXF_TARGET)
 114          target_link_options(${TACXXF_TARGET} INTERFACE ${flags})
 115        endif()
 116      endif()
 117    else()
 118      message(WARNING "'${flags_as_string}' fail(s) to link.")
 119    endif()
 120  endfunction()
 121  
 122  if(MSVC)
 123    try_append_cxx_flags("/WX /options:strict" VAR working_compiler_werror_flag SKIP_LINK)
 124  else()
 125    try_append_cxx_flags("-Werror" VAR working_compiler_werror_flag SKIP_LINK)
 126  endif()
 127