From aba1c9d17232bfcb5e91fcfe6322e6ef37f92ca1 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Sun, 6 Oct 2024 20:28:11 +0200 Subject: [PATCH] target_link_libraries: Add support for the LINKER: prefix It is now possible to use the `LINKER:` prefix in `LINK_LIBRARIES` and `INTERFACE_LINK_LIBRARIES` target properties. Fixes: #26318 --- Help/command/LINK_LIBRARIES_LINKER.txt | 24 +++++++ Help/command/target_link_libraries.rst | 2 + Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst | 2 + Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst | 6 ++ Help/prop_tgt/LINK_LIBRARIES.rst | 2 + .../target_link_libraries-LINKER-prefix.rst | 5 ++ Source/cmComputeLinkInformation.cxx | 8 +++ Tests/RunCMake/CMakeLists.txt | 1 + .../CMakeLists.txt | 5 ++ .../LINKER_expansion-LINKER-check.cmake | 3 + ...NKER_expansion-LINKER_CONSUMER-check.cmake | 3 + .../LINKER_expansion-LINKER_SHELL-check.cmake | 3 + .../LINKER_expansion-validation.cmake | 15 +++++ .../LINKER_expansion.cmake | 63 +++++++++++++++++++ .../LinkOptionsLib.c | 7 +++ .../RunCMakeTest.cmake | 22 +++++++ .../bad_SHELL_usage-result.txt | 1 + .../bad_SHELL_usage-stderr.txt | 4 ++ .../bad_SHELL_usage.cmake | 5 ++ .../dump.c | 13 ++++ 20 files changed, 194 insertions(+) create mode 100644 Help/command/LINK_LIBRARIES_LINKER.txt create mode 100644 Help/release/dev/target_link_libraries-LINKER-prefix.rst create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c diff --git a/Help/command/LINK_LIBRARIES_LINKER.txt b/Help/command/LINK_LIBRARIES_LINKER.txt new file mode 100644 index 0000000000..7dc6b8410f --- /dev/null +++ b/Help/command/LINK_LIBRARIES_LINKER.txt @@ -0,0 +1,24 @@ +Handling Compiler Driver Differences +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.32 + +To pass options to the linker tool, each compiler driver has its own syntax. +The ``LINKER:`` prefix and ``,`` separator can be used to specify, in a portable +way, options to pass to the linker tool. ``LINKER:`` is replaced by the +appropriate driver option and ``,`` by the appropriate driver separator. +The driver prefix and driver separator are given by the values of the +:variable:`CMAKE__LINKER_WRAPPER_FLAG` and +:variable:`CMAKE__LINKER_WRAPPER_FLAG_SEP` variables. + +For example, ``"LINKER:-z,defs"`` becomes ``-Xlinker -z -Xlinker defs`` for +``Clang`` and ``-Wl,-z,defs`` for ``GNU GCC``. + +The ``LINKER:`` prefix supports, as an alternative syntax, specification of +arguments using the ``SHELL:`` prefix and space as separator. The previous +example then becomes ``"LINKER:SHELL:-z defs"``. + +.. note:: + + Specifying the ``SHELL:`` prefix anywhere other than at the beginning of the + ``LINKER:`` prefix is not supported. diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst index 94a24297db..caa6441978 100644 --- a/Help/command/target_link_libraries.rst +++ b/Help/command/target_link_libraries.rst @@ -148,6 +148,8 @@ command lines. See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem properties. +.. include:: ../command/LINK_LIBRARIES_LINKER.txt + Libraries for a Target and/or its Dependents ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst index 53f5838f7a..73d273bb94 100644 --- a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst +++ b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst @@ -32,6 +32,8 @@ direct link dependencies of a target's dependents by using the :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` and :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE` target properties. +.. include:: ../command/LINK_LIBRARIES_LINKER.txt + Creating Relocatable Packages ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst index 785b17cfa5..886adf2379 100644 --- a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst +++ b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst @@ -8,3 +8,9 @@ INTERFACE_LINK_OPTIONS .. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_OPTIONS`` .. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_OPTIONS` .. include:: INTERFACE_BUILD_PROPERTY.txt + +.. include:: ../command/DEVICE_LINK_OPTIONS.txt + +.. include:: ../command/OPTIONS_SHELL.txt + +.. include:: ../command/LINK_OPTIONS_LINKER.txt diff --git a/Help/prop_tgt/LINK_LIBRARIES.rst b/Help/prop_tgt/LINK_LIBRARIES.rst index b449aa151b..8814980b71 100644 --- a/Help/prop_tgt/LINK_LIBRARIES.rst +++ b/Help/prop_tgt/LINK_LIBRARIES.rst @@ -33,3 +33,5 @@ See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target property for details on how CMake orders direct link dependencies on linker command lines. + +.. include:: ../command/LINK_LIBRARIES_LINKER.txt diff --git a/Help/release/dev/target_link_libraries-LINKER-prefix.rst b/Help/release/dev/target_link_libraries-LINKER-prefix.rst new file mode 100644 index 0000000000..08f36af4f1 --- /dev/null +++ b/Help/release/dev/target_link_libraries-LINKER-prefix.rst @@ -0,0 +1,5 @@ +target_link_libraries-LINKER-prefix +----------------------------------- + +* The :command:`target_link_libraries` command gains the support of the + ``LINKER:`` prefix. diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 26ff32649a..bd401151f5 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1883,6 +1883,7 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, // foo ==> -lfoo // libfoo.a ==> -Wl,-Bstatic -lfoo + const cm::string_view LINKER{ "LINKER:" }; BT const& item = entry.Item; if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') { @@ -1905,6 +1906,13 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, this->Items.emplace_back(item, ItemIsPath::No); return; } + if (cmHasPrefix(item.Value, LINKER)) { + std::vector> linkerFlag{ 1, item }; + this->Target->ResolveLinkerWrapper(linkerFlag, this->GetLinkLanguage(), + true); + this->Items.emplace_back(linkerFlag.front(), ItemIsPath::No); + return; + } // Parse out the prefix, base, and suffix components of the // library name. If the name matches that of a shared or static diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0a96aef221..85da0cd552 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -875,6 +875,7 @@ add_RunCMake_test(target_link_libraries-LINK_GROUP -DCMAKE_SYSTEM_NAME=${CMAKE_S -DCMAKE_IMPORT_LIBRARY_PREFIX=${CMAKE_IMPORT_LIBRARY_PREFIX} -DCMAKE_IMPORT_LIBRARY_SUFFIX=${CMAKE_IMPORT_LIBRARY_SUFFIX} -DCMAKE_LINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}) +add_RunCMake_test(target_link_libraries-LINKER-prefix -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}) add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}) add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} -DCMake_TEST_CUDA=${CMake_TEST_CUDA}) diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt new file mode 100644 index 0000000000..a8cb6d1811 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.30...3.32) + +project(${RunCMake_TEST} LANGUAGES NONE) + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake new file mode 100644 index 0000000000..99f5aa3fc2 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake @@ -0,0 +1,3 @@ + +set(reference_file "LINKER.txt") +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake new file mode 100644 index 0000000000..99f5aa3fc2 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake @@ -0,0 +1,3 @@ + +set(reference_file "LINKER.txt") +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake new file mode 100644 index 0000000000..99f5aa3fc2 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake @@ -0,0 +1,3 @@ + +set(reference_file "LINKER.txt") +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake new file mode 100644 index 0000000000..27adde6744 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake @@ -0,0 +1,15 @@ + +if (actual_stdout MATCHES "LINKER:" AND NOT linker_prefix_expected) + set (RunCMake_TEST_FAILED "LINKER: prefix was not expanded.") + return() +endif() + +if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${reference_file}") + set (RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/${reference_file}: Reference file not found.") + return() +endif() +file(READ "${RunCMake_TEST_BINARY_DIR}/${reference_file}" linker_flag) + +if (NOT actual_stdout MATCHES "${linker_flag}") + set (RunCMake_TEST_FAILED "LINKER: was not expanded correctly.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake new file mode 100644 index 0000000000..f71efbdac3 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake @@ -0,0 +1,63 @@ + +enable_language(C) + +set(cfg_dir) +get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(_isMultiConfig) + set(cfg_dir /Debug) +endif() +set(DUMP_EXE "${CMAKE_CURRENT_BINARY_DIR}${cfg_dir}/dump${CMAKE_EXECUTABLE_SUFFIX}") + +add_executable(dump dump.c) + +# ensure no temp file nor response file will be used +set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 0) +string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") +string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") + +function (add_test_library target_name) + add_library(${target_name} SHARED LinkOptionsLib.c) + + # use LAUNCH facility to dump linker command + set_property(TARGET ${target_name} PROPERTY RULE_LAUNCH_LINK "\"${DUMP_EXE}\"") + + add_dependencies(${target_name} dump) +endfunction() + +# Use LINKER alone +add_test_library(linker) +target_link_libraries(linker PRIVATE "LINKER:-foo,bar") + +# Use LINKER with SHELL +add_test_library(linker_shell) +target_link_libraries(linker_shell PRIVATE "LINKER:SHELL:-foo bar") + +# Propagate LINKER +add_library(linker_interface INTERFACE) +target_link_libraries(linker_interface INTERFACE "LINKER:-foo,bar") +add_test_library(linker_consumer) +target_link_libraries(linker_consumer PRIVATE linker_interface) + +# generate reference for LINKER flag +if (CMAKE_C_LINKER_WRAPPER_FLAG) + set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG}) + list(GET linker_flag -1 linker_space) + if (linker_space STREQUAL " ") + list(REMOVE_AT linker_flag -1) + else() + set(linker_space) + endif() + list (JOIN linker_flag " " linker_flag) + if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP) + set(linker_sep "${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}") + + string (APPEND linker_flag "${linker_space}" "-foo${linker_sep}bar") + else() + set(linker_prefix "${linker_flag}${linker_space}") + + set (linker_flag "${linker_prefix}-foo ${linker_prefix}bar") + endif() +else() + set(linker_flag "-foo bar") +endif() +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER.txt" "${linker_flag}") diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c new file mode 100644 index 0000000000..9bbd24cd8b --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) +__declspec(dllexport) +#endif + int flags_lib(void) +{ + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake new file mode 100644 index 0000000000..cabf2cc03b --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake @@ -0,0 +1,22 @@ + +include(RunCMake) + +macro(run_cmake_target test subtest target) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + + +run_cmake(bad_SHELL_usage) + +if(RunCMake_GENERATOR MATCHES "(Ninja|Makefile)") + run_cmake(LINKER_expansion) + + run_cmake_target(LINKER_expansion LINKER linker) + run_cmake_target(LINKER_expansion LINKER_SHELL linker_shell) + run_cmake_target(LINKER_expansion LINKER_CONSUMER linker_consumer) +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt new file mode 100644 index 0000000000..d6a298d34f --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at bad_SHELL_usage.cmake:[0-9]+ \(add_library\): + 'SHELL:' prefix is not supported as part of 'LINKER:' arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake new file mode 100644 index 0000000000..e25bef60a8 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake @@ -0,0 +1,5 @@ + +enable_language(C) + +add_library(example SHARED LinkOptionsLib.c) +target_link_libraries(example PRIVATE "LINKER:-foo,SHELL:-bar") diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c b/Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c new file mode 100644 index 0000000000..8baa313fd1 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c @@ -0,0 +1,13 @@ + +#include "stdio.h" + +int main(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + return 0; +}