diff options
author | Marc Chevrier <marc.chevrier@gmail.com> | 2023-09-27 13:22:55 (GMT) |
---|---|---|
committer | Marc Chevrier <marc.chevrier@gmail.com> | 2023-10-13 09:52:35 (GMT) |
commit | 96a953b1ed7e41260aa0869bad0ff14c788cf57e (patch) | |
tree | d9bedd8494b073f3795e4ed80f01b22a2b5a9093 | |
parent | ee5f31ba727e392e1ebc9f5be54c74ac1868d029 (diff) | |
download | CMake-96a953b1ed7e41260aa0869bad0ff14c788cf57e.zip CMake-96a953b1ed7e41260aa0869bad0ff14c788cf57e.tar.gz CMake-96a953b1ed7e41260aa0869bad0ff14c788cf57e.tar.bz2 |
Add options to specify linker tool
Offer the capability, through variable `CMAKE_LINKER_TYPE`, as well as
the target property `LINKER_TYPE` to specify which linker must be used.
The implementation of this capability is specified by variables specific
to the language and linker type: `CMAKE_<LANG>_USING_LINKER_<TYPE>`.
Some definitions are provided as part of `CMake`.
For example, to select the `LLVM` linker rather than the standard one,
the type `LLD` should be specified through the variable `CMAKE_LINKER_TYPE`.
And, on `Apple`, `Linux` and some environments on `Windows`, the variable
`CMAKE_<LANG>_USING_LINKER_LLD` has value `-fuse-ld=lld`. And for `Windows`
environments based on `MSVC`, where the linker is used directly, the tool
`lld-link.exe` will be used rather than `link.exe`.
Fixes: #19174, #24254, #24990
59 files changed, 623 insertions, 16 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index fa1d297..55054f5 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -336,6 +336,7 @@ Properties on Targets /prop_tgt/LINK_SEARCH_START_STATIC /prop_tgt/LINK_WHAT_YOU_USE /prop_tgt/LINKER_LANGUAGE + /prop_tgt/LINKER_TYPE /prop_tgt/LOCATION /prop_tgt/LOCATION_CONFIG /prop_tgt/MACHO_COMPATIBILITY_VERSION diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index d9df773..9320ffa 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -474,6 +474,8 @@ Variables that Control the Build /variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE_SUPPORTED /variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG /variable/CMAKE_LANG_LINKER_LAUNCHER + /variable/CMAKE_LANG_USING_LINKER_MODE + /variable/CMAKE_LANG_USING_LINKER_TYPE /variable/CMAKE_LANG_VISIBILITY_PRESET /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG @@ -490,6 +492,7 @@ Variables that Control the Build /variable/CMAKE_LINK_LIBRARY_USING_FEATURE_SUPPORTED /variable/CMAKE_LINK_WHAT_YOU_USE /variable/CMAKE_LINK_WHAT_YOU_USE_CHECK + /variable/CMAKE_LINKER_TYPE /variable/CMAKE_MACOSX_BUNDLE /variable/CMAKE_MACOSX_RPATH /variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG diff --git a/Help/prop_tgt/LINKER_TYPE.rst b/Help/prop_tgt/LINKER_TYPE.rst new file mode 100644 index 0000000..90a663d --- /dev/null +++ b/Help/prop_tgt/LINKER_TYPE.rst @@ -0,0 +1,26 @@ +LINKER_TYPE +----------- + +.. versionadded:: 3.29 + +Specify which linker will be used for the link step. The property value may use +:manual:`generator expressions <cmake-generator-expressions(7)>`. + +.. code-block:: cmake + + add_library(lib1 SHARED ...) + set_property(TARGET lib1 PROPERTY LINKER_TYPE LLD) + +This specifies that ``lib1`` should use linker type ``LLD`` for the link step. +The implementation details will be provided by the variable +:variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` with ``<TYPE>`` having the value +``LLD``. + +This property is not supported on :generator:`Green Hills MULTI` and +:generator:`Visual Studio 9 2008` generators. + +.. note:: + It is assumed that the linker specified is fully compatible with the standard + one. CMake will not do any options translation. + +.. include:: ../variable/LINKER_PREDEFINED_TYPES.txt diff --git a/Help/release/dev/Linker-user-selection.rst b/Help/release/dev/Linker-user-selection.rst new file mode 100644 index 0000000..ed78099 --- /dev/null +++ b/Help/release/dev/Linker-user-selection.rst @@ -0,0 +1,6 @@ +Linker-user-selection +--------------------- + +* The linker tool can now be specified for a selection of compilers/platforms + by setting :variable:`CMAKE_LINKER_TYPE` variable or :prop_tgt:`LINKER_TYPE` + target property. diff --git a/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst b/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst new file mode 100644 index 0000000..c9b6779 --- /dev/null +++ b/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst @@ -0,0 +1,15 @@ +CMAKE_<LANG>_USING_LINKER_MODE +------------------------------ + +.. versionadded:: 3.29 + +This variable specify what is the type of data stored in variable + :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>`. There are two possible values: + +``FLAG`` + :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` holds compiler flags. This is + the default. + +``TOOL`` + :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` holds the path to the linker + tool. diff --git a/Help/variable/CMAKE_LANG_USING_LINKER_TYPE.rst b/Help/variable/CMAKE_LANG_USING_LINKER_TYPE.rst new file mode 100644 index 0000000..e4d9fa6 --- /dev/null +++ b/Help/variable/CMAKE_LANG_USING_LINKER_TYPE.rst @@ -0,0 +1,30 @@ +CMAKE_<LANG>_USING_LINKER_<TYPE> +-------------------------------- + +.. versionadded:: 3.29 + +This variable defines how to specify the linker for the link step for the type +as specified by the variable :variable:`CMAKE_LINKER_TYPE` or the target +property :prop_tgt:`LINKER_TYPE`. It can hold compiler flags for the link step +or directly the linker tool. The type of data is given by the variable +:variable:`CMAKE_<LANG>_USING_LINKER_MODE`. + +For example, to specify the ``LLVM`` linker for ``GNU`` compilers, we have: + +.. code-block:: cmake + + set(CMAKE_C_USING_LINKER_LLD "-fuse-ld=lld") + +Or on ``Windows`` platform, for ``Clang`` compilers simulating ``MSVC``, we +have: + +.. code-block:: cmake + + set(CMAKE_C_USING_LINKER_LLD "-fuse-ld=lld-link") + +And for the ``MSVC`` compiler, linker is directly used, so we have: + +.. code-block:: cmake + + set(CMAKE_C_USING_LINKER_LLD "/path/to/lld-link.exe") + set(CMAKE_C_USING_LINKER_MODE TOOL) diff --git a/Help/variable/CMAKE_LINKER_TYPE.rst b/Help/variable/CMAKE_LINKER_TYPE.rst new file mode 100644 index 0000000..17ea947 --- /dev/null +++ b/Help/variable/CMAKE_LINKER_TYPE.rst @@ -0,0 +1,18 @@ +CMAKE_LINKER_TYPE +----------------- + +.. versionadded:: 3.29 + +Specify which linker will be used for the link step. + +.. note:: + It is assumed that the linker specified is fully compatible with the standard + one. CMake will not do any options translation. + +This variable is used to initialize the :prop_tgt:`LINKER_TYPE` target +property when they are created by calls to :command:`add_library` or +:command:`add_executable` commands. It is meaningful only for targets having a +link step. If set, its value is also used by the :command:`try_compile` +command. + +.. include:: LINKER_PREDEFINED_TYPES.txt diff --git a/Help/variable/LINKER_PREDEFINED_TYPES.txt b/Help/variable/LINKER_PREDEFINED_TYPES.txt new file mode 100644 index 0000000..50dc3df --- /dev/null +++ b/Help/variable/LINKER_PREDEFINED_TYPES.txt @@ -0,0 +1,57 @@ +Linker types are case-sensitive and may only contain letters, numbers and +underscores. Linker types defined in all uppercase are reserved for CMake's own +built-in types. The pre-defined linker types are: + +``DEFAULT`` + This type corresponds to standard linking, essentially equivalent to + not specifying :prop_tgt:`LINKER_TYPE` target property. + +``SYSTEM`` + Use the standard linker delivered by the platform or the standard toolkit + (for example, ``SYSTEM`` imply Microsoft linker for all ``MSVC`` compatible + compilers). This type is supported for the following platforms/compilers: + + * Linux, for ``GNU``, ``Clang`` and ``NVIDIA`` compilers. + * All Apple variants for ``AppleClang``, ``Clang`` and ``GNU`` compilers. + * Windows, for ``MSVC``, ``GNU``, ``Clang`` and ``NVIDIA`` compilers. + +``LLD`` + Use the ``LLVM`` linker. This type is supported for the following + platforms/compilers: + + * Linux, for ``GNU``, ``Clang`` and ``NVIDIA`` compilers. + * All Apple variants for ``Clang`` and ``AppleClang`` compilers. + * Windows, for ``GNU``, ``Clang`` compilers with ``GNU`` front-end and + ``CLang``, ``MSVC`` and ``NVIDIA`` compilers with ``MSVC`` front-end. + +``BFD`` + Use the ``GNU`` linker. This type is supported for the following + platforms/compilers: + + * Linux, for ``GNU``, ``Clang`` and ``NVIDIA`` compilers. + * Windows, for ``GNU``, ``Clang`` compilers with ``GNU`` front-end. + +``GOLD`` + Supported on Linux platform for ``GNU``, ``Clang`` and ``NVIDIA`` compilers. + +``MOLD`` + Use the `mold linker <https://github.com/rui314/mold>`_. This type is + supported on the following platforms: + + * Linux platform for ``GNU``, ``Clang`` and ``NVIDIA`` compilers. + * All Apple variants for ``Clang`` and ``AppleClang`` compilers as an + alias to ``SOLD``. + +``SOLD`` + Use the `sold linker <https://github.com/bluewhalesystems/sold>`_. This type + is only supported on Apple platforms for ``Clang`` and ``AppleClang`` + compilers. + +``APPLE_CLASSIC`` + Use the Apple linker in the classic behavior (i.e. before ``Xcode 15.0``). + This type is only supported on Apple platforms for ``GNU``, ``Clang`` and + ``AppleClang`` compilers. + +``MSVC`` + Use the Microsoft linker. This type is only supported on Windows + platform for ``MSVC`` and ``Clang`` compiler with ``MSVC`` front-end. diff --git a/Modules/CMakeASMCompiler.cmake.in b/Modules/CMakeASMCompiler.cmake.in index 1efd9f5..fab366a 100644 --- a/Modules/CMakeASMCompiler.cmake.in +++ b/Modules/CMakeASMCompiler.cmake.in @@ -5,6 +5,8 @@ set(CMAKE_ASM@ASM_DIALECT@_COMPILER_AR "@_CMAKE_ASM_COMPILER_AR@") set(CMAKE_RANLIB "@CMAKE_RANLIB@") 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_MT "@CMAKE_MT@") set(CMAKE_TAPI "@CMAKE_TAPI@") set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LOADED 1) diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in index 2f0b774..01185a3 100644 --- a/Modules/CMakeCCompiler.cmake.in +++ b/Modules/CMakeCCompiler.cmake.in @@ -26,6 +26,8 @@ set(CMAKE_C_COMPILER_AR "@CMAKE_C_COMPILER_AR@") set(CMAKE_RANLIB "@CMAKE_RANLIB@") 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_MT "@CMAKE_MT@") set(CMAKE_TAPI "@CMAKE_TAPI@") set(CMAKE_COMPILER_IS_GNUCC @CMAKE_COMPILER_IS_GNUCC@) diff --git a/Modules/CMakeCUDACompiler.cmake.in b/Modules/CMakeCUDACompiler.cmake.in index 3c28c28..3bc21fb 100644 --- a/Modules/CMakeCUDACompiler.cmake.in +++ b/Modules/CMakeCUDACompiler.cmake.in @@ -72,5 +72,7 @@ set(CMAKE_CUDA_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CUDA_IMPLICIT_LINK_FR @_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT@ set(CMAKE_LINKER "@CMAKE_LINKER@") +set(CMAKE_LINKER_LINK "@CMAKE_LINKER_LINK@") +set(CMAKE_LINKER_LLD "@CMAKE_LINKER_LLD@") set(CMAKE_AR "@CMAKE_AR@") set(CMAKE_MT "@CMAKE_MT@") diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in index 8b6f82b..fbc1540 100644 --- a/Modules/CMakeCXXCompiler.cmake.in +++ b/Modules/CMakeCXXCompiler.cmake.in @@ -27,6 +27,8 @@ set(CMAKE_CXX_COMPILER_AR "@CMAKE_CXX_COMPILER_AR@") set(CMAKE_RANLIB "@CMAKE_RANLIB@") 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_MT "@CMAKE_MT@") set(CMAKE_TAPI "@CMAKE_TAPI@") set(CMAKE_COMPILER_IS_GNUCXX @CMAKE_COMPILER_IS_GNUCXX@) diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index e12b175..cf270c0 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -60,6 +60,13 @@ endfunction() __resolve_tool_path(CMAKE_LINKER "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Linker") __resolve_tool_path(CMAKE_MT "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Manifest Tool") +macro(__resolve_linker_path __linker_type __name __search_path __doc) + if(NOT CMAKE_LINKER_${__linker_type}) + set( CMAKE_LINKER_${__linker_type} "${__name}") + endif() + __resolve_tool_path(CMAKE_LINKER_${__linker_type} "${__search_path}" "${__doc}") +endmacro() + set(_CMAKE_TOOL_VARS "") # if it's the MS C/CXX compiler, search for link @@ -93,6 +100,10 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND list(APPEND _CMAKE_TOOL_VARS LINKER MT AR) + # look-up for possible usable linker + __resolve_linker_path(LINK "link" "${_CMAKE_TOOLCHAIN_LOCATION}" "link Linker") + __resolve_linker_path(LLD "lld-link" "${_CMAKE_TOOLCHAIN_LOCATION}" "lld-link Linker") + elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^x(Open)?Watcom$") set(_CMAKE_LINKER_NAMES "wlink") set(_CMAKE_AR_NAMES "wlib") diff --git a/Modules/CMakeHIPCompiler.cmake.in b/Modules/CMakeHIPCompiler.cmake.in index 6d5e62a..0c06c3b 100644 --- a/Modules/CMakeHIPCompiler.cmake.in +++ b/Modules/CMakeHIPCompiler.cmake.in @@ -74,5 +74,7 @@ set(CMAKE_HIP_COMPILER_AR "@CMAKE_HIP_COMPILER_AR@") set(CMAKE_RANLIB "@CMAKE_RANLIB@") 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_MT "@CMAKE_MT@") set(CMAKE_TAPI "@CMAKE_TAPI@") diff --git a/Modules/CMakeOBJCCompiler.cmake.in b/Modules/CMakeOBJCCompiler.cmake.in index de73645..95e52bf 100644 --- a/Modules/CMakeOBJCCompiler.cmake.in +++ b/Modules/CMakeOBJCCompiler.cmake.in @@ -24,6 +24,8 @@ set(CMAKE_OBJC_COMPILER_AR "@CMAKE_OBJC_COMPILER_AR@") set(CMAKE_RANLIB "@CMAKE_RANLIB@") 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_MT "@CMAKE_MT@") set(CMAKE_TAPI "@CMAKE_TAPI@") set(CMAKE_COMPILER_IS_GNUOBJC @CMAKE_COMPILER_IS_GNUOBJC@) diff --git a/Modules/CMakeOBJCXXCompiler.cmake.in b/Modules/CMakeOBJCXXCompiler.cmake.in index 94d24ff..87aca96 100644 --- a/Modules/CMakeOBJCXXCompiler.cmake.in +++ b/Modules/CMakeOBJCXXCompiler.cmake.in @@ -25,6 +25,8 @@ set(CMAKE_OBJCXX_COMPILER_AR "@CMAKE_OBJCXX_COMPILER_AR@") set(CMAKE_RANLIB "@CMAKE_RANLIB@") 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_MT "@CMAKE_MT@") set(CMAKE_TAPI "@CMAKE_TAPI@") set(CMAKE_COMPILER_IS_GNUOBJCXX @CMAKE_COMPILER_IS_GNUOBJCXX@) diff --git a/Modules/Platform/Apple-Clang.cmake b/Modules/Platform/Apple-Clang.cmake index 57b3910..5fe4300 100644 --- a/Modules/Platform/Apple-Clang.cmake +++ b/Modules/Platform/Apple-Clang.cmake @@ -18,6 +18,13 @@ macro(__apple_compiler_clang lang) set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "-framework <LIBRARY>") set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE) + # linker selection + set(CMAKE_${lang}_USING_LINKER_SYSTEM "-fuse-ld=ld") + set(CMAKE_${lang}_USING_LINKER_APPLE_CLASSIC "-fuse-ld=ld" "LINKER:-ld_classic") + set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld") + set(CMAKE_${lang}_USING_LINKER_MOLD "-fuse-ld=mold") + set(CMAKE_${lang}_USING_LINKER_SOLD "-fuse-ld=sold") + if(_CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhoneOS") set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-miphoneos-version-min=") elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhoneSimulator") diff --git a/Modules/Platform/Apple-GNU.cmake b/Modules/Platform/Apple-GNU.cmake index 823c790..15f6a71 100644 --- a/Modules/Platform/Apple-GNU.cmake +++ b/Modules/Platform/Apple-GNU.cmake @@ -17,6 +17,9 @@ macro(__apple_compiler_gnu lang) set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "-framework <LIBRARY>") set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_${lang}_USING_LINKER_SYSTEM "") + set(CMAKE_${lang}_USING_LINKER_APPLE_CLASSIC "LINKER:-ld_classic") endmacro() macro(cmake_gnu_set_sysroot_flag lang) diff --git a/Modules/Platform/Linux-Clang-CUDA.cmake b/Modules/Platform/Linux-Clang-CUDA.cmake new file mode 100644 index 0000000..4a9337e --- /dev/null +++ b/Modules/Platform/Linux-Clang-CUDA.cmake @@ -0,0 +1,2 @@ +include(Platform/Linux-GNU) +__linux_compiler_gnu(CUDA) diff --git a/Modules/Platform/Linux-GNU.cmake b/Modules/Platform/Linux-GNU.cmake index 6878254..b8ce521 100644 --- a/Modules/Platform/Linux-GNU.cmake +++ b/Modules/Platform/Linux-GNU.cmake @@ -12,4 +12,11 @@ macro(__linux_compiler_gnu lang) # We pass this for historical reasons. Projects may have # executables that use dlopen but do not set ENABLE_EXPORTS. set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic") + + # linker selection + set(CMAKE_${lang}_USING_LINKER_SYSTEM "") + set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld") + set(CMAKE_${lang}_USING_LINKER_BFD "-fuse-ld=bfd") + set(CMAKE_${lang}_USING_LINKER_GOLD "-fuse-ld=gold") + set(CMAKE_${lang}_USING_LINKER_MOLD "-fuse-ld=mold") endmacro() diff --git a/Modules/Platform/Linux-NVIDIA-CUDA.cmake b/Modules/Platform/Linux-NVIDIA-CUDA.cmake new file mode 100644 index 0000000..4b416de --- /dev/null +++ b/Modules/Platform/Linux-NVIDIA-CUDA.cmake @@ -0,0 +1,7 @@ + +# linker selection +set(CMAKE_CUDA_USING_LINKER_SYSTEM "") +set(CMAKE_CUDA_USING_LINKER_LLD "-fuse-ld=lld") +set(CMAKE_CUDA_USING_LINKER_BFD "-fuse-ld=bfd") +set(CMAKE_CUDA_USING_LINKER_GOLD "-fuse-ld=gold") +set(CMAKE_CUDA_USING_LINKER_MOLD "-fuse-ld=mold") diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake index 33d271d..a03fc9e 100644 --- a/Modules/Platform/Windows-Clang.cmake +++ b/Modules/Platform/Windows-Clang.cmake @@ -53,6 +53,12 @@ macro(__windows_compiler_clang_gnu lang) set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "") set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "") + # linker selection + set(CMAKE_${lang}_USING_LINKER_DEFAULT "-fuse-ld=lld-link") + set(CMAKE_${lang}_USING_LINKER_SYSTEM "-fuse-ld=link") + set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld-link") + set(CMAKE_${lang}_USING_LINKER_MSVC "-fuse-ld=link") + set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1) set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 1) set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1) @@ -74,10 +80,10 @@ macro(__windows_compiler_clang_gnu lang) set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>") set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>") set(CMAKE_${lang}_CREATE_SHARED_LIBRARY - "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /MANIFEST:EMBED -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES> <MANIFESTS>") + "<CMAKE_${lang}_COMPILER> -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /MANIFEST:EMBED -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES> <MANIFESTS>") set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY}) set(CMAKE_${lang}_LINK_EXECUTABLE - "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /MANIFEST:EMBED -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES> <MANIFESTS>") + "<CMAKE_${lang}_COMPILER> -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /MANIFEST:EMBED -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES> <MANIFESTS>") set(CMAKE_${lang}_CREATE_WIN32_EXE "-Xlinker /subsystem:windows") set(CMAKE_${lang}_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console") diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake index 412af6b..ac990d5 100644 --- a/Modules/Platform/Windows-GNU.cmake +++ b/Modules/Platform/Windows-GNU.cmake @@ -112,6 +112,11 @@ macro(__windows_compiler_gnu lang) set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic") endforeach() + # linker selection + set(CMAKE_${lang}_USING_LINKER_SYSTEM "") + set(CMAKE_${lang}_USING_LINKER_BFD "-fuse-ld=bfd") + set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld") + # No -fPIC on Windows set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "") set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "") diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 829ab9b..1fbf0cc 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -512,6 +512,12 @@ macro(__windows_compiler_msvc lang) set(CMAKE_DEPFILE_FLAGS_${lang} "/showIncludes") set(CMAKE_${lang}_DEPFILE_FORMAT msvc) endif() + + # linker selection + set(CMAKE_${lang}_USING_LINKER_SYSTEM "${CMAKE_LINKER_LINK}") + set(CMAKE_${lang}_USING_LINKER_LLD "${CMAKE_LINKER_LLD}") + set(CMAKE_${lang}_USING_LINKER_MSVC "${CMAKE_LINKER_LINK}") + set(CMAKE_${lang}_USING_LINKER_MODE TOOL) endmacro() macro(__windows_compiler_msvc_enable_rc flags) diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake index 326e715..6489841 100644 --- a/Modules/Platform/Windows-NVIDIA-CUDA.cmake +++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake @@ -47,6 +47,12 @@ set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICIT_DLINK_FLAGS}") unset(__IMPLICIT_DLINK_FLAGS) +# linker selection +set(CMAKE_CUDA_USING_LINKER_SYSTEM "${CMAKE_LINKER_LINK}") +set(CMAKE_CUDA_USING_LINKER_LLD "${CMAKE_LINKER_LLD}") +set(CMAKE_CUDA_USING_LINKER_MSVC "${CMAKE_LINKER_LINK}") +set(CMAKE_CUDA_USING_LINKER_MODE TOOL) + string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}") if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 7e19812..69d5ffc 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -14,6 +14,7 @@ #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" +#include "cmsys/RegularExpression.hxx" #include "cmArgumentParser.h" #include "cmConfigureLog.h" @@ -83,6 +84,7 @@ std::string const kCMAKE_HIP_PLATFORM = "CMAKE_HIP_PLATFORM"; std::string const kCMAKE_HIP_RUNTIME_LIBRARY = "CMAKE_HIP_RUNTIME_LIBRARY"; std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS"; std::string const kCMAKE_ISPC_HEADER_SUFFIX = "CMAKE_ISPC_HEADER_SUFFIX"; +std::string const kCMAKE_LINKER_TYPE = "CMAKE_LINKER_TYPE"; std::string const kCMAKE_LINK_SEARCH_END_STATIC = "CMAKE_LINK_SEARCH_END_STATIC"; std::string const kCMAKE_LINK_SEARCH_START_STATIC = @@ -1114,6 +1116,20 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( vars.insert(varList.begin(), varList.end()); } + if (this->Makefile->GetDefinition(kCMAKE_LINKER_TYPE)) { + // propagate various variables to support linker selection + vars.insert(kCMAKE_LINKER_TYPE); + auto defs = this->Makefile->GetDefinitions(); + cmsys::RegularExpression linkerTypeDef{ + "^CMAKE_[A-Za-z]+_USING_LINKER_" + }; + for (auto const& def : defs) { + if (linkerTypeDef.find(def)) { + vars.insert(def); + } + } + } + if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0083) == cmPolicies::NEW) { // To ensure full support of PIE, propagate cache variables diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index d51dbd0..4e46df7 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -175,14 +175,15 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const cm::string_view property(this->Top()->Property); return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || - property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s; + property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s || + property == "LINKER_TYPE"_s; } bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const { cm::string_view property(this->Top()->Property); - return property == "LINK_OPTIONS"_s; + return property == "LINK_OPTIONS"_s || property == "LINKER_TYPE"_s; } bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 2ea18bd..f7a6a4e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -868,6 +868,31 @@ cmValue cmGeneratorTarget::GetFeature(const std::string& feature, return this->LocalGenerator->GetFeature(feature, config); } +std::string cmGeneratorTarget::GetLinkerTypeProperty( + std::string const& lang, std::string const& config) const +{ + std::string propName{ "LINKER_TYPE" }; + auto linkerType = this->GetProperty(propName); + if (!linkerType.IsEmpty()) { + cmGeneratorExpressionDAGChecker dagChecker(this, propName, nullptr, + nullptr); + auto ltype = + cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(), + config, this, &dagChecker, this, lang); + if (this->IsDeviceLink()) { + cmList list{ ltype }; + const auto DL_BEGIN = "<DEVICE_LINK>"_s; + const auto DL_END = "</DEVICE_LINK>"_s; + cm::erase_if(list, [&](const std::string& item) { + return item == DL_BEGIN || item == DL_END; + }); + return list.to_string(); + } + return ltype; + } + return std::string{}; +} + const char* cmGeneratorTarget::GetLinkPIEProperty( const std::string& config) const { @@ -5515,6 +5540,50 @@ std::string cmGeneratorTarget::GetLinkerLanguage( return this->GetLinkClosure(config)->LinkerLanguage; } +std::string cmGeneratorTarget::GetLinkerTool(const std::string& config) const +{ + return this->GetLinkerTool(this->GetLinkerLanguage(config), config); +} + +std::string cmGeneratorTarget::GetLinkerTool(const std::string& lang, + const std::string& config) const +{ + auto usingLinker = + cmStrCat("CMAKE_", lang, "_USING_", this->IsDeviceLink() ? "DEVICE_" : "", + "LINKER_"); + auto format = this->Makefile->GetDefinition(cmStrCat(usingLinker, "MODE")); + if (!format || format != "TOOL"_s) { + return this->Makefile->GetDefinition("CMAKE_LINKER"); + } + + auto linkerType = this->GetLinkerTypeProperty(lang, config); + if (linkerType.empty()) { + linkerType = "DEFAULT"; + } + usingLinker = cmStrCat(usingLinker, linkerType); + auto linkerTool = this->Makefile->GetDefinition(usingLinker); + + if (!linkerTool) { + if (this->GetGlobalGenerator()->IsVisualStudio() && + linkerType == "DEFAULT"_s) { + return std::string{}; + } + + // fall-back to generic definition + linkerTool = this->Makefile->GetDefinition("CMAKE_LINKER"); + + if (linkerType != "DEFAULT"_s) { + this->LocalGenerator->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("LINKER_TYPE '", linkerType, + "' is unknown. Did you forgot to define '", usingLinker, + "' variable?")); + } + } + + return linkerTool; +} + std::string cmGeneratorTarget::GetPDBOutputName( const std::string& config) const { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index bf49914..a32c5d8 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -205,6 +205,9 @@ public: cmValue GetFeature(const std::string& feature, const std::string& config) const; + std::string GetLinkerTypeProperty(std::string const& lang, + std::string const& config) const; + const char* GetLinkPIEProperty(const std::string& config) const; bool IsIPOEnabled(std::string const& lang, std::string const& config) const; @@ -788,6 +791,10 @@ public: //! Return the preferred linker language for this target std::string GetLinkerLanguage(const std::string& config) const; + //! Return the preferred linker tool for this target + std::string GetLinkerTool(const std::string& config) const; + std::string GetLinkerTool(const std::string& lang, + const std::string& config) const; /** Does this target have a GNU implib to convert to MS format? */ bool HasImplibGNUtoMS(std::string const& config) const; diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 95e2187..940f49d 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -116,6 +116,19 @@ void cmGhsMultiTargetGenerator::Generate() void cmGhsMultiTargetGenerator::GenerateTarget() { + if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE && + !this->GeneratorTarget + ->GetLinkerTypeProperty( + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName), + this->ConfigName) + .empty()) { + // Green Hill MULTI does not support this feature. + cmSystemTools::Message( + cmStrCat("'LINKER_TYPE' property, specified on target '", + this->GeneratorTarget->GetName(), + "', is not supported by this generator.")); + } + // Open the target file in copy-if-different mode. std::string fproj = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 5076e6c..9f6786e 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2500,6 +2500,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, this->CurrentLocalGenerator->GetStaticLibraryFlags( extraLinkOptions, configName, llang, gtgt); } else { + this->CurrentLocalGenerator->AppendLinkerTypeFlags(extraLinkOptions, gtgt, + configName, llang); + cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index fe8d502..76e36ab 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -82,7 +82,6 @@ static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER", "CMAKE_CURRENT_SOURCE_DIR", "CMAKE_CURRENT_BINARY_DIR", "CMAKE_RANLIB", - "CMAKE_LINKER", "CMAKE_MT", "CMAKE_TAPI", "CMAKE_CUDA_HOST_COMPILER", @@ -1604,6 +1603,7 @@ void cmLocalGenerator::GetTargetFlags( } std::string extraLinkFlags; + this->AppendLinkerTypeFlags(extraLinkFlags, target, config, linkLanguage); this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config, linkLanguage); this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage); @@ -3200,6 +3200,49 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) } } +void cmLocalGenerator::AppendLinkerTypeFlags(std::string& flags, + cmGeneratorTarget* target, + const std::string& config, + const std::string& linkLanguage) +{ + switch (target->GetType()) { + case cmStateEnums::EXECUTABLE: + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + break; + default: + return; + } + + auto usingLinker = + cmStrCat("CMAKE_", linkLanguage, "_USING_", + target->IsDeviceLink() ? "DEVICE_" : "", "LINKER_"); + + auto format = this->Makefile->GetDefinition(cmStrCat(usingLinker, "MODE")); + if (format && format != "FLAG"_s) { + return; + } + + auto linkerType = target->GetLinkerTypeProperty(linkLanguage, config); + if (linkerType.empty()) { + linkerType = "DEFAULT"; + } + usingLinker = cmStrCat(usingLinker, linkerType); + auto linkerTypeFlags = this->Makefile->GetDefinition(usingLinker); + if (linkerTypeFlags) { + if (!linkerTypeFlags.IsEmpty()) { + auto linkerFlags = cmExpandListWithBacktrace(linkerTypeFlags); + target->ResolveLinkerWrapper(linkerFlags, linkLanguage); + this->AppendFlags(flags, linkerFlags); + } + } else if (linkerType != "DEFAULT"_s) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("LINKER_TYPE '", linkerType, + "' is unknown. Did you forgot to define '", + usingLinker, "' variable?")); + } +} + void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index a920cfe..a61def9 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -177,6 +177,9 @@ public: void AddPchDependencies(cmGeneratorTarget* target); void AddUnityBuild(cmGeneratorTarget* target); virtual void AddXCConfigSources(cmGeneratorTarget* /* target */) {} + void AppendLinkerTypeFlags(std::string& flags, cmGeneratorTarget* target, + const std::string& config, + const std::string& linkLanguage); void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, const std::string& lang); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 7b02c56..3f3779a 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -32,6 +32,7 @@ #include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmSourceFile.h" @@ -1085,6 +1086,16 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( cmComputeLinkInformation& cli = *pcli; std::string linkLanguage = cli.GetLinkLanguage(); + if (!target->GetLinkerTypeProperty(linkLanguage, configName).empty()) { + // Visual Studio 10 or upper is required for this feature + this->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("'LINKER_TYPE' property, specified on target '", + target->GetName(), + "', is not supported by this generator."), + target->GetBacktrace()); + } + // Compute the variable name to lookup standard libraries for this // language. std::string standardLibsVar = @@ -1161,6 +1172,16 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( cmComputeLinkInformation& cli = *pcli; std::string linkLanguage = cli.GetLinkLanguage(); + if (!target->GetLinkerTypeProperty(linkLanguage, configName).empty()) { + // Visual Studio 10 or upper is required for this feature + this->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("'LINKER_TYPE' property, specified on target '", + target->GetName(), + "', is not supported by this generator."), + target->GetBacktrace()); + } + bool isWin32Executable = target->IsWin32Executable(configName); // Compute the variable name to lookup standard libraries for this diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 4a2b9e8..96a0d5c 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -344,6 +344,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) return; } + auto linker = this->GeneratorTarget->GetLinkerTool(this->GetConfigName()); + // Build list of dependencies. std::vector<std::string> depends; this->AppendLinkDepends(depends, linkLanguage); @@ -533,6 +535,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); vars.Language = linkLanguage.c_str(); + vars.Linker = linker.c_str(); vars.AIXExports = aixExports.c_str(); vars.Objects = buildObjs.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index fc3caa1..0429155 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -441,6 +441,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( return; } + auto linker = this->GeneratorTarget->GetLinkerTool(this->GetConfigName()); + // Build list of dependencies. std::vector<std::string> depends; this->AppendLinkDepends(depends, linkLanguage); @@ -766,6 +768,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); vars.Language = linkLanguage.c_str(); + vars.Linker = linker.c_str(); vars.AIXExports = aixExports.c_str(); vars.Objects = buildObjs.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 0c2a719..343f6b8 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -153,6 +153,8 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags( this->LocalGenerator->AppendCompileOptions(flags, opts); this->LocalGenerator->SetLinkScriptShell(false); + this->LocalGenerator->AppendLinkerTypeFlags( + flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); this->LocalGenerator->AppendPositionIndependentLinkerFlags( flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); this->LocalGenerator->AppendDependencyInfoLinkerFlags( diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 48c30b6..5e7bb6e 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -294,6 +294,9 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule( .c_str(); vars.Language = "CUDA"; + std::string linker = + this->GetGeneratorTarget()->GetLinkerTool("CUDA", config); + vars.Linker = linker.c_str(); // build response file name std::string responseFlag = this->GetMakefile()->GetSafeDefinition( @@ -400,6 +403,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules( vars.Fatbinary = "$FATBIN"; vars.RegisterFile = "$REGISTER"; vars.LinkFlags = "$LINK_FLAGS"; + std::string linker = + this->GetGeneratorTarget()->GetLinkerTool("CUDA", config); + vars.Linker = linker.c_str(); std::string flags = this->GetFlags("CUDA", config); vars.Flags = flags.c_str(); @@ -441,6 +447,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str(); + std::string linker = this->GetGeneratorTarget()->GetLinkerTool(config); + vars.Linker = linker.c_str(); std::string lang = this->TargetLinkLanguage(config); vars.Language = lang.c_str(); vars.AIXExports = "$AIX_EXPORTS"; diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 638bb42..a8c81d0 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -27,6 +27,19 @@ std::string cmRulePlaceholderExpander::ExpandVariable( return this->ReplaceValues->LinkFlags; } } + if (this->ReplaceValues->Linker) { + if (variable == "CMAKE_LINKER") { + auto result = this->OutputConverter->ConvertToOutputForExisting( + this->ReplaceValues->Linker); + if (this->ReplaceValues->Launcher) { + // Add launcher as part of expansion so that it always appears + // immediately before the command itself, regardless of whether the + // overall rule template contains other content at the front. + result = cmStrCat(this->ReplaceValues->Launcher, " ", result); + } + return result; + } + } if (this->ReplaceValues->Manifests) { if (variable == "MANIFESTS") { return this->ReplaceValues->Manifests; @@ -325,17 +338,7 @@ std::string cmRulePlaceholderExpander::ExpandVariable( auto mapIt = this->VariableMappings.find(variable); if (mapIt != this->VariableMappings.end()) { if (variable.find("_FLAG") == std::string::npos) { - std::string ret = - this->OutputConverter->ConvertToOutputForExisting(mapIt->second); - - if (this->ReplaceValues->Launcher && variable == "CMAKE_LINKER") { - // Add launcher as part of expansion so that it always appears - // immediately before the command itself, regardless of whether the - // overall rule template contains other content at the front. - ret = cmStrCat(this->ReplaceValues->Launcher, " ", ret); - } - - return ret; + return this->OutputConverter->ConvertToOutputForExisting(mapIt->second); } return mapIt->second; } diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 5d1f199..225abd4 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -53,6 +53,7 @@ public: const char* SONameFlag = nullptr; const char* TargetSOName = nullptr; const char* TargetInstallNameDir = nullptr; + const char* Linker = nullptr; const char* LinkFlags = nullptr; const char* Manifests = nullptr; const char* LanguageCompileFlags = nullptr; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index abbf29e..d93f658 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -456,6 +456,7 @@ TargetProperty const StaticTargetProperties[] = { { "AUTORCC_EXECUTABLE"_s, IC::CanCompileSources }, // Linking properties + { "LINKER_TYPE"_s, IC::CanCompileSources }, { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports }, { "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget }, { "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources }, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ce94fe1..84f808d 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2987,6 +2987,16 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( e1.WritePlatformConfigTag( "IntDir", cond, R"($(Platform)\$(Configuration)\$(ProjectName)\)"); } else { + if (ttype == cmStateEnums::SHARED_LIBRARY || + ttype == cmStateEnums::MODULE_LIBRARY || + ttype == cmStateEnums::EXECUTABLE) { + auto linker = this->GeneratorTarget->GetLinkerTool(config); + if (!linker.empty()) { + ConvertToWindowsSlash(linker); + e1.WritePlatformConfigTag("LinkToolExe", cond, linker); + } + } + std::string intermediateDir = cmStrCat( this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/', config, '/'); diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 4387c5b..4f80015 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -737,6 +737,14 @@ if((CMAKE_C_COMPILER_ID STREQUAL "AppleClang" endif() endif() +if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin|Windows)" + AND CMAKE_C_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU|MSVC|NVIDIA)$" + AND NOT CMAKE_GENERATOR STREQUAL "Green Hills MULTI") + add_RunCMake_test(LinkerSelection -DCMake_TEST_CUDA=${CMake_TEST_CUDA} + -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} + -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}) +endif() + add_RunCMake_test(File_Archive) add_RunCMake_test(File_Configure) add_RunCMake_test(File_Generate) diff --git a/Tests/RunCMake/LinkerSelection/AppleClassic.cmake b/Tests/RunCMake/LinkerSelection/AppleClassic.cmake new file mode 100644 index 0000000..62a12ad --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/AppleClassic.cmake @@ -0,0 +1,7 @@ + +enable_language(C) + +set(CMAKE_LINKER_TYPE APPLE_CLASSIC) + +add_executable(main main.c) +target_link_libraries(main PRIVATE m m) diff --git a/Tests/RunCMake/LinkerSelection/CMakeLists.txt b/Tests/RunCMake/LinkerSelection/CMakeLists.txt new file mode 100644 index 0000000..6a9ce76 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.28) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/LinkerSelection/CustomLinkerType-build-check.cmake b/Tests/RunCMake/LinkerSelection/CustomLinkerType-build-check.cmake new file mode 100644 index 0000000..235c38e --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/CustomLinkerType-build-check.cmake @@ -0,0 +1,2 @@ + +include("${CMAKE_CURRENT_LIST_DIR}/LinkerType-validation.cmake") diff --git a/Tests/RunCMake/LinkerSelection/CustomLinkerType.cmake b/Tests/RunCMake/LinkerSelection/CustomLinkerType.cmake new file mode 100644 index 0000000..4bf98b0 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/CustomLinkerType.cmake @@ -0,0 +1,36 @@ + +enable_language(C) + +set(CMAKE_C_USING_LINKER_FOO_C "${CMAKE_C_USING_LINKER_LLD}") + +add_executable(main main.c) +set_property(TARGET main PROPERTY LINKER_TYPE "$<$<LINK_LANGUAGE:C>:FOO_C>$<$<LINK_LANGUAGE:CUDA>:FOO_CUDA>") + +if(CMake_TEST_CUDA) + enable_language(CUDA) + + set(CMAKE_CUDA_USING_LINKER_FOO_CUDA "${CMAKE_CUDA_USING_LINKER_LLD}") + + add_executable(mainCU main.cu) + set_property(TARGET mainCU PROPERTY LINKER_TYPE "$<$<LINK_LANGUAGE:C>:FOO_C>$<$<LINK_LANGUAGE:CUDA>:FOO_CUDA>") +endif() + +# +# Generate file for validation +# +if (CMAKE_C_USING_LINKER_MODE STREQUAL "TOOL") + cmake_path(GET CMAKE_C_USING_LINKER_FOO_C FILENAME LINKER_TYPE_OPTION) +else() + set(LINKER_TYPE_OPTION "${CMAKE_C_USING_LINKER_FOO_C}") +endif() +if(CMake_TEST_CUDA) + if (CMAKE_CUDA_USING_LINKER_MODE STREQUAL "TOOL") + cmake_path(GET CMAKE_CUDA_USING_LINKER_FOO_CUDA FILENAME CUDA_LINKER) + else() + set(CUDA_LINKER "${CMAKE_CUDA_USING_LINKER_FOO_CUDA}") + endif() + string(APPEND LINKER_TYPE_OPTION "|${CUDA_LINKER}") +endif() + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER_TYPE_OPTION.cmake" + "set(LINKER_TYPE_OPTION \"${LINKER_TYPE_OPTION}\")\n") diff --git a/Tests/RunCMake/LinkerSelection/InvalidLinkerType-result.txt b/Tests/RunCMake/LinkerSelection/InvalidLinkerType-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/InvalidLinkerType-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/LinkerSelection/InvalidLinkerType-stderr.txt b/Tests/RunCMake/LinkerSelection/InvalidLinkerType-stderr.txt new file mode 100644 index 0000000..11aea7a --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/InvalidLinkerType-stderr.txt @@ -0,0 +1,3 @@ +CMake Error in CMakeLists.txt: + LINKER_TYPE 'FOO' is unknown. Did you forgot to define + 'CMAKE_C_USING_LINKER_FOO' variable\? diff --git a/Tests/RunCMake/LinkerSelection/InvalidLinkerType.cmake b/Tests/RunCMake/LinkerSelection/InvalidLinkerType.cmake new file mode 100644 index 0000000..bbe398c --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/InvalidLinkerType.cmake @@ -0,0 +1,5 @@ + +enable_language(C) + +set(CMAKE_LINKER_TYPE FOO) +add_executable(main main.c) diff --git a/Tests/RunCMake/LinkerSelection/LinkerType-validation.cmake b/Tests/RunCMake/LinkerSelection/LinkerType-validation.cmake new file mode 100644 index 0000000..3f82479 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/LinkerType-validation.cmake @@ -0,0 +1,9 @@ + +include ("${RunCMake_TEST_BINARY_DIR}/LINKER_TYPE_OPTION.cmake") + +# In some environment, `=` character is escaped +string(REPLACE "=" "\\\\?=" LINKER_TYPE_OPTION "${LINKER_TYPE_OPTION}") + +if (NOT actual_stdout MATCHES "${LINKER_TYPE_OPTION}") + set (RunCMake_TEST_FAILED "Not found expected '${LINKER_TYPE_OPTION}'.") +endif() diff --git a/Tests/RunCMake/LinkerSelection/RunCMakeTest.cmake b/Tests/RunCMake/LinkerSelection/RunCMakeTest.cmake new file mode 100644 index 0000000..cae4ca4 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/RunCMakeTest.cmake @@ -0,0 +1,44 @@ +include(RunCMake) + +if (RunCMake_GENERATOR MATCHES "Visual Studio 9 2008") + run_cmake(UnsupportedLinkerType) + return() +endif() + +run_cmake(InvalidLinkerType) + +# look-up for LLVM linker +if (WIN32) + set (LINKER_NAMES lld-link) +else() + set(LINKER_NAMES ld.lld ld64.lld) +endif() +find_program(LLD_LINKER NAMES ${LINKER_NAMES}) + +macro(run_cmake_and_build test) + run_cmake_with_options(${test} -DCMake_TEST_CUDA=${CMake_TEST_CUDA}) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + set(RunCMake_TEST_NO_CLEAN 1) + if(CMake_TEST_CUDA) + string(APPEND "|${CMAKE_CUDA_USING_LINKER_LLD}") + endif() + run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Release --verbose ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + +if(LLD_LINKER) + block(SCOPE_FOR VARIABLES) + set(CMAKE_VERBOSE_MAKEFILE TRUE) + set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES FALSE) + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES FALSE) + + run_cmake_and_build(ValidLinkerType) + run_cmake_and_build(CustomLinkerType) + endblock() +endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0") + run_cmake_and_build(AppleClassic) +endif() diff --git a/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType-result.txt b/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType-stderr.txt b/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType-stderr.txt new file mode 100644 index 0000000..6473451 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType-stderr.txt @@ -0,0 +1,3 @@ +CMake Error at UnsupportedLinkerType.cmake:[0-9]+ \(add_executable\): + 'LINKER_TYPE' property, specified on target 'main', is not supported by + this generator. diff --git a/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType.cmake b/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType.cmake new file mode 100644 index 0000000..1b0703c --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/UnsupportedLinkerType.cmake @@ -0,0 +1,5 @@ + +enable_language(C) + +set(CMAKE_LINKER_TYPE LDD) +add_executable(main main.c) diff --git a/Tests/RunCMake/LinkerSelection/ValidLinkerType-build-check.cmake b/Tests/RunCMake/LinkerSelection/ValidLinkerType-build-check.cmake new file mode 100644 index 0000000..235c38e --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/ValidLinkerType-build-check.cmake @@ -0,0 +1,2 @@ + +include("${CMAKE_CURRENT_LIST_DIR}/LinkerType-validation.cmake") diff --git a/Tests/RunCMake/LinkerSelection/ValidLinkerType.cmake b/Tests/RunCMake/LinkerSelection/ValidLinkerType.cmake new file mode 100644 index 0000000..a685ac1 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/ValidLinkerType.cmake @@ -0,0 +1,32 @@ + +enable_language(C) + +set(CMAKE_LINKER_TYPE LLD) + +add_executable(main main.c) + +if(CMake_TEST_CUDA) + enable_language(CUDA) + + add_executable(mainCU main.cu) +endif() + +# +# Generate file for validation +# +if (CMAKE_C_USING_LINKER_MODE STREQUAL "TOOL") + cmake_path(GET CMAKE_C_USING_LINKER_LLD FILENAME LINKER_TYPE_OPTION) +else() + set(LINKER_TYPE_OPTION "${CMAKE_C_USING_LINKER_LLD}") +endif() +if(CMake_TEST_CUDA) + if (CMAKE_CUDA_USING_LINKER_MODE STREQUAL "TOOL") + cmake_path(GET CMAKE_CUDA_USING_LINKER_LLD FILENAME CUDA_LINKER) + else() + set(CUDA_LINKER "${CMAKE_CUDA_USING_LINKER_LLD}") + endif() + string(APPEND LINKER_TYPE_OPTION "|${CUDA_LINKER}") +endif() + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER_TYPE_OPTION.cmake" + "set(LINKER_TYPE_OPTION \"${LINKER_TYPE_OPTION}\")\n") diff --git a/Tests/RunCMake/LinkerSelection/main.c b/Tests/RunCMake/LinkerSelection/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/LinkerSelection/main.cu b/Tests/RunCMake/LinkerSelection/main.cu new file mode 100644 index 0000000..766b775 --- /dev/null +++ b/Tests/RunCMake/LinkerSelection/main.cu @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} |