1# This function defines a linker script in place of the symlink traditionally
2# created for shared libraries.
3#
4# More specifically, this function goes through the PUBLIC and INTERFACE
5# library dependencies of <target> and gathers them into a linker script,
6# such that those libraries are linked against when the shared library for
7# <target> is linked against.
8#
9# Arguments:
10#   <target>: A target representing a shared library. A linker script will be
11#             created in place of that target's TARGET_LINKER_FILE, which is
12#             the symlink pointing to the actual shared library (usually
13#             libFoo.so pointing to libFoo.so.1, which itself points to
14#             libFoo.so.1.0).
15
16function(define_linker_script target)
17  if (NOT TARGET "${target}")
18    message(FATAL_ERROR "The provided target '${target}' is not actually a target.")
19  endif()
20
21  get_target_property(target_type "${target}" TYPE)
22  if (NOT "${target_type}" STREQUAL "SHARED_LIBRARY")
23    message(FATAL_ERROR "The provided target '${target}' is not a shared library (its type is '${target_type}').")
24  endif()
25
26  set(symlink "$<TARGET_LINKER_FILE:${target}>")
27  set(soname "$<TARGET_SONAME_FILE_NAME:${target}>")
28
29  get_target_property(interface_libs "${target}" INTERFACE_LINK_LIBRARIES)
30
31  set(link_libraries)
32  if (interface_libs)
33    foreach(lib IN LISTS interface_libs)
34      if ("${lib}" STREQUAL "cxx-headers")
35        continue()
36      endif()
37      if (TARGET "${lib}" OR
38          (${lib} MATCHES "cxxabi(_static|_shared)?" AND HAVE_LIBCXXABI) OR
39          (${lib} MATCHES "unwind(_static|_shared)?" AND HAVE_LIBUNWIND))
40        list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}$<TARGET_PROPERTY:${lib},OUTPUT_NAME>")
41      else()
42        list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}${lib}")
43      endif()
44    endforeach()
45  endif()
46  string(REPLACE ";" " " link_libraries "${link_libraries}")
47
48  set(linker_script "INPUT(${soname} ${link_libraries})")
49  add_custom_command(TARGET "${target}" POST_BUILD
50    COMMAND "${CMAKE_COMMAND}" -E remove "${symlink}"
51    COMMAND "${CMAKE_COMMAND}" -E echo "${linker_script}" > "${symlink}"
52    COMMENT "Generating linker script: '${linker_script}' as file ${symlink}"
53    VERBATIM
54  )
55endfunction()
56