Index: libcxx/cmake/Modules/HandleLibcxxFlags.cmake =================================================================== --- libcxx/cmake/Modules/HandleLibcxxFlags.cmake +++ libcxx/cmake/Modules/HandleLibcxxFlags.cmake @@ -228,3 +228,12 @@ macro(split_list listname) string(REPLACE ";" " " ${listname} "${${listname}}") endmacro() + +# Appends value to all lists in ARGN, if the condition is true. +macro(append_list_if condition value) + if(${condition}) + foreach(list ${ARGN}) + list(APPEND ${list} ${value}) + endforeach() + endif() +endmacro() Index: libcxx/cmake/config-ix.cmake =================================================================== --- libcxx/cmake/config-ix.cmake +++ libcxx/cmake/config-ix.cmake @@ -84,4 +84,5 @@ check_library_exists(pthread pthread_create "" LIBCXX_HAS_PTHREAD_LIB) check_library_exists(m ccos "" LIBCXX_HAS_M_LIB) check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB) + check_library_exists(dl dlopen "" LIBCXX_HAS_DL_LIB) endif() Index: libcxx/lib/CMakeLists.txt =================================================================== --- libcxx/lib/CMakeLists.txt +++ libcxx/lib/CMakeLists.txt @@ -352,7 +352,7 @@ # Generate a linker script inplace of a libc++.so symlink. Rerun this command # after cxx builds. -if (LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_ABI_LINKER_SCRIPT) +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) @@ -373,10 +373,26 @@ COMMAND ${PYTHON_EXECUTABLE} ${LIBCXX_SOURCE_DIR}/utils/gen_link_script.py ARGS + "$" "$" ${LIBCXX_INTERFACE_LIBRARY_NAMES} WORKING_DIRECTORY ${LIBCXX_BUILD_DIR} ) + append_list_if(LIBCXX_HAS_M_LIB m LIBCXX_STATIC_LIBRARY_LIBS) + append_list_if(LIBCXX_HAS_DL_LIB dl LIBCXX_STATIC_LIBRARY_LIBS) + append_list_if(LIBCXX_HAS_PTHREAD_LIB pthread LIBCXX_STATIC_LIBRARY_LIBS) + add_custom_command(TARGET cxx_static POST_BUILD + COMMAND + ${PYTHON_EXECUTABLE} ${LIBCXX_SOURCE_DIR}/utils/gen_link_script.py + ARGS + "${CMAKE_STATIC_LIBRARY_PREFIX}c++static${CMAKE_STATIC_LIBRARY_SUFFIX}" + "$" + ${LIBCXX_INTERFACE_LIBRARY_NAMES} + ${LIBCXX_STATIC_LIBRARY_LIBS} + BYPRODUCTS + ${LIBCXX_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}c++static${CMAKE_STATIC_LIBRARY_SUFFIX} + WORKING_DIRECTORY ${LIBCXX_LIBRARY_DIR} + ) endif() if (LIBCXX_INSTALL_LIBRARY) Index: libcxx/utils/gen_link_script.py =================================================================== --- libcxx/utils/gen_link_script.py +++ libcxx/utils/gen_link_script.py @@ -8,77 +8,56 @@ # #===----------------------------------------------------------------------===## +""" +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 print_and_exit(msg): - sys.stderr.write(msg + '\n') - sys.exit(1) - -def usage_and_exit(): - print_and_exit("Usage: ./gen_link_script.py [--help] [--dryrun] ...") - -def help_and_exit(): - help_msg = \ -"""Usage - - gen_link_script.py [--help] [--dryrun] ... - - Generate a linker script that links libc++ to the proper ABI library. - The script replaces the specified libc++ symlink. - An example script for c++abi would look like "INPUT(libc++.so.1 -lc++abi)". - -Arguments - - The top level symlink to the versioned libc++ shared - library. This file is replaced with a linker script. - - List of library names to include in linker script. - -Exit Status: - 0 if OK, - 1 if the action failed. -""" - print_and_exit(help_msg) - -def parse_args(): - args = list(sys.argv) - del args[0] - if len(args) == 0: - usage_and_exit() - if args[0] == '--help': - help_and_exit() - dryrun = '--dryrun' == args[0] - if dryrun: - del args[0] - if len(args) < 2: - usage_and_exit() - symlink_file = args[0] - public_libs = args[1:] - return dryrun, symlink_file, public_libs def main(): - dryrun, symlink_file, public_libs = parse_args() - - # Check that the given libc++.so file is a valid symlink. - if not os.path.islink(symlink_file): - print_and_exit("symlink file %s is not a symlink" % symlink_file) - - # Read the symlink so we know what libc++ to link to in the linker script. - linked_libcxx = os.readlink(symlink_file) + 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") + parser.add_argument("output", help="Path to libc++ linker script") + parser.add_argument("libraries", nargs="+", + help="List of libraries libc++ depends on") + args = parser.parse_args() + + if os.path.islink(args.input): + # Read the symlink so we know what libc++ to link to. + libcxx = os.readlink(args.input) + elif not os.path.exists(args.input): + # Rename the output so we can replace it with the script. + libcxx = os.path.relpath(args.input) + if os.path.exists(args.output): + os.rename(args.output, libcxx) + else: + libcxx = args.input # Prepare the list of public libraries to link. - public_libs = ['-l%s' % l for l in public_libs] + public_libs = ['-l%s' % l for l in args.libraries] # Generate the linker script contents and print the script and destination # information. - contents = "INPUT(%s %s)" % (linked_libcxx, ' '.join(public_libs)) - print("GENERATING SCRIPT: '%s' as file %s" % (contents, symlink_file)) + contents = "INPUT(%s %s)" % (libcxx, ' '.join(public_libs)) + print("GENERATING SCRIPT: '%s' as file %s" % (contents, args.output)) + + if args.dryrun: + return 0 # Remove the existing libc++ symlink and replace it with the script. - if not dryrun: - os.unlink(symlink_file) - with open(symlink_file, 'w') as f: - f.write(contents + "\n") + with open(args.output, 'w') as f: + f.write(contents + "\n") + + return 0 if __name__ == '__main__': - main() + sys.exit(main())