# # Copyright © 2018-2021 pastdue ( https://github.com/past-due/ ) and contributors # License: MIT License ( https://opensource.org/licenses/MIT ) # # Script Version: 2021-05-21a # # ADD_TARGET_LINK_FLAGS_IF_SUPPORTED( TARGET # [COMPILER_TYPE = CXX] # LINK_FLAGS # [CONFIG ] # [CACHED_RESULT_NAME ] # [QUIET = FAILURES] ) # # ADD_TARGET_LINK_FLAGS_IF_SUPPORTED adds the specified link flags to the target if # the link flags seem to be supported by the current (specified) compiler + linker. # # If COMPILER_TYPE C is specified, this checks if the configured C compiler + linker # seems to support the link flags. If COMPILER_TYPE CXX is specified, this checks # if the configured CXX compiler + linker seems to support the link flags. The # default COMPILER_TYPE is CXX. # # If CACHED_RESULT_NAME is specified, the result of the link-flag check will be stored # in a CACHE variable with the name ${CACHED_RESULT_NAME}. Every subsequent CMake run # will re-use this cached value rather than performing the check again, even if the # ``code`` changes. If you wish to perform the check anew on every CMake run, omit # the CACHED_RESULT_NAME parameter. (In most cases, using a CACHED_RESULT_NAME is # recommended.) # # QUIET can be specified to control message output with one of the following settings: # "ALL" - do NOT output any messages # "FAILIRES" - do NOT output messages on any failures # "OFF" - all output is enabled # function(ADD_TARGET_LINK_FLAGS_IF_SUPPORTED) set(_options) set(_oneValueArgs TARGET COMPILER_TYPE LINK_FLAGS CONFIG CACHED_RESULT_NAME QUIET) set(_multiValueArgs) CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) if(NOT DEFINED _parsedArguments_TARGET) message( FATAL_ERROR "ADD_TARGET_LINK_FLAGS_IF_SUPPORTED requires TARGET" ) endif() if(NOT DEFINED _parsedArguments_LINK_FLAGS) message( FATAL_ERROR "ADD_TARGET_LINK_FLAGS_IF_SUPPORTED requires LINK_FLAGS" ) endif() if(DEFINED _parsedArguments_QUIET) if(NOT _parsedArguments_QUIET MATCHES "^(ALL|FAILURES|OFF)$") message( FATAL_ERROR "ADD_TARGET_LINK_FLAGS_IF_SUPPORTED invalid QUIET value - must be one of: (ALL, FAILURES, OFF)" ) endif() else() set(_parsedArguments_QUIET "FAILURES") endif() if(NOT DEFINED _parsedArguments_COMPILER_TYPE) set(_parsedArguments_COMPILER_TYPE "CXX") endif() set(_link_flags_config_suffix) if(DEFINED _parsedArguments_CONFIG) set(_link_flags_config_suffix "_${_parsedArguments_CONFIG}") endif() set(_check_cached_status) if(_parsedArguments_CACHED_RESULT_NAME) if(DEFINED "${_parsedArguments_CACHED_RESULT_NAME}") set(_check_cached_status " (cached)") endif() set(_cached_result_variable_name "${_parsedArguments_CACHED_RESULT_NAME}") else() # Generate a temporary variable name that isn't in the cache while(NOT _cached_result_variable_name) string(RANDOM LENGTH 12 _tmpRandom) set(_tmpRandom "_NOCACHE_tmp_rnd_${_tmpRandom}") if(NOT DEFINED "${_tmpRandom}") set(_cached_result_variable_name "${_tmpRandom}") endif() endwhile() endif() if(_parsedArguments_COMPILER_TYPE MATCHES "CXX") CHECK_CXX_LINKER_FLAGS("${_parsedArguments_LINK_FLAGS}" ${_cached_result_variable_name} QUIET) elseif(_parsedArguments_COMPILER_TYPE MATCHES "C") CHECK_C_LINKER_FLAGS("${_parsedArguments_LINK_FLAGS}" ${_cached_result_variable_name} QUIET) else() message( FATAL_ERROR "ADD_TARGET_LINK_FLAGS_IF_SUPPORTED invalid COMPILER_TYPE value - must be one of: (C, CXX)" ) endif() if(${_cached_result_variable_name}) if(NOT _parsedArguments_QUIET OR _parsedArguments_QUIET MATCHES "FAILURES") message( STATUS "Set TARGET ${_parsedArguments_TARGET} LINK_FLAG${_link_flags_config_suffix}: ${_parsedArguments_LINK_FLAGS} ... YES${_check_cached_status}" ) endif() set_property(TARGET ${_parsedArguments_TARGET} APPEND_STRING PROPERTY "LINK_FLAGS${_link_flags_config_suffix}" " ${_parsedArguments_LINK_FLAGS}") else() if(NOT _parsedArguments_QUIET) message( STATUS "Set TARGET ${_parsedArguments_TARGET} LINK_FLAG${_link_flags_config_suffix}: ${_parsedArguments_LINK_FLAGS} ... no${_check_cached_status}" ) endif() endif() if(NOT _parsedArguments_CACHED_RESULT_NAME) # Unset the temporary cached variable that CHECK_CXX_LINKER_FLAG populated unset(_cached_result_variable_name CACHE) endif() endfunction() INCLUDE(CheckCSourceRuns) INCLUDE(CheckCSourceCompiles) # CHECK_C_LINKER_FLAGS( <_FLAGS> <_RESULT> # [QUIET] ) function(CHECK_C_LINKER_FLAGS _FLAGS _RESULT) set(_options QUIET) set(_oneValueArgs) set(_multiValueArgs) CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) set(_cmake_required_link_options_varname "CMAKE_REQUIRED_LINK_OPTIONS") if (CMAKE_VERSION VERSION_LESS 3.14) # CMake < 3.14 does not support CMAKE_REQUIRED_LINK_OPTIONS, so use CMAKE_REQUIRED_FLAGS (but this may fail in some cases) set(_cmake_required_link_options_varname "CMAKE_REQUIRED_FLAGS") endif() set(${_cmake_required_link_options_varname} "${_FLAGS}") if(_parsedArguments_QUIET) set(CMAKE_REQUIRED_QUIET ON) endif() set(_test_source "int main() { return 0; }") if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_GENERATOR_PLATFORM) CHECK_C_SOURCE_RUNS("${_test_source}" ${_RESULT}) else() CHECK_C_SOURCE_COMPILES("${_test_source}" ${_RESULT}) endif() if(_parsedArguments_QUIET) unset(CMAKE_REQUIRED_QUIET) endif() set(${_cmake_required_link_options_varname} "") endfunction(CHECK_C_LINKER_FLAGS) INCLUDE(CheckCXXSourceRuns) INCLUDE(CheckCXXSourceCompiles) # CHECK_CXX_LINKER_FLAGS( <_FLAGS> <_RESULT> # [QUIET] ) function(CHECK_CXX_LINKER_FLAGS _FLAGS _RESULT) set(_options QUIET) set(_oneValueArgs) set(_multiValueArgs) CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) set(_cmake_required_link_options_varname "CMAKE_REQUIRED_LINK_OPTIONS") if (CMAKE_VERSION VERSION_LESS 3.14) # CMake < 3.14 does not support CMAKE_REQUIRED_LINK_OPTIONS, so use CMAKE_REQUIRED_FLAGS (but this may fail in some cases) set(_cmake_required_link_options_varname "CMAKE_REQUIRED_FLAGS") endif() set(${_cmake_required_link_options_varname} "${_FLAGS}") if(_parsedArguments_QUIET) set(CMAKE_REQUIRED_QUIET ON) endif() set(_test_source "int main() { return 0; }") if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_GENERATOR_PLATFORM) CHECK_CXX_SOURCE_RUNS("${_test_source}" ${_RESULT}) else() CHECK_CXX_SOURCE_COMPILES("${_test_source}" ${_RESULT}) endif() if(_parsedArguments_QUIET) unset(CMAKE_REQUIRED_QUIET) endif() set(${_cmake_required_link_options_varname} "") endfunction(CHECK_CXX_LINKER_FLAGS)