1*58b9f456SAndroid Build Coastguard Worker#!/usr/bin/env python 2*58b9f456SAndroid Build Coastguard Worker#===----------------------------------------------------------------------===## 3*58b9f456SAndroid Build Coastguard Worker# 4*58b9f456SAndroid Build Coastguard Worker# The LLVM Compiler Infrastructure 5*58b9f456SAndroid Build Coastguard Worker# 6*58b9f456SAndroid Build Coastguard Worker# This file is dual licensed under the MIT and the University of Illinois Open 7*58b9f456SAndroid Build Coastguard Worker# Source Licenses. See LICENSE.TXT for details. 8*58b9f456SAndroid Build Coastguard Worker# 9*58b9f456SAndroid Build Coastguard Worker#===----------------------------------------------------------------------===## 10*58b9f456SAndroid Build Coastguard Worker 11*58b9f456SAndroid Build Coastguard Workerfrom argparse import ArgumentParser 12*58b9f456SAndroid Build Coastguard Workerfrom ctypes.util import find_library 13*58b9f456SAndroid Build Coastguard Workerimport distutils.spawn 14*58b9f456SAndroid Build Coastguard Workerimport glob 15*58b9f456SAndroid Build Coastguard Workerimport tempfile 16*58b9f456SAndroid Build Coastguard Workerimport os 17*58b9f456SAndroid Build Coastguard Workerimport shutil 18*58b9f456SAndroid Build Coastguard Workerimport subprocess 19*58b9f456SAndroid Build Coastguard Workerimport signal 20*58b9f456SAndroid Build Coastguard Workerimport sys 21*58b9f456SAndroid Build Coastguard Worker 22*58b9f456SAndroid Build Coastguard Workertemp_directory_root = None 23*58b9f456SAndroid Build Coastguard Workerdef exit_with_cleanups(status): 24*58b9f456SAndroid Build Coastguard Worker if temp_directory_root is not None: 25*58b9f456SAndroid Build Coastguard Worker shutil.rmtree(temp_directory_root) 26*58b9f456SAndroid Build Coastguard Worker sys.exit(status) 27*58b9f456SAndroid Build Coastguard Worker 28*58b9f456SAndroid Build Coastguard Workerdef print_and_exit(msg): 29*58b9f456SAndroid Build Coastguard Worker sys.stderr.write(msg + '\n') 30*58b9f456SAndroid Build Coastguard Worker exit_with_cleanups(1) 31*58b9f456SAndroid Build Coastguard Worker 32*58b9f456SAndroid Build Coastguard Workerdef find_and_diagnose_missing(lib, search_paths): 33*58b9f456SAndroid Build Coastguard Worker if os.path.exists(lib): 34*58b9f456SAndroid Build Coastguard Worker return os.path.abspath(lib) 35*58b9f456SAndroid Build Coastguard Worker if not lib.startswith('lib') or not lib.endswith('.a'): 36*58b9f456SAndroid Build Coastguard Worker print_and_exit(("input file '%s' not not name a static library. " 37*58b9f456SAndroid Build Coastguard Worker "It should start with 'lib' and end with '.a") % lib) 38*58b9f456SAndroid Build Coastguard Worker for sp in search_paths: 39*58b9f456SAndroid Build Coastguard Worker assert type(sp) is list and len(sp) == 1 40*58b9f456SAndroid Build Coastguard Worker path = os.path.join(sp[0], lib) 41*58b9f456SAndroid Build Coastguard Worker if os.path.exists(path): 42*58b9f456SAndroid Build Coastguard Worker return os.path.abspath(path) 43*58b9f456SAndroid Build Coastguard Worker print_and_exit("input '%s' does not exist" % lib) 44*58b9f456SAndroid Build Coastguard Worker 45*58b9f456SAndroid Build Coastguard Worker 46*58b9f456SAndroid Build Coastguard Workerdef execute_command(cmd, cwd=None): 47*58b9f456SAndroid Build Coastguard Worker """ 48*58b9f456SAndroid Build Coastguard Worker Execute a command, capture and return its output. 49*58b9f456SAndroid Build Coastguard Worker """ 50*58b9f456SAndroid Build Coastguard Worker kwargs = { 51*58b9f456SAndroid Build Coastguard Worker 'stdin': subprocess.PIPE, 52*58b9f456SAndroid Build Coastguard Worker 'stdout': subprocess.PIPE, 53*58b9f456SAndroid Build Coastguard Worker 'stderr': subprocess.PIPE, 54*58b9f456SAndroid Build Coastguard Worker 'cwd': cwd 55*58b9f456SAndroid Build Coastguard Worker } 56*58b9f456SAndroid Build Coastguard Worker p = subprocess.Popen(cmd, **kwargs) 57*58b9f456SAndroid Build Coastguard Worker out, err = p.communicate() 58*58b9f456SAndroid Build Coastguard Worker exitCode = p.wait() 59*58b9f456SAndroid Build Coastguard Worker if exitCode == -signal.SIGINT: 60*58b9f456SAndroid Build Coastguard Worker raise KeyboardInterrupt 61*58b9f456SAndroid Build Coastguard Worker return out, err, exitCode 62*58b9f456SAndroid Build Coastguard Worker 63*58b9f456SAndroid Build Coastguard Worker 64*58b9f456SAndroid Build Coastguard Workerdef execute_command_verbose(cmd, cwd=None, verbose=False): 65*58b9f456SAndroid Build Coastguard Worker """ 66*58b9f456SAndroid Build Coastguard Worker Execute a command and print its output on failure. 67*58b9f456SAndroid Build Coastguard Worker """ 68*58b9f456SAndroid Build Coastguard Worker out, err, exitCode = execute_command(cmd, cwd=cwd) 69*58b9f456SAndroid Build Coastguard Worker if exitCode != 0 or verbose: 70*58b9f456SAndroid Build Coastguard Worker report = "Command: %s\n" % ' '.join(["'%s'" % a for a in cmd]) 71*58b9f456SAndroid Build Coastguard Worker if exitCode != 0: 72*58b9f456SAndroid Build Coastguard Worker report += "Exit Code: %d\n" % exitCode 73*58b9f456SAndroid Build Coastguard Worker if out: 74*58b9f456SAndroid Build Coastguard Worker report += "Standard Output:\n--\n%s--" % out 75*58b9f456SAndroid Build Coastguard Worker if err: 76*58b9f456SAndroid Build Coastguard Worker report += "Standard Error:\n--\n%s--" % err 77*58b9f456SAndroid Build Coastguard Worker if exitCode != 0: 78*58b9f456SAndroid Build Coastguard Worker report += "\n\nFailed!" 79*58b9f456SAndroid Build Coastguard Worker sys.stderr.write('%s\n' % report) 80*58b9f456SAndroid Build Coastguard Worker if exitCode != 0: 81*58b9f456SAndroid Build Coastguard Worker exit_with_cleanups(exitCode) 82*58b9f456SAndroid Build Coastguard Worker 83*58b9f456SAndroid Build Coastguard Workerdef main(): 84*58b9f456SAndroid Build Coastguard Worker parser = ArgumentParser( 85*58b9f456SAndroid Build Coastguard Worker description="Merge multiple archives into a single library") 86*58b9f456SAndroid Build Coastguard Worker parser.add_argument( 87*58b9f456SAndroid Build Coastguard Worker '-v', '--verbose', dest='verbose', action='store_true', default=False) 88*58b9f456SAndroid Build Coastguard Worker parser.add_argument( 89*58b9f456SAndroid Build Coastguard Worker '-o', '--output', dest='output', required=True, 90*58b9f456SAndroid Build Coastguard Worker help='The output file. stdout is used if not given', 91*58b9f456SAndroid Build Coastguard Worker type=str, action='store') 92*58b9f456SAndroid Build Coastguard Worker parser.add_argument( 93*58b9f456SAndroid Build Coastguard Worker '-L', dest='search_paths', 94*58b9f456SAndroid Build Coastguard Worker help='Paths to search for the libraries along', action='append', 95*58b9f456SAndroid Build Coastguard Worker nargs=1) 96*58b9f456SAndroid Build Coastguard Worker parser.add_argument( 97*58b9f456SAndroid Build Coastguard Worker '--ar', dest='ar_exe', required=False, 98*58b9f456SAndroid Build Coastguard Worker help='The ar executable to use, finds \'ar\' in the path if not given', 99*58b9f456SAndroid Build Coastguard Worker type=str, action='store') 100*58b9f456SAndroid Build Coastguard Worker parser.add_argument( 101*58b9f456SAndroid Build Coastguard Worker 'archives', metavar='archives', nargs='+', 102*58b9f456SAndroid Build Coastguard Worker help='The archives to merge') 103*58b9f456SAndroid Build Coastguard Worker 104*58b9f456SAndroid Build Coastguard Worker args = parser.parse_args() 105*58b9f456SAndroid Build Coastguard Worker 106*58b9f456SAndroid Build Coastguard Worker ar_exe = args.ar_exe 107*58b9f456SAndroid Build Coastguard Worker if not ar_exe: 108*58b9f456SAndroid Build Coastguard Worker ar_exe = distutils.spawn.find_executable('ar') 109*58b9f456SAndroid Build Coastguard Worker if not ar_exe: 110*58b9f456SAndroid Build Coastguard Worker print_and_exit("failed to find 'ar' executable") 111*58b9f456SAndroid Build Coastguard Worker 112*58b9f456SAndroid Build Coastguard Worker if len(args.archives) < 2: 113*58b9f456SAndroid Build Coastguard Worker print_and_exit('fewer than 2 inputs provided') 114*58b9f456SAndroid Build Coastguard Worker archives = [find_and_diagnose_missing(ar, args.search_paths) 115*58b9f456SAndroid Build Coastguard Worker for ar in args.archives] 116*58b9f456SAndroid Build Coastguard Worker print ('Merging archives: %s' % archives) 117*58b9f456SAndroid Build Coastguard Worker if not os.path.exists(os.path.dirname(args.output)): 118*58b9f456SAndroid Build Coastguard Worker print_and_exit("output path doesn't exist: '%s'" % args.output) 119*58b9f456SAndroid Build Coastguard Worker 120*58b9f456SAndroid Build Coastguard Worker global temp_directory_root 121*58b9f456SAndroid Build Coastguard Worker temp_directory_root = tempfile.mkdtemp('.libcxx.merge.archives') 122*58b9f456SAndroid Build Coastguard Worker 123*58b9f456SAndroid Build Coastguard Worker for arc in archives: 124*58b9f456SAndroid Build Coastguard Worker execute_command_verbose([ar_exe, 'x', arc], cwd=temp_directory_root, 125*58b9f456SAndroid Build Coastguard Worker verbose=args.verbose) 126*58b9f456SAndroid Build Coastguard Worker 127*58b9f456SAndroid Build Coastguard Worker files = glob.glob(os.path.join(temp_directory_root, '*.o*')) 128*58b9f456SAndroid Build Coastguard Worker if not files: 129*58b9f456SAndroid Build Coastguard Worker print_and_exit('Failed to glob for %s' % temp_directory_root) 130*58b9f456SAndroid Build Coastguard Worker cmd = [ar_exe, 'qcs', args.output] + files 131*58b9f456SAndroid Build Coastguard Worker execute_command_verbose(cmd, cwd=temp_directory_root, verbose=args.verbose) 132*58b9f456SAndroid Build Coastguard Worker 133*58b9f456SAndroid Build Coastguard Worker 134*58b9f456SAndroid Build Coastguard Workerif __name__ == '__main__': 135*58b9f456SAndroid Build Coastguard Worker main() 136*58b9f456SAndroid Build Coastguard Worker exit_with_cleanups(0) 137