1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-24 19:59:47 +08:00

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
This commit is contained in:
Marc Chevrier
2024-10-06 20:28:11 +02:00
parent 5b4dbd87f1
commit aba1c9d172
20 changed files with 194 additions and 0 deletions

View File

@@ -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_<LANG>_LINKER_WRAPPER_FLAG` and
:variable:`CMAKE_<LANG>_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.

View File

@@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
target_link_libraries-LINKER-prefix
-----------------------------------
* The :command:`target_link_libraries` command gains the support of the
``LINKER:`` prefix.

View File

@@ -1883,6 +1883,7 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry,
// foo ==> -lfoo
// libfoo.a ==> -Wl,-Bstatic -lfoo
const cm::string_view LINKER{ "LINKER:" };
BT<std::string> 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<BT<std::string>> 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

View File

@@ -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})

View File

@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.30...3.32)
project(${RunCMake_TEST} LANGUAGES NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,3 @@
set(reference_file "LINKER.txt")
include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")

View File

@@ -0,0 +1,3 @@
set(reference_file "LINKER.txt")
include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")

View File

@@ -0,0 +1,3 @@
set(reference_file "LINKER.txt")
include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")

View File

@@ -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()

View File

@@ -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}")

View File

@@ -0,0 +1,7 @@
#if defined(_WIN32)
__declspec(dllexport)
#endif
int flags_lib(void)
{
return 0;
}

View File

@@ -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()

View File

@@ -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\)

View File

@@ -0,0 +1,5 @@
enable_language(C)
add_library(example SHARED LinkOptionsLib.c)
target_link_libraries(example PRIVATE "LINKER:-foo,SHELL:-bar")

View File

@@ -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;
}