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