|  | #!/usr/bin/env python | 
|  | #===----------------------------------------------------------------------===## | 
|  | # | 
|  | #                     The LLVM Compiler Infrastructure | 
|  | # | 
|  | # This file is dual licensed under the MIT and the University of Illinois Open | 
|  | # Source Licenses. See LICENSE.TXT for details. | 
|  | # | 
|  | #===----------------------------------------------------------------------===## | 
|  |  | 
|  | from argparse import ArgumentParser | 
|  | from ctypes.util import find_library | 
|  | import distutils.spawn | 
|  | import glob | 
|  | import tempfile | 
|  | import os | 
|  | import shutil | 
|  | import subprocess | 
|  | import signal | 
|  | import sys | 
|  |  | 
|  | temp_directory_root = None | 
|  | def exit_with_cleanups(status): | 
|  | if temp_directory_root is not None: | 
|  | shutil.rmtree(temp_directory_root) | 
|  | sys.exit(status) | 
|  |  | 
|  | def print_and_exit(msg): | 
|  | sys.stderr.write(msg + '\n') | 
|  | exit_with_cleanups(1) | 
|  |  | 
|  | def find_and_diagnose_missing(lib, search_paths): | 
|  | if os.path.exists(lib): | 
|  | return os.path.abspath(lib) | 
|  | if not lib.startswith('lib') or not lib.endswith('.a'): | 
|  | print_and_exit(("input file '%s' not not name a static library. " | 
|  | "It should start with 'lib' and end with '.a") % lib) | 
|  | for sp in search_paths: | 
|  | assert type(sp) is list and len(sp) == 1 | 
|  | path = os.path.join(sp[0], lib) | 
|  | if os.path.exists(path): | 
|  | return os.path.abspath(path) | 
|  | print_and_exit("input '%s' does not exist" % lib) | 
|  |  | 
|  |  | 
|  | def execute_command(cmd, cwd=None): | 
|  | """ | 
|  | Execute a command, capture and return its output. | 
|  | """ | 
|  | kwargs = { | 
|  | 'stdin': subprocess.PIPE, | 
|  | 'stdout': subprocess.PIPE, | 
|  | 'stderr': subprocess.PIPE, | 
|  | 'cwd': cwd | 
|  | } | 
|  | p = subprocess.Popen(cmd, **kwargs) | 
|  | out, err = p.communicate() | 
|  | exitCode = p.wait() | 
|  | if exitCode == -signal.SIGINT: | 
|  | raise KeyboardInterrupt | 
|  | return out, err, exitCode | 
|  |  | 
|  |  | 
|  | def execute_command_verbose(cmd, cwd=None, verbose=False): | 
|  | """ | 
|  | Execute a command and print its output on failure. | 
|  | """ | 
|  | out, err, exitCode = execute_command(cmd, cwd=cwd) | 
|  | if exitCode != 0 or verbose: | 
|  | report = "Command: %s\n" % ' '.join(["'%s'" % a for a in cmd]) | 
|  | if exitCode != 0: | 
|  | report += "Exit Code: %d\n" % exitCode | 
|  | if out: | 
|  | report += "Standard Output:\n--\n%s--" % out | 
|  | if err: | 
|  | report += "Standard Error:\n--\n%s--" % err | 
|  | if exitCode != 0: | 
|  | report += "\n\nFailed!" | 
|  | sys.stderr.write('%s\n' % report) | 
|  | if exitCode != 0: | 
|  | exit_with_cleanups(exitCode) | 
|  |  | 
|  | def main(): | 
|  | parser = ArgumentParser( | 
|  | description="Merge multiple archives into a single library") | 
|  | parser.add_argument( | 
|  | '-v', '--verbose', dest='verbose', action='store_true', default=False) | 
|  | parser.add_argument( | 
|  | '-o', '--output', dest='output', required=True, | 
|  | help='The output file. stdout is used if not given', | 
|  | type=str, action='store') | 
|  | parser.add_argument( | 
|  | '-L', dest='search_paths', | 
|  | help='Paths to search for the libraries along', action='append', | 
|  | nargs=1) | 
|  | parser.add_argument( | 
|  | 'archives', metavar='archives',  nargs='+', | 
|  | help='The archives to merge') | 
|  |  | 
|  | args = parser.parse_args() | 
|  |  | 
|  | ar_exe = distutils.spawn.find_executable('ar') | 
|  | if not ar_exe: | 
|  | print_and_exit("failed to find 'ar' executable") | 
|  |  | 
|  | if len(args.archives) < 2: | 
|  | print_and_exit('fewer than 2 inputs provided') | 
|  | archives = [find_and_diagnose_missing(ar, args.search_paths) | 
|  | for ar in args.archives] | 
|  | print ('Merging archives: %s' % archives) | 
|  | if not os.path.exists(os.path.dirname(args.output)): | 
|  | print_and_exit("output path doesn't exist: '%s'" % args.output) | 
|  |  | 
|  | global temp_directory_root | 
|  | temp_directory_root = tempfile.mkdtemp('.libcxx.merge.archives') | 
|  |  | 
|  | for arc in archives: | 
|  | execute_command_verbose([ar_exe, '-x', arc], cwd=temp_directory_root, | 
|  | verbose=args.verbose) | 
|  |  | 
|  | files = glob.glob(os.path.join(temp_directory_root, '*.o')) | 
|  | if not files: | 
|  | print_and_exit('Failed to glob for %s' % glob_path) | 
|  | cmd = [ar_exe, '-qc', args.output] + files | 
|  | execute_command_verbose(cmd, cwd=temp_directory_root, verbose=args.verbose) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main() | 
|  | exit_with_cleanups(0) |