From af96c0f4faf5bf9f4a4dbc958b09a1dfc58dab38 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Sat, 16 May 2020 17:01:23 +0200 Subject: CheckLinkerFlag: Add module to check validity of linker flags Fixes: #15934 --- Help/manual/cmake-modules.7.rst | 1 + Help/module/CheckLinkerFlag.rst | 1 + Help/release/dev/CheckLinkerFlag.rst | 5 ++ Modules/CheckLinkerFlag.cmake | 81 ++++++++++++++++++++++ Tests/RunCMake/CMakeLists.txt | 6 ++ Tests/RunCMake/CheckLinkerFlag/CMakeLists.txt | 5 ++ .../CheckLinkerFlag/CheckCLinkerFlag.cmake | 3 + .../CheckLinkerFlag/CheckCXXLinkerFlag.cmake | 3 + .../CheckLinkerFlag/CheckFortranLinkerFlag.cmake | 3 + .../RunCMake/CheckLinkerFlag/CheckLinkerFlag.cmake | 14 ++++ .../CheckLinkerFlag/CheckOBJCLinkerFlag.cmake | 3 + .../CheckLinkerFlag/CheckOBJCXXLinkerFlag.cmake | 3 + Tests/RunCMake/CheckLinkerFlag/RunCMakeTest.cmake | 14 ++++ 13 files changed, 142 insertions(+) create mode 100644 Help/module/CheckLinkerFlag.rst create mode 100644 Help/release/dev/CheckLinkerFlag.rst create mode 100644 Modules/CheckLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/CMakeLists.txt create mode 100644 Tests/RunCMake/CheckLinkerFlag/CheckCLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/CheckCXXLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/CheckFortranLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/CheckLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/CheckOBJCLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/CheckOBJCXXLinkerFlag.cmake create mode 100644 Tests/RunCMake/CheckLinkerFlag/RunCMakeTest.cmake diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index be64112..50131e8 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -36,6 +36,7 @@ These modules are loaded using the :command:`include` command. /module/CheckIncludeFiles /module/CheckLanguage /module/CheckLibraryExists + /module/CheckLinkerFlag /module/CheckOBJCCompilerFlag /module/CheckOBJCSourceCompiles /module/CheckOBJCSourceRuns diff --git a/Help/module/CheckLinkerFlag.rst b/Help/module/CheckLinkerFlag.rst new file mode 100644 index 0000000..4005725 --- /dev/null +++ b/Help/module/CheckLinkerFlag.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckLinkerFlag.cmake diff --git a/Help/release/dev/CheckLinkerFlag.rst b/Help/release/dev/CheckLinkerFlag.rst new file mode 100644 index 0000000..fd48d99 --- /dev/null +++ b/Help/release/dev/CheckLinkerFlag.rst @@ -0,0 +1,5 @@ +CheckLinkerFlag +--------------- + +* New :module:`CheckLinkerFlag` module has been added to provide a facility to + check validity of link flags. diff --git a/Modules/CheckLinkerFlag.cmake b/Modules/CheckLinkerFlag.cmake new file mode 100644 index 0000000..beda5fe --- /dev/null +++ b/Modules/CheckLinkerFlag.cmake @@ -0,0 +1,81 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckLinkerFlag +--------------- + +Check whether the compiler supports a given link flag. + +.. command:: check_linker_flag + + .. code-block:: cmake + + check_linker_flag( ) + +Check that the link ```` is accepted by the ```` compiler without +a diagnostic. Stores the result in an internal cache entry named ````. + +This command temporarily sets the ``CMAKE_REQUIRED_LINK_OPTIONS`` variable +and calls the ``check__source_compiles`` macro from the +``CheckSourceCompiles`` module (:module:`CheckCSourceCompiles`, +:module:`CheckCSourceCompiles`, :module:`CheckCXXSourceCompiles`, +:module:`CheckOBJCSourceCompiles`, :module:`CheckOBJCXXSourceCompiles` or +:module:`CheckFortranSourceCompiles`). See documentation of these +modules for a listing of variables that can otherwise modify the build. + +The underlying implementation rely on :prop_tgt:`LINK_OPTIONS` property to +check the specified flag. The ``LINKER:`` prefix, as described in +:command:`target_link_options` command, can be used as well. + +A positive result from this check indicates only that the compiler did not +issue a diagnostic message when given the link flag. Whether the flag has any +effect or even a specific one is beyond the scope of this module. + +.. note:: + Since the :command:`try_compile` command forwards flags from variables + like :variable:`CMAKE__FLAGS`, unknown flags in such variables may + cause a false negative for this check. +#]=======================================================================] + +include_guard(GLOBAL) + +include(CMakeCheckCompilerFlagCommonPatterns) + +function(CHECK_LINKER_FLAG _lang _flag _var) + get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES) + if (NOT _lang IN_LIST _supported_languages) + message (SEND_ERROR "check_linker_flag: ${_lang}: unknown language.") + return() + endif() + + include (Check${_lang}SourceCompiles) + + set(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}") + + # Normalize locale during test compilation. + set(_locale_vars LC_ALL LC_MESSAGES LANG) + foreach(v IN LISTS _locale_vars) + set(_locale_vars_saved_${v} "$ENV{${v}}") + set(ENV{${v}} C) + endforeach() + + if (_lang MATCHES "^(C|CXX)$") + set (_source "int main() { return 0; }") + elseif (_lang STREQUAL "Fortran") + set (_source " program test\n stop\n end program") + elseif (_lang MATCHES "^(OBJC|OBJCXX)$") + set (_source "#ifndef __OBJC__\n# error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }") + else() + message (SEND_ERROR "check_linker_flag: ${_lang}: unsupported language.") + return() + endif() + check_compiler_flag_common_patterns(_common_patterns) + + cmake_language (CALL check_${_lang}_source_compiles "${_source}" ${_var} ${_common_patterns}) + + foreach(v IN LISTS _locale_vars) + set(ENV{${v}} ${_locale_vars_saved_${v}}) + endforeach() + set(${_var} "${${_var}}" PARENT_SCOPE) +endfunction() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0f94e4e..a042669 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -487,6 +487,12 @@ add_RunCMake_test(target_include_directories) add_RunCMake_test(target_sources) add_RunCMake_test(CheckModules) add_RunCMake_test(CheckIPOSupported) +if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin)" + AND (CMAKE_C_COMPILER_ID MATCHES "Clang|GNU" OR CMAKE_Fortran_COMPILER_ID MATCHES "GNU")) + add_RunCMake_test(CheckLinkerFlag -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} + -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}) +endif() + add_RunCMake_test(CommandLine -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}) add_RunCMake_test(CommandLineTar) diff --git a/Tests/RunCMake/CheckLinkerFlag/CMakeLists.txt b/Tests/RunCMake/CheckLinkerFlag/CMakeLists.txt new file mode 100644 index 0000000..0421e28 --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.13) + +project(${RunCMake_TEST} LANGUAGES NONE) + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CheckLinkerFlag/CheckCLinkerFlag.cmake b/Tests/RunCMake/CheckLinkerFlag/CheckCLinkerFlag.cmake new file mode 100644 index 0000000..c8e87a4 --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CheckCLinkerFlag.cmake @@ -0,0 +1,3 @@ + +set (CHECK_LANGUAGE C) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckLinkerFlag.cmake") diff --git a/Tests/RunCMake/CheckLinkerFlag/CheckCXXLinkerFlag.cmake b/Tests/RunCMake/CheckLinkerFlag/CheckCXXLinkerFlag.cmake new file mode 100644 index 0000000..4e299b9 --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CheckCXXLinkerFlag.cmake @@ -0,0 +1,3 @@ + +set (CHECK_LANGUAGE CXX) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckLinkerFlag.cmake") diff --git a/Tests/RunCMake/CheckLinkerFlag/CheckFortranLinkerFlag.cmake b/Tests/RunCMake/CheckLinkerFlag/CheckFortranLinkerFlag.cmake new file mode 100644 index 0000000..bca288e --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CheckFortranLinkerFlag.cmake @@ -0,0 +1,3 @@ + +set (CHECK_LANGUAGE Fortran) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckLinkerFlag.cmake") diff --git a/Tests/RunCMake/CheckLinkerFlag/CheckLinkerFlag.cmake b/Tests/RunCMake/CheckLinkerFlag/CheckLinkerFlag.cmake new file mode 100644 index 0000000..c3bd465 --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CheckLinkerFlag.cmake @@ -0,0 +1,14 @@ + +enable_language (${CHECK_LANGUAGE}) + +include(CheckLinkerFlag) + +check_linker_flag(${CHECK_LANGUAGE} "LINKER:-L,/dir" VALID_LINKER_FLAG) +if(NOT VALID_LINKER_FLAG) + message(SEND_ERROR "Test fail for valid linker flag.") +endif() + +check_linker_flag(${CHECK_LANGUAGE} "LINKER:-D" INVALID_LINKER_FLAG) +if(INVALID_LINKER_FLAG) + message(SEND_ERROR "Test fail for invalid linker flag.") +endif() diff --git a/Tests/RunCMake/CheckLinkerFlag/CheckOBJCLinkerFlag.cmake b/Tests/RunCMake/CheckLinkerFlag/CheckOBJCLinkerFlag.cmake new file mode 100644 index 0000000..fa1d18e --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CheckOBJCLinkerFlag.cmake @@ -0,0 +1,3 @@ + +set (CHECK_LANGUAGE OBJC) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckLinkerFlag.cmake") diff --git a/Tests/RunCMake/CheckLinkerFlag/CheckOBJCXXLinkerFlag.cmake b/Tests/RunCMake/CheckLinkerFlag/CheckOBJCXXLinkerFlag.cmake new file mode 100644 index 0000000..414efb8 --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/CheckOBJCXXLinkerFlag.cmake @@ -0,0 +1,3 @@ + +set (CHECK_LANGUAGE OBJCXX) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckLinkerFlag.cmake") diff --git a/Tests/RunCMake/CheckLinkerFlag/RunCMakeTest.cmake b/Tests/RunCMake/CheckLinkerFlag/RunCMakeTest.cmake new file mode 100644 index 0000000..224a2a3 --- /dev/null +++ b/Tests/RunCMake/CheckLinkerFlag/RunCMakeTest.cmake @@ -0,0 +1,14 @@ +include(RunCMake) + +if (CMAKE_C_COMPILER_ID MATCHES "Clang|GNU") + run_cmake(CheckCLinkerFlag) + run_cmake(CheckCXXLinkerFlag) + if (APPLE) + run_cmake(CheckOBJCLinkerFlag) + run_cmake(CheckOBJCXXLinkerFlag) + endif() +endif() + +if (CMAKE_Fortran_COMPILER_ID MATCHES "GNU") + run_cmake(CheckFortranLinkerFlag) +endif() -- cgit v0.12