1# Copyright 2020 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4"""Strip arm64e architecture from a binary if present.""" 5 6import argparse 7import os 8import shutil 9import subprocess 10import sys 11 12 13def check_output(command): 14 """Returns the output from |command| or propagates error, quitting script.""" 15 process = subprocess.Popen( 16 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 17 outs, errs = process.communicate() 18 if process.returncode: 19 sys.stderr.write('error: command failed with retcode %d: %s\n\n' % 20 (process.returncode, ' '.join(map(repr, command)))) 21 sys.stderr.write(errs.decode('UTF-8', errors='ignore')) 22 sys.exit(process.returncode) 23 return outs.decode('UTF-8') 24 25 26def check_call(command): 27 """Invokes |command| or propagates error.""" 28 check_output(command) 29 30 31def parse_args(args): 32 """Parses the command-line.""" 33 parser = argparse.ArgumentParser() 34 parser.add_argument('--input', required=True, help='Path to input binary') 35 parser.add_argument('--output', required=True, help='Path to output binary') 36 parser.add_argument('--xcode-version', required=True, help='Version of Xcode') 37 return parser.parse_args(args) 38 39 40def get_archs(path): 41 """Extracts the architectures present in binary at |path|.""" 42 outputs = check_output(["xcrun", "lipo", "-info", os.path.abspath(path)]) 43 return outputs.split(': ')[-1].split() 44 45 46def main(args): 47 parsed = parse_args(args) 48 49 outdir = os.path.dirname(parsed.output) 50 if not os.path.isdir(outdir): 51 os.makedirs(outdir) 52 53 if os.path.exists(parsed.output): 54 os.unlink(parsed.output) 55 56 # As "lipo" fails with an error if asked to remove an architecture that is 57 # not included, only use it if "arm64e" is present in the binary. Otherwise 58 # simply copy the file. 59 if 'arm64e' in get_archs(parsed.input): 60 check_output([ 61 "xcrun", "lipo", "-remove", "arm64e", "-output", 62 os.path.abspath(parsed.output), 63 os.path.abspath(parsed.input) 64 ]) 65 else: 66 shutil.copy(parsed.input, parsed.output) 67 68 69if __name__ == '__main__': 70 main(sys.argv[1:]) 71