#!/usr/bin/env python3 # Postprocess binaries to prepare for their execution on Darwin platforms. # This includes un-rpathization and codesigning. import argparse import os import re import subprocess import sys utils = os.path.dirname(os.path.realpath(__file__)) def main(arguments): parser = argparse.ArgumentParser( description='Postprocess binaries to prepare for \ their execution on Darwin platforms') parser.add_argument('bins', nargs='+', help='one or more binary files') args = parser.parse_args(arguments) for bin in args.bins: unrpathize(bin) codesign(bin) # This function rewrites binaries that use these `@rpath`-based load # commands to use direct /usr/lib/swift paths instead, to work around # an issue where the DYLD_LIBRARY_PATH override doesn't reliably work # with runpath-relative loads of system libraries on some dyld versions. # (rdar://78851265) def unrpathize(filename): dylibsOutput = subprocess.check_output( ['xcrun', 'dyldinfo', '-dylibs', filename]) # Do not rewrite @rpath-relative load commands for these libraries: # they are test support libraries that are never installed under # /usr/lib/swift and they aren't loaded via DYLD_LIBRARY_PATH. allow_list = { 'libswiftDifferentiationUnittest.dylib', 'libswiftLocalizationAnalysisTestHelper.dylib', 'libswiftOSLogTestHelper.dylib', 'libswiftRemoteMirror.dylib', 'libswiftRuntimeUnittest.dylib', 'libswiftStdlibCollectionUnittest.dylib', 'libswiftStdlibUnicodeUnittest.dylib', 'libswiftStdlibUnittest.dylib', 'libswiftStdlibUnittestFoundationExtras.dylib', 'libswiftSwiftPrivate.dylib', 'libswiftSwiftPrivateLibcExtras.dylib', 'libswiftSwiftPrivateThreadExtras.dylib', 'libswiftSwiftReflectionTest.dylib', } # The output from dyldinfo -dylibs is a line of header followed by one # install name per line, indented with spaces. dylib_regex = re.compile( r"(^|.*\s)(?P@rpath/(?Plibswift.*\.dylib))\s*$") # Build a command to invoke install_name_tool. command = ['install_name_tool'] for binaryline in dylibsOutput.splitlines(): line = binaryline.decode("utf-8", "strict") match = dylib_regex.match(line) if match and match.group('filename') not in allow_list: command.append('-change') command.append(match.group('path')) command.append('/usr/lib/swift/' + match.group('filename')) continue # Don't run the command if we didn't find any dylibs to change: # it's invalid to invoke install_name_tool without any operations. if len(command) == 1: return # The last argument is the filename to operate on. command.append(filename) subprocess.check_call(command) def codesign(filename): # "-" is the signing identity for ad-hoc signing. command = ["/usr/bin/codesign", "--force", "--sign", "-", filename] subprocess.check_call(command) sys.exit(main(sys.argv[1:]))