Link Step: compute effective linker used by the compiler

Extract the effective linker during the computation of implicit artifacts
delivered by the compiler to the linker.
Define various variables describing the linker:
* CMAKE_<LANG>_COMPILER_LINKER
* CMAKE_<LANG>_COMPILER_LINKER_VERSION
* CMAKE_<LANG>_COMPILER_LINKER_ID
* CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT

This is complementary to feature introduced by commit 96a953b1ed
(Add options to specify linker tool, 2023-09-27).

Fixes: #17596, #18209, #25344
This commit is contained in:
Marc Chevrier
2023-05-27 10:54:53 +02:00
committed by Brad King
parent 8a79a20257
commit c26c6ac488
22 changed files with 421 additions and 97 deletions

View File

@@ -74,6 +74,10 @@ Variables that Provide Information
/variable/CMAKE_JOB_POOLS
/variable/CMAKE_LANG_COMPILER_AR
/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT
/variable/CMAKE_LANG_COMPILER_LINKER
/variable/CMAKE_LANG_COMPILER_LINKER_FRONTEND_VARIANT
/variable/CMAKE_LANG_COMPILER_LINKER_ID
/variable/CMAKE_LANG_COMPILER_LINKER_VERSION
/variable/CMAKE_LANG_COMPILER_RANLIB
/variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX
/variable/CMAKE_LINK_LIBRARY_SUFFIX

View File

@@ -0,0 +1,8 @@
compiler-linker
---------------
* The linker effectively used for the link step is now documented with the
:variable:`CMAKE_<LANG>_COMPILER_LINKER`,
:variable:`CMAKE_<LANG>_COMPILER_LINKER_ID`,
:variable:`CMAKE_<LANG>_COMPILER_LINKER_VERSION` and
:variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables.

View File

@@ -0,0 +1,15 @@
CMAKE_<LANG>_COMPILER_LINKER
----------------------------
.. versionadded:: 3.29
The full path to the linker for ``LANG``.
This is the command that will be used as the ``<LANG>`` linker.
This variable is not guaranteed to be defined for all linkers or languages.
.. note::
This variable is read-only. It must not be set by the user. To select a
specific linker, use the :variable:`CMAKE_LINKER_TYPE` variable or the
:prop_tgt:`LINKER_TYPE` target property.

View File

@@ -0,0 +1,21 @@
CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT
---------------------------------------------
.. versionadded:: 3.29
Identification string of the linker frontend variant.
Some linkers have multiple, different frontends for accepting command
line options. (For example ``LLCM LLD`` originally only had a frontend
compatible with the ``GNU`` compiler but since its port to Windows
(``lld-link``) it now also supports a frontend compatible with ``MSVC``.)
When CMake detects such a linker it sets this variable to what would have been
the :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` for the linker whose frontend
it resembles.
.. note::
In other words, this variable describes what command line options
and language extensions the linker frontend expects.
This variable is set for ``GNU``, ``MSVC``, ``MOLD`` and ``AppleClang``
linkers that have only one frontend variant.

View File

@@ -0,0 +1,31 @@
CMAKE_<LANG>_COMPILER_LINKER_ID
-------------------------------
.. versionadded:: 3.29
Linker identification string.
A short string unique to the linker vendor. Possible values
include:
=============================== ===============================================
Value Name
=============================== ===============================================
``AppleClang`` Apple Clang
``LLD`` `LLVM LLD`_
``GNU`` `GNU Binutils - ld linker`_ (also known as
``bfd``)
``GNUgold`` `GNU Binutils - gold linker`_
``MSVC`` `Microsoft Visual Studio`_
``MOLD`` `mold: A Modern Linker`_ or, on Apple, `sold`_
linker
=============================== ===============================================
This variable is not guaranteed to be defined for all linkers or languages.
.. _LLVM LLD: https://lld.llvm.org
.. _GNU Binutils - ld linker: https://sourceware.org/binutils
.. _GNU Binutils - gold linker: https://sourceware.org/binutils
.. _Microsoft Visual Studio: https://visualstudio.microsoft.com
.. _mold\: A Modern Linker: https://github.com/rui314/mold
.. _sold: https://github.com/bluewhalesystems/sold

View File

@@ -0,0 +1,10 @@
CMAKE_<LANG>_COMPILER_LINKER_VERSION
------------------------------------
.. versionadded:: 3.29
Linker version string.
Linker version in major[.minor[.patch[.tweak]]] format. This
variable is not guaranteed to be defined for all linkers or
languages.

View File

@@ -7,6 +7,10 @@ set(CMAKE_ASM@ASM_DIALECT@_COMPILER_RANLIB "@_CMAKE_ASM_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LINKER "@CMAKE_ASM_COMPILER_LINKER@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LINKER_ID "@CMAKE_ASM_COMPILER_LINKER_ID@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LINKER_VERSION @CMAKE_ASM_COMPILER_LINKER_VERSION@)
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_ASM_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_MT "@CMAKE_MT@")
set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LOADED 1)

View File

@@ -28,6 +28,10 @@ set(CMAKE_C_COMPILER_RANLIB "@CMAKE_C_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_C_COMPILER_LINKER "@CMAKE_C_COMPILER_LINKER@")
set(CMAKE_C_COMPILER_LINKER_ID "@CMAKE_C_COMPILER_LINKER_ID@")
set(CMAKE_C_COMPILER_LINKER_VERSION @CMAKE_C_COMPILER_LINKER_VERSION@)
set(CMAKE_C_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_C_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_MT "@CMAKE_MT@")
set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUCC @CMAKE_COMPILER_IS_GNUCC@)

View File

@@ -74,5 +74,9 @@ set(CMAKE_CUDA_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CUDA_IMPLICIT_LINK_FR
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_CUDA_COMPILER_LINKER "@CMAKE_CUDA_COMPILER_LINKER@")
set(CMAKE_CUDA_COMPILER_LINKER_ID "@CMAKE_CUDA_COMPILER_LINKER_ID@")
set(CMAKE_CUDA_COMPILER_LINKER_VERSION @CMAKE_CUDA_COMPILER_LINKER_VERSION@)
set(CMAKE_CUDA_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_CUDA_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_AR "@CMAKE_AR@")
set(CMAKE_MT "@CMAKE_MT@")

View File

@@ -29,6 +29,10 @@ set(CMAKE_CXX_COMPILER_RANLIB "@CMAKE_CXX_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_CXX_COMPILER_LINKER "@CMAKE_CXX_COMPILER_LINKER@")
set(CMAKE_CXX_COMPILER_LINKER_ID "@CMAKE_CXX_COMPILER_LINKER_ID@")
set(CMAKE_CXX_COMPILER_LINKER_VERSION @CMAKE_CXX_COMPILER_LINKER_VERSION@)
set(CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_MT "@CMAKE_MT@")
set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUCXX @CMAKE_COMPILER_IS_GNUCXX@)

View File

@@ -6,6 +6,7 @@
# This is used internally by CMake and should not be included by user
# code.
include(${CMAKE_ROOT}/Modules/Internal/CMakeDetermineLinkerId.cmake)
include(${CMAKE_ROOT}/Modules/CMakeParseImplicitIncludeInfo.cmake)
include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)
@@ -19,15 +20,19 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
set(BIN "${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerABI_${lang}.bin")
set(CMAKE_FLAGS )
set(COMPILE_DEFINITIONS )
set(LINK_OPTIONS )
if(DEFINED CMAKE_${lang}_VERBOSE_FLAG)
set(CMAKE_FLAGS "-DEXE_LINKER_FLAGS=${CMAKE_${lang}_VERBOSE_FLAG}")
set(LINK_OPTIONS "${CMAKE_${lang}_VERBOSE_FLAG}")
set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_FLAG}")
endif()
if(DEFINED CMAKE_${lang}_VERBOSE_COMPILE_FLAG)
set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_COMPILE_FLAG}")
endif()
if(DEFINED CMAKE_${lang}_VERBOSE_LINK_FLAG)
list(APPEND LINK_OPTIONS "${CMAKE_${lang}_VERBOSE_LINK_FLAG}")
endif()
if(lang MATCHES "^(CUDA|HIP)$")
if(CMAKE_${lang}_ARCHITECTURES STREQUAL "native")
if(CMAKE_CUDA_ARCHITECTURES STREQUAL "native")
# We are about to detect the native architectures, so we do
# not yet know them. Use all architectures during detection.
set(CMAKE_${lang}_ARCHITECTURES "all")
@@ -39,6 +44,9 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
# from which we might detect implicit link libraries.
list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=")
endif()
list(JOIN LINK_OPTIONS " " LINK_OPTIONS)
list(APPEND CMAKE_FLAGS "-DEXE_LINKER_FLAGS=${LINK_OPTIONS}")
__TestCompiler_setTryCompileTargetType()
# Avoid failing ABI detection on warnings.
@@ -53,7 +61,6 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
set(ENV{LC_ALL} C)
set(ENV{LC_MESSAGES} C)
set(ENV{LANG} C)
try_compile(CMAKE_${lang}_ABI_COMPILED
SOURCES ${src}
CMAKE_FLAGS ${CMAKE_FLAGS}
@@ -146,39 +153,42 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
set(implicit_libs "${CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES}")
set(implicit_fwks "${CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES}")
else()
# Parse implicit linker information for this language, if available.
set(implicit_dirs "")
set(implicit_objs "")
set(implicit_libs "")
set(implicit_fwks "")
if(CMAKE_${lang}_VERBOSE_FLAG)
CMAKE_PARSE_IMPLICIT_LINK_INFO("${OUTPUT}" implicit_libs implicit_dirs implicit_fwks log
"${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}"
COMPUTE_IMPLICIT_OBJECTS implicit_objs
LANGUAGE ${lang})
message(CONFIGURE_LOG
"Parsed ${lang} implicit link information:\n${log}\n\n")
endif()
# for VS IDE Intel Fortran we have to figure out the
# implicit link path for the fortran run time using
# a try-compile
if("${lang}" MATCHES "Fortran"
AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path")
# Build a sample project which reports symbols.
try_compile(IFORT_LIB_PATH_COMPILED
PROJECT IntelFortranImplicit
SOURCE_DIR ${CMAKE_ROOT}/Modules/IntelVSImplicitPath
BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
CMAKE_FLAGS
"-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
OUTPUT_VARIABLE _output)
file(WRITE
"${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt"
"${_output}")
include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL)
message(CHECK_PASS "done")
endif()
# Parse implicit linker information for this language, if available.
set(implicit_dirs "")
set(implicit_objs "")
set(implicit_libs "")
set(implicit_fwks "")
set(compute_artifacts COMPUTE_LINKER linker_tool)
if(CMAKE_${lang}_VERBOSE_FLAG)
list(APPEND compute_artifacts COMPUTE_IMPLICIT_LIBS implicit_libs
COMPUTE_IMPLICIT_DIRS implicit_dirs
COMPUTE_IMPLICIT_FWKS implicit_fwks
COMPUTE_IMPLICIT_OBJECTS implicit_objs)
endif()
cmake_parse_implicit_link_info2("${OUTPUT}" log "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}"
${compute_artifacts} LANGUAGE ${lang})
message(CONFIGURE_LOG
"Parsed ${lang} implicit link information:\n${log}\n\n")
# for VS IDE Intel Fortran we have to figure out the
# implicit link path for the fortran run time using
# a try-compile
if("${lang}" MATCHES "Fortran"
AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path")
# Build a sample project which reports symbols.
try_compile(IFORT_LIB_PATH_COMPILED
PROJECT IntelFortranImplicit
SOURCE_DIR ${CMAKE_ROOT}/Modules/IntelVSImplicitPath
BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
CMAKE_FLAGS
"-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
OUTPUT_VARIABLE _output)
file(WRITE
"${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt"
"${_output}")
include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL)
message(CHECK_PASS "done")
endif()
endif()
# Implicit link libraries cannot be used explicitly for multiple
@@ -193,6 +203,12 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
list(REMOVE_ITEM implicit_dirs $ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE})
endif()
set(CMAKE_${lang}_COMPILER_LINKER "${linker_tool}" PARENT_SCOPE)
cmake_determine_linker_id(${lang} "${linker_tool}")
set(CMAKE_${lang}_COMPILER_LINKER_ID "${CMAKE_${lang}_COMPILER_LINKER_ID}" PARENT_SCOPE)
set(CMAKE_${lang}_COMPILER_LINKER_VERSION ${CMAKE_${lang}_COMPILER_LINKER_VERSION} PARENT_SCOPE)
set(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT ${CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT} PARENT_SCOPE)
set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE)
set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE)
set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE)

View File

@@ -15,6 +15,10 @@ set(CMAKE_AR "@CMAKE_AR@")
set(CMAKE_Fortran_COMPILER_AR "@CMAKE_Fortran_COMPILER_AR@")
set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_Fortran_COMPILER_LINKER "@CMAKE_Fortran_COMPILER_LINKER@")
set(CMAKE_Fortran_COMPILER_LINKER_ID "@CMAKE_Fortran_COMPILER_LINKER_ID@")
set(CMAKE_Fortran_COMPILER_LINKER_VERSION @CMAKE_Fortran_COMPILER_LINKER_VERSION@)
set(CMAKE_Fortran_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_Fortran_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_Fortran_COMPILER_RANLIB "@CMAKE_Fortran_COMPILER_RANLIB@")
set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUG77 @CMAKE_COMPILER_IS_GNUG77@)

View File

@@ -76,5 +76,9 @@ set(CMAKE_HIP_COMPILER_RANLIB "@CMAKE_HIP_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_HIP_COMPILER_LINKER "@CMAKE_HIP_COMPILER_LINKER@")
set(CMAKE_HIP_COMPILER_LINKER_ID "@CMAKE_HIP_COMPILER_LINKER_ID@")
set(CMAKE_HIP_COMPILER_LINKER_VERSION @CMAKE_HIP_COMPILER_LINKER_VERSION@)
set(CMAKE_HIP_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_HIP_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_MT "@CMAKE_MT@")
set(CMAKE_TAPI "@CMAKE_TAPI@")

View File

@@ -26,6 +26,10 @@ set(CMAKE_OBJC_COMPILER_RANLIB "@CMAKE_OBJC_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_OBJC_COMPILER_LINKER "@CMAKE_OBJC_COMPILER_LINKER@")
set(CMAKE_OBJC_COMPILER_LINKER_ID "@CMAKE_OBJC_COMPILER_LINKER_ID@")
set(CMAKE_OBJC_COMPILER_LINKER_VERSION @CMAKE_OBJC_COMPILER_LINKER_VERSION@)
set(CMAKE_OBJC_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_OBJC_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_MT "@CMAKE_MT@")
set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUOBJC @CMAKE_COMPILER_IS_GNUOBJC@)

View File

@@ -27,6 +27,10 @@ set(CMAKE_OBJCXX_COMPILER_RANLIB "@CMAKE_OBJCXX_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@")
set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@")
set(CMAKE_OBJCXX_COMPILER_LINKER "@CMAKE_OBJCXX_COMPILER_LINKER@")
set(CMAKE_OBJCXX_COMPILER_LINKER_ID "@CMAKE_OBJCXX_COMPILER_LINKER_ID@")
set(CMAKE_OBJCXX_COMPILER_LINKER_VERSION @CMAKE_OBJCXX_COMPILER_LINKER_VERSION@)
set(CMAKE_OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT @CMAKE_OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT@)
set(CMAKE_MT "@CMAKE_MT@")
set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUOBJCXX @CMAKE_COMPILER_IS_GNUOBJCXX@)

View File

@@ -15,6 +15,26 @@ cmake_policy(SET CMP0054 NEW)
# compatibility don't break.
#
function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj_regex)
set(keywordArgs)
set(oneValueArgs LANGUAGE COMPUTE_IMPLICIT_OBJECTS)
set(multiValueArgs )
cmake_parse_arguments(EXTRA_PARSE "${keywordArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
cmake_parse_implicit_link_info2("${text}" "${log_var}" "${obj_regex}"
COMPUTE_IMPLICIT_LIBS "${lib_var}" COMPUTE_IMPLICIT_DIRS "${dir_var}"
COMPUTE_IMPLICIT_FWKS "${fwk_var}" ${ARGN})
set(${lib_var} "${${lib_var}}" PARENT_SCOPE)
set(${dir_var} "${${dir_var}}" PARENT_SCOPE)
set(${fwk_var} "${${fwk_var}}" PARENT_SCOPE)
set(${log_var} "${${log_var}}" PARENT_SCOPE)
if(EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS)
set(${EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS} "${${EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS}}" PARENT_SCOPE)
endif()
endfunction()
function(cmake_parse_implicit_link_info2 text log_var obj_regex)
set(implicit_libs_tmp "")
set(implicit_objs_tmp "")
set(implicit_dirs_tmp)
@@ -22,25 +42,29 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
set(log "")
set(keywordArgs)
set(oneValueArgs COMPUTE_IMPLICIT_OBJECTS LANGUAGE)
set(oneValueArgs LANGUAGE
COMPUTE_IMPLICIT_LIBS COMPUTE_IMPLICIT_DIRS COMPUTE_IMPLICIT_FWKS
COMPUTE_IMPLICIT_OBJECTS COMPUTE_LINKER)
set(multiValueArgs )
cmake_parse_arguments(EXTRA_PARSE "${keywordArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(is_msvc 0)
if(EXTRA_PARSE_LANGUAGE AND
("x${CMAKE_${EXTRA_PARSE_LANGUAGE}_ID}" STREQUAL "xMSVC" OR
("x${CMAKE_${EXTRA_PARSE_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC" OR
"x${CMAKE_${EXTRA_PARSE_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC"))
set(is_msvc 1)
endif()
# Parse implicit linker arguments.
set(linker "CMAKE_LINKER-NOTFOUND")
if(CMAKE_LINKER)
get_filename_component(linker ${CMAKE_LINKER} NAME)
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" linker "${linker}")
endif()
set(linker "ld[0-9]*(\\.[a-z]+)?")
if(is_msvc)
string(APPEND linker "|link\\.exe|lld-link")
string(APPEND linker "|link\\.exe|lld-link(\\.exe)?")
endif()
if(CMAKE_LINKER)
get_filename_component(default_linker ${CMAKE_LINKER} NAME)
if (NOT default_linker MATCHES "(${linker})")
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" default_linker "${default_linker}")
list(PREPEND linker "${default_linker}|")
endif()
endif()
set(startfile "CMAKE_LINK_STARTFILE-NOTFOUND")
if(CMAKE_LINK_STARTFILE)
@@ -50,9 +74,35 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
# whole line and just the command (argv[0]).
set(linker_regex "^( *|.*[/\\])(${linker}|${startfile}|([^/\\]+-)?ld|collect2)[^/\\]*( |$)")
set(linker_exclude_regex "collect2 version |^[A-Za-z0-9_]+=|/ldfe ")
set(linker_tool_regex "^[ \t]*(->|exec:|\")?[ \t]*(.*[/\\](${linker}))(\"|,| |$)")
set(linker_tool_exclude_regex "cuda-fake-ld|-fuse-ld=")
set(linker_tool "NOTFOUND")
set(link_line_parsed 0)
string(APPEND log " link line regex: [${linker_regex}]\n")
if(EXTRA_PARSE_COMPUTE_LINKER)
string(APPEND log " linker tool regex: [${linker_tool_regex}]\n")
endif()
string(REGEX REPLACE "\r?\n" ";" output_lines "${text}")
foreach(line IN LISTS output_lines)
if(EXTRA_PARSE_COMPUTE_LINKER AND
NOT linker_tool AND NOT "${line}" MATCHES "${linker_tool_exclude_regex}"
AND "${line}" MATCHES "${linker_tool_regex}")
set(linker_tool "${CMAKE_MATCH_2}")
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
# pick-up last path
string(REGEX REPLACE "^.*([A-Za-z]:[/\\][^:]+)$" "\\1" linker_tool "${linker_tool}")
cmake_path(SET linker_tool "${linker_tool}")
endif()
string(APPEND log " linker tool for '${EXTRA_PARSE_LANGUAGE}': ${linker_tool}\n")
endif()
if(NOT (EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS OR EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS
OR EXTRA_PARSE_COMPUTE_IMPLICIT_FWKS OR EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS))
if(linker_tool)
break()
else()
continue()
endif()
endif()
set(cmd)
if("${line}" MATCHES "${linker_regex}" AND
NOT "${line}" MATCHES "${linker_exclude_regex}")
@@ -86,7 +136,8 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
endif()
endif()
set(search_static 0)
if("${cmd}" MATCHES "${linker_regex}")
if(NOT link_line_parsed AND "${cmd}" MATCHES "${linker_regex}")
set(link_line_parsed 1)
string(APPEND log " link line: [${line}]\n")
string(REGEX REPLACE ";-([LYz]);" ";-\\1" args "${args}")
set(skip_value_of "")
@@ -95,58 +146,75 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
string(APPEND log " arg [${arg}] ==> skip value of ${skip_value_of}\n")
set(skip_value_of "")
elseif("${arg}" MATCHES "^-L(.:)?[/\\]")
# Unix search path.
string(REGEX REPLACE "^-L" "" dir "${arg}")
list(APPEND implicit_dirs_tmp ${dir})
string(APPEND log " arg [${arg}] ==> dir [${dir}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS)
# Unix search path.
string(REGEX REPLACE "^-L" "" dir "${arg}")
list(APPEND implicit_dirs_tmp ${dir})
string(APPEND log " arg [${arg}] ==> dir [${dir}]\n")
endif()
elseif("${arg}" MATCHES "^[-/](LIBPATH|libpath):(.+)")
# MSVC search path.
set(dir "${CMAKE_MATCH_2}")
list(APPEND implicit_dirs_tmp ${dir})
string(APPEND log " arg [${arg}] ==> dir [${dir}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS)
# MSVC search path.
set(dir "${CMAKE_MATCH_2}")
list(APPEND implicit_dirs_tmp ${dir})
string(APPEND log " arg [${arg}] ==> dir [${dir}]\n")
endif()
elseif(is_msvc AND "${arg}" STREQUAL "-link")
string(APPEND log " arg [${arg}] ==> ignore MSVC cl option\n")
elseif(is_msvc AND "${arg}" MATCHES "^(.*\\.[Ll][Ii][Bb])$")
set(lib "${CMAKE_MATCH_1}")
list(APPEND implicit_libs_tmp ${lib})
string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
elseif(is_msvc AND NOT "${arg}" MATCHES "^/[Ii][Mm][Pp][Ll][Ii][Bb]:"
AND "${arg}" MATCHES "^(.*\\.[Ll][Ii][Bb])$")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
set(lib "${CMAKE_MATCH_1}")
list(APPEND implicit_libs_tmp ${lib})
string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
endif()
elseif("${arg}" STREQUAL "-lto_library")
# ld argument "-lto_library <path>"
set(skip_value_of "${arg}")
string(APPEND log " arg [${arg}] ==> ignore, skip following value\n")
elseif("${arg}" MATCHES "^-l([^:].*)$")
# Unix library.
set(lib "${CMAKE_MATCH_1}")
if(search_static AND lib MATCHES "^(gfortran|stdc\\+\\+)$")
# Search for the static library later, once all link dirs are known.
set(lib "SEARCH_STATIC:${lib}")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
# Unix library.
set(lib "${CMAKE_MATCH_1}")
if(search_static AND lib MATCHES "^(gfortran|stdc\\+\\+)$")
# Search for the static library later, once all link dirs are known.
set(lib "SEARCH_STATIC:${lib}")
endif()
list(APPEND implicit_libs_tmp ${lib})
string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
endif()
list(APPEND implicit_libs_tmp ${lib})
string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.a$")
# Unix library full path.
list(APPEND implicit_libs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> lib [${arg}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
# Unix library full path.
list(APPEND implicit_libs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> lib [${arg}]\n")
endif()
elseif("${arg}" MATCHES "^[-/](DEFAULTLIB|defaultlib):(.+)")
# Windows library.
set(lib "${CMAKE_MATCH_2}")
list(APPEND implicit_libs_tmp ${lib})
string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
# Windows library.
set(lib "${CMAKE_MATCH_2}")
list(APPEND implicit_libs_tmp ${lib})
string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
endif()
elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.o$")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS)
list(APPEND implicit_objs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> obj [${arg}]\n")
endif()
if(obj_regex AND "${arg}" MATCHES "${obj_regex}")
# Object file full path.
list(APPEND implicit_libs_tmp ${arg})
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
if(obj_regex AND "${arg}" MATCHES "${obj_regex}")
# Object file full path.
list(APPEND implicit_libs_tmp ${arg})
endif()
endif()
elseif("${arg}" MATCHES "^-Y(P,)?[^0-9]")
# Sun search path ([^0-9] avoids conflict with Mac -Y<num>).
string(REGEX REPLACE "^-Y(P,)?" "" dirs "${arg}")
string(REPLACE ":" ";" dirs "${dirs}")
list(APPEND implicit_dirs_tmp ${dirs})
string(APPEND log " arg [${arg}] ==> dirs [${dirs}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS)
# Sun search path ([^0-9] avoids conflict with Mac -Y<num>).
string(REGEX REPLACE "^-Y(P,)?" "" dirs "${arg}")
string(REPLACE ":" ";" dirs "${dirs}")
list(APPEND implicit_dirs_tmp ${dirs})
string(APPEND log " arg [${arg}] ==> dirs [${dirs}]\n")
endif()
elseif("${arg}" STREQUAL "-Bstatic")
set(search_static 1)
string(APPEND log " arg [${arg}] ==> search static\n" )
@@ -154,13 +222,17 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
set(search_static 0)
string(APPEND log " arg [${arg}] ==> search dynamic\n" )
elseif("${arg}" MATCHES "^-l:")
# HP named library.
list(APPEND implicit_libs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> lib [${arg}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
# HP named library.
list(APPEND implicit_libs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> lib [${arg}]\n")
endif()
elseif("${arg}" MATCHES "^-z(all|default|weak)extract")
# Link editor option.
list(APPEND implicit_libs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> opt [${arg}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
# Link editor option.
list(APPEND implicit_libs_tmp ${arg})
string(APPEND log " arg [${arg}] ==> opt [${arg}]\n")
endif()
elseif("${arg}" STREQUAL "cl.exe")
string(APPEND log " arg [${arg}] ==> recognize MSVC cl\n")
set(is_msvc 1)
@@ -168,25 +240,29 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
string(APPEND log " arg [${arg}] ==> ignore\n")
endif()
endforeach()
break()
elseif("${line}" MATCHES "LPATH(=| is:? *)(.*)$")
string(APPEND log " LPATH line: [${line}]\n")
# HP search path.
string(REPLACE ":" ";" paths "${CMAKE_MATCH_2}")
list(APPEND implicit_dirs_tmp ${paths})
string(APPEND log " dirs [${paths}]\n")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS)
string(APPEND log " LPATH line: [${line}]\n")
# HP search path.
string(REPLACE ":" ";" paths "${CMAKE_MATCH_2}")
list(APPEND implicit_dirs_tmp ${paths})
string(APPEND log " dirs [${paths}]\n")
endif()
else()
string(APPEND log " ignore line: [${line}]\n")
endif()
if((NOT EXTRA_PARSE_COMPUTE_LINKER OR linker_tool) AND link_line_parsed)
break()
endif()
endforeach()
# Look for library search paths reported by linker.
if("${output_lines}" MATCHES ";Library search paths:((;\t[^;]+)+)")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS AND "${output_lines}" MATCHES ";Library search paths:((;\t[^;]+)+)")
string(REPLACE ";\t" ";" implicit_dirs_match "${CMAKE_MATCH_1}")
string(APPEND log " Library search paths: [${implicit_dirs_match}]\n")
list(APPEND implicit_dirs_tmp ${implicit_dirs_match})
endif()
if("${output_lines}" MATCHES ";Framework search paths:((;\t[^;]+)+)")
if(EXTRA_PARSE_COMPUTE_IMPLICIT_FWKS AND "${output_lines}" MATCHES ";Framework search paths:((;\t[^;]+)+)")
string(REPLACE ";\t" ";" implicit_fwks_match "${CMAKE_MATCH_1}")
string(APPEND log " Framework search paths: [${implicit_fwks_match}]\n")
list(APPEND implicit_fwks_tmp ${implicit_fwks_match})
@@ -271,11 +347,21 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj
string(APPEND log " implicit fwks: [${implicit_fwks}]\n")
# Return results.
set(${lib_var} "${implicit_libs}" PARENT_SCOPE)
set(${dir_var} "${implicit_dirs}" PARENT_SCOPE)
set(${fwk_var} "${implicit_fwks}" PARENT_SCOPE)
if(EXTRA_PARSE_COMPUTE_LINKER)
set(${EXTRA_PARSE_COMPUTE_LINKER} "${linker_tool}" PARENT_SCOPE)
endif()
set(${log_var} "${log}" PARENT_SCOPE)
if(EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS)
set(${EXTRA_PARSE_COMPUTE_IMPLICIT_LIBS} "${implicit_libs}" PARENT_SCOPE)
endif()
if(EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS)
set(${EXTRA_PARSE_COMPUTE_IMPLICIT_DIRS} "${implicit_dirs}" PARENT_SCOPE)
endif()
if(EXTRA_PARSE_COMPUTE_IMPLICIT_FWKS)
set(${EXTRA_PARSE_COMPUTE_IMPLICIT_FWKS} "${implicit_fwks}" PARENT_SCOPE)
endif()
if(EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS)
set(${EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS} "${implicit_objs}" PARENT_SCOPE)
endif()

View File

@@ -0,0 +1,92 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# Function to identify the linker. This is used internally by CMake and should
# not be included by user code.
# If successful, sets CMAKE_<lang>_COMPILER_LINKER_ID and
# CMAKE_<lang>_COMPILER_LINKER_VERSION
cmake_policy(PUSH)
cmake_policy(SET CMP0053 NEW)
cmake_policy(SET CMP0054 NEW)
function(cmake_determine_linker_id lang linker)
if (NOT linker)
# linker was not identified
unset(CMAKE_${lang}_COMPILER_LINKER_ID PARENT_SCOPE)
unset(CMAKE_${lang}_COMPILER_LINKER_VERSION PARENT_SCOPE)
unset(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT PARENT_SCOPE)
return()
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR linker MATCHES "lld$")
set(flags "--version")
else()
set(flags "-v")
endif()
execute_process(COMMAND "${linker}" ${flags}
OUTPUT_VARIABLE linker_desc
ERROR_VARIABLE linker_desc
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE)
set(linker_frontend)
set(linker_version)
# Compute the linker ID
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND linker_desc MATCHES "@\\(#\\)PROGRAM:ld")
set(linker_id "AppleClang")
set(linker_frontend "GNU")
elseif (linker_desc MATCHES "mold \\(sold\\)")
set(linker_id "MOLD")
set(linker_frontend "GNU")
elseif (linker_desc MATCHES "mold")
set(linker_id "MOLD")
set(linker_frontend "GNU")
elseif (linker_desc MATCHES "LLD")
set(linker_id "LLD")
set(linker_frontend "GNU")
if (WIN32 AND NOT linker_desc MATCHES "compatible with GNU")
set (linker_frontend "MSVC")
endif()
elseif (linker_desc MATCHES "GNU ld")
set(linker_id "GNU")
set(linker_frontend "GNU")
elseif (linker_desc MATCHES "GNU gold")
set(linker_id "GNUgold")
set(linker_frontend "GNU")
elseif (linker_desc MATCHES "Microsoft \\(R\\) Incremental Linker")
set(linker_id "MSVC")
set(linker_frontend "MSVC")
else()
# unknown linker
set(linker_id "UNKNOWN")
endif()
# Get linker version
if (linker_id STREQUAL "AppleClang")
string(REGEX REPLACE ".+PROJECT:[a-z0-9]+-([0-9.]+).+" "\\1" linker_version "${linker_desc}")
elseif (linker_id MATCHES "MOLD|SOLD")
string(REGEX REPLACE "^mold (\\(sold\\) )?([0-9.]+).+" "\\2" linker_version "${linker_desc}")
elseif (linker_id STREQUAL "LLD")
string(REGEX REPLACE ".*LLD ([0-9.]+).*" "\\1" linker_version "${linker_desc}")
elseif (linker_id MATCHES "(GNU|GOLD)")
string(REGEX REPLACE "^GNU [^ ]+ \\([^)]+\\) ([0-9.]+).*" "\\1" linker_version "${linker_desc}")
elseif (linker_id STREQUAL "MSVC")
string(REGEX REPLACE ".+Linker Version ([0-9.]+).+" "\\1" linker_version "${linker_desc}")
endif()
set(CMAKE_${lang}_COMPILER_LINKER_ID "${linker_id}" PARENT_SCOPE)
if (linker_frontend)
set(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT "${linker_frontend}" PARENT_SCOPE)
else()
unset(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT PARENT_SCOPE)
endif()
if (linker_version)
set(CMAKE_${lang}_COMPILER_LINKER_VERSION "${linker_version}" PARENT_SCOPE)
else()
unset(CMAKE_${lang}_COMPILER_LINKER_VERSION PARENT_SCOPE)
endif()
endfunction()
cmake_policy(POP)

View File

@@ -52,6 +52,8 @@ macro(__cygwin_compiler_gnu lang)
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
set(CMAKE_${lang}_CREATE_WIN32_EXE "-mwindows")
set(CMAKE_${lang}_VERBOSE_LINK_FLAG "-Wl,-v")
# No -fPIC on cygwin
set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")

View File

@@ -13,6 +13,8 @@ macro(__linux_compiler_gnu lang)
# executables that use dlopen but do not set ENABLE_EXPORTS.
set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
set(CMAKE_${lang}_VERBOSE_LINK_FLAG "-Wl,-v")
# linker selection
set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld")

View File

@@ -1,4 +1,6 @@
set(CMAKE_CUDA_VERBOSE_LINK_FLAG "-Wl,-v")
# linker selection
set(CMAKE_CUDA_USING_LINKER_SYSTEM "")
set(CMAKE_CUDA_USING_LINKER_LLD "-fuse-ld=lld")

View File

@@ -45,6 +45,7 @@ macro(__windows_compiler_clang_gnu lang)
math(EXPR MSVC_VERSION "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}")
endif()
set(CMAKE_${lang}_VERBOSE_LINK_FLAG "-v")
# No -fPIC on Windows
set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")

View File

@@ -112,6 +112,8 @@ macro(__windows_compiler_gnu lang)
set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
endforeach()
set(CMAKE_${lang}_VERBOSE_LINK_FLAG "-Wl,-v")
# linker selection
set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
set(CMAKE_${lang}_USING_LINKER_BFD "-fuse-ld=bfd")