diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -380,9 +380,6 @@ if (APPLE) message(FATAL_ERROR "LIBCXX_ENABLE_ABI_LINKER_SCRIPT cannot be used on APPLE targets") endif() - if (NOT PYTHONINTERP_FOUND) - message(FATAL_ERROR "LIBCXX_ENABLE_ABI_LINKER_SCRIPT requires python but it was not found.") - endif() if (NOT LIBCXX_ENABLE_SHARED) message(FATAL_ERROR "LIBCXX_ENABLE_ABI_LINKER_SCRIPT is only available for shared library builds.") endif() @@ -447,12 +444,9 @@ # LIBCXX_COMPILE_FLAGS: Compile only flags. # LIBCXX_LINK_FLAGS: Linker only flags. # LIBCXX_LIBRARIES: libraries libc++ is linked to. -# LIBCXX_INTERFACE_LIBRARIES: Libraries that must be linked when using libc++ -# These libraries are exposed in the linker script. set(LIBCXX_COMPILE_FLAGS "") set(LIBCXX_LINK_FLAGS "") set(LIBCXX_LIBRARIES "") -set(LIBCXX_INTERFACE_LIBRARIES "") # Include macros for adding and removing libc++ flags. include(HandleLibcxxFlags) diff --git a/libcxx/cmake/Modules/DefineLinkerScript.cmake b/libcxx/cmake/Modules/DefineLinkerScript.cmake new file mode 100644 --- /dev/null +++ b/libcxx/cmake/Modules/DefineLinkerScript.cmake @@ -0,0 +1,50 @@ +# 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 and gathers them into a linker script, +# such that those libraries are linked against when the shared library for +# is linked against. +# +# Arguments: +# : 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 "$") + set(soname "$") + + get_target_property(interface_libs "${target}" INTERFACE_LINK_LIBRARIES) + + set(link_libraries) + if (interface_libs) + foreach(lib IN LISTS interface_libs) + if (TARGET "${lib}") + list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}$") + else() + list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}${lib}") + endif() + endforeach() + endif() + list(JOIN 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() diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -177,12 +177,10 @@ if (LIBCXXABI_USE_LLVM_UNWINDER) if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) target_link_libraries(cxx_shared PUBLIC unwind_shared) - list(APPEND LIBCXX_INTERFACE_LIBRARIES unwind_shared) # For the linker script elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) # libunwind is already included in libc++abi else() - target_link_libraries(cxx_shared PRIVATE unwind) - list(APPEND LIBCXX_INTERFACE_LIBRARIES unwind) # For the linker script + target_link_libraries(cxx_shared PUBLIC unwind) endif() endif() @@ -195,7 +193,6 @@ endif() else() target_link_libraries(cxx_shared PUBLIC "${LIBCXX_CXX_SHARED_ABI_LIBRARY}") - list(APPEND LIBCXX_INTERFACE_LIBRARIES "${LIBCXX_CXX_SHARED_ABI_LIBRARY}") # For the linker script endif() # Maybe re-export symbols from libc++abi @@ -222,31 +219,10 @@ endif() endif() - # Generate a linker script in place of a libc++.so symlink. Rerun this command - # after cxx builds. + # Generate a linker script in place of a libc++.so symlink. if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT) - # Get the name of the ABI library and handle the case where CXXABI_LIBNAME - # is a target name and not a library. Ex cxxabi_shared. - set(LIBCXX_INTERFACE_LIBRARY_NAMES) - foreach(lib ${LIBCXX_INTERFACE_LIBRARIES}) - # FIXME: Handle cxxabi_static and unwind_static. - if (TARGET ${lib} OR - (${lib} MATCHES "cxxabi(_static|_shared)?" AND HAVE_LIBCXXABI) OR - (${lib} MATCHES "unwind(_static|_shared)?" AND HAVE_LIBUNWIND)) - list(APPEND LIBCXX_INTERFACE_LIBRARY_NAMES "$") - else() - list(APPEND LIBCXX_INTERFACE_LIBRARY_NAMES "${lib}") - endif() - endforeach() - add_custom_command(TARGET cxx_shared POST_BUILD - COMMAND - ${PYTHON_EXECUTABLE} ${LIBCXX_SOURCE_DIR}/utils/gen_link_script.py - ARGS - --input "$" - --output "$" - ${LIBCXX_INTERFACE_LIBRARY_NAMES} - WORKING_DIRECTORY ${LIBCXX_BUILD_DIR} - ) + include(DefineLinkerScript) + define_linker_script(cxx_shared) endif() list(APPEND LIBCXX_BUILD_TARGETS "cxx_shared") diff --git a/libcxx/utils/gen_link_script.py b/libcxx/utils/gen_link_script.py deleted file mode 100755 --- a/libcxx/utils/gen_link_script.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -#===----------------------------------------------------------------------===## -# -# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -# See https://llvm.org/LICENSE.txt for license information. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -#===----------------------------------------------------------------------===## - -""" -Generate a linker script that links libc++ to the proper ABI library. -An example script for c++abi would look like "INPUT(libc++.so.1 -lc++abi)". -""" - -import argparse -import os -import sys - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--dryrun", help="Don't write any output", - action="store_true", default=False) - parser.add_argument("--rename", action="store_true", default=False, - help="Rename the output as input so we can replace it") - parser.add_argument("--input", help="Path to libc++ library", required=True) - parser.add_argument("--output", help="Path to libc++ linker script", - required=True) - parser.add_argument("libraries", nargs="+", - help="List of libraries libc++ depends on") - args = parser.parse_args() - - # Use the relative path for the libc++ library. - libcxx = os.path.relpath(args.input, os.path.dirname(args.output)) - - # Prepare the list of public libraries to link. - public_libs = ['-l%s' % l for l in args.libraries] - - # Generate the linker script contents. - contents = "INPUT(%s)" % ' '.join([libcxx] + public_libs) - - if args.dryrun: - print("GENERATING SCRIPT: '%s' as file %s" % (contents, args.output)) - return 0 - - # Remove the existing libc++ symlink if it exists. - if os.path.islink(args.output): - os.unlink(args.output) - - # Replace it with the linker script. - with open(args.output, 'w') as f: - f.write(contents + "\n") - - return 0 - - -if __name__ == '__main__': - sys.exit(main())