DefineLinkerScript.cmake
2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# This function defines a linker script in place of the symlink traditionally
# created for shared libraries.
#
# More specifically, this function goes through the PUBLIC and INTERFACE
# library dependencies of <target> and gathers them into a linker script,
# such that those libraries are linked against when the shared library for
# <target> is linked against.
#
# Arguments:
# <target>: A target representing a shared library. A linker script will be
# created in place of that target's TARGET_LINKER_FILE, which is
# the symlink pointing to the actual shared library (usually
# libFoo.so pointing to libFoo.so.1, which itself points to
# libFoo.so.1.0).
function(define_linker_script target)
if (NOT TARGET "${target}")
message(FATAL_ERROR "The provided target '${target}' is not actually a target.")
endif()
get_target_property(target_type "${target}" TYPE)
if (NOT "${target_type}" STREQUAL "SHARED_LIBRARY")
message(FATAL_ERROR "The provided target '${target}' is not a shared library (its type is '${target_type}').")
endif()
set(symlink "$<TARGET_LINKER_FILE:${target}>")
set(soname "$<TARGET_SONAME_FILE_NAME:${target}>")
get_target_property(interface_libs "${target}" INTERFACE_LINK_LIBRARIES)
set(link_libraries)
if (interface_libs)
foreach(lib IN LISTS interface_libs)
if ("${lib}" STREQUAL "cxx-headers")
continue()
endif()
# If ${lib} is not a target, we use a dummy target which we know will
# have an OUTPUT_NAME property so that CMake doesn't fail when evaluating
# the non-selected branch of the `IF`. It doesn't matter what it evaluates
# to because it's not selected, but it must not cause an error.
# See https://gitlab.kitware.com/cmake/cmake/-/issues/21045.
set(output_name_tgt "$<IF:$<TARGET_EXISTS:${lib}>,${lib},${target}>")
set(libname "$<IF:$<TARGET_EXISTS:${lib}>,$<TARGET_PROPERTY:${output_name_tgt},OUTPUT_NAME>,${lib}>")
list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}${libname}")
endforeach()
endif()
string(REPLACE ";" " " link_libraries "${link_libraries}")
set(linker_script "INPUT(${soname} ${link_libraries})")
add_custom_command(TARGET "${target}" POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E remove "${symlink}"
COMMAND "${CMAKE_COMMAND}" -E echo "${linker_script}" > "${symlink}"
COMMENT "Generating linker script: '${linker_script}' as file ${symlink}"
VERBATIM
)
endfunction()