/ cmake / module / TryAppendCXXFlags.cmake
TryAppendCXXFlags.cmake
  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()