import os import shutil import subprocess import sys MAGIC = { b'\xca\xfe\xba\xbe': 'MachO-universal', b'\xce\xfa\xed\xfe': 'MachO-i386', b'\xcf\xfa\xed\xfe': 'MachO-x86_64', b'\xfe\xed\xfa\xce': 'MachO-ppc', b'\xfe\xed\xfa\xcf': 'MachO-ppc64', } def get_arch(path): with open(path, 'rb') as fi: head = fi.read(4) try: return MAGIC[head][6:] except KeyError: return None def cp_arch(src_path, dst_path, arch='x86_64', ignore_wrong_arch=False): src_arch = get_arch(src_path) if src_arch == arch: shutil.copy2(src_path, dst_path) elif src_arch == 'universal': subprocess.check_call(['lipo', '-thin', arch, '-output', dst_path, src_path]) else: msg = "MachO type %r: %s" % (src_arch, src_path) if ignore_wrong_arch: sys.stdout.write('WARNING: ignoring %s\n' % msg) shutil.copy2(src_path, dst_path) else: sys.exit('ERROR: %s' % msg) def main_cp_arch(): from optparse import OptionParser p = OptionParser(usage="usage: %prog [options] SRC [SRC ...] DST_DIR", description="""\ Copy MachO binaries from SRC to DST_DIR, and use lipo to "thin" binaries (if necessary), such that all binaries in DST_DIR are thin binaries of ARCH.""") p.add_option("--arch", action="store", default="x86_64", help="target architecture, defaults to %default") p.add_option("--ignore-wrong-arch", action="store_true", help="ignore non-universal binaries of wrong ARCH") opts, args = p.parse_args() if len(args) < 2: p.error('two or more arguments expected, try -h') src_paths, dst_dir = args[:-1], args[-1] if not os.path.isdir(dst_dir): p.error('no such directory: %s' % dst_dir) for src_path in src_paths: if os.path.isfile(src_path): cp_arch(src_path, os.path.join(dst_dir, os.path.basename(src_path)), arch=opts.arch, ignore_wrong_arch=opts.ignore_wrong_arch) if __name__ == '__main__': main_cp_arch()