|  | #!/usr/bin/python3 | 
|  |  | 
|  |  | 
|  | import argparse | 
|  | import collections | 
|  | import json | 
|  | import os | 
|  | import subprocess | 
|  | import sys | 
|  | import tempfile | 
|  |  | 
|  |  | 
|  | class OrderedSet(collections.OrderedDict): | 
|  |  | 
|  | def add(self, value): | 
|  | self[value] = True | 
|  |  | 
|  |  | 
|  | def compile_module(module, sources, settings, extras, tmpdir): | 
|  | output_file_map = {} | 
|  | if settings.whole_module_optimization: | 
|  | output_file_map[''] = { | 
|  | 'object': os.path.join(settings.object_dir, module + '.o'), | 
|  | 'dependencies': os.path.join(tmpdir, module + '.d'), | 
|  | } | 
|  | else: | 
|  | for source in sources: | 
|  | name, _ = os.path.splitext(os.path.basename(source)) | 
|  | output_file_map[source] = { | 
|  | 'object': os.path.join(settings.object_dir, name + '.o'), | 
|  | 'dependencies': os.path.join(tmpdir, name + '.d'), | 
|  | } | 
|  |  | 
|  | for key in ('module_path', 'header_path', 'depfile'): | 
|  | path = getattr(settings, key) | 
|  | if os.path.exists(path): | 
|  | os.unlink(path) | 
|  | if key == 'module_path': | 
|  | for ext in '.swiftdoc', '.swiftsourceinfo': | 
|  | path = os.path.splitext(getattr(settings, key))[0] + ext | 
|  | if os.path.exists(path): | 
|  | os.unlink(path) | 
|  | directory = os.path.dirname(path) | 
|  | if not os.path.exists(directory): | 
|  | os.makedirs(directory) | 
|  |  | 
|  | if not os.path.exists(settings.object_dir): | 
|  | os.makedirs(settings.object_dir) | 
|  |  | 
|  | for key in output_file_map: | 
|  | path = output_file_map[key]['object'] | 
|  | if os.path.exists(path): | 
|  | os.unlink(path) | 
|  |  | 
|  | output_file_map_path = os.path.join(tmpdir, module + '.json') | 
|  | with open(output_file_map_path, 'w') as output_file_map_file: | 
|  | output_file_map_file.write(json.dumps(output_file_map)) | 
|  | output_file_map_file.flush() | 
|  |  | 
|  | extra_args = [] | 
|  | if settings.bridge_header: | 
|  | extra_args.extend([ | 
|  | '-import-objc-header', | 
|  | os.path.abspath(settings.bridge_header), | 
|  | ]) | 
|  |  | 
|  | if settings.whole_module_optimization: | 
|  | extra_args.append('-whole-module-optimization') | 
|  |  | 
|  | if settings.target: | 
|  | extra_args.extend([ | 
|  | '-target', | 
|  | settings.target, | 
|  | ]) | 
|  |  | 
|  | if settings.sdk: | 
|  | extra_args.extend([ | 
|  | '-sdk', | 
|  | os.path.abspath(settings.sdk), | 
|  | ]) | 
|  |  | 
|  | if settings.include_dirs: | 
|  | for include_dir in settings.include_dirs: | 
|  | extra_args.append('-I' + include_dir) | 
|  |  | 
|  | process = subprocess.Popen( | 
|  | ['swiftc', | 
|  | '-parse-as-library', | 
|  | '-module-name', | 
|  | module, | 
|  | '-emit-object', | 
|  | '-emit-dependencies', | 
|  | '-emit-module', | 
|  | '-emit-module-path', | 
|  | settings.module_path, | 
|  | '-emit-objc-header', | 
|  | '-emit-objc-header-path', | 
|  | settings.header_path, | 
|  | '-output-file-map', | 
|  | output_file_map_path, | 
|  | ] + extra_args + extras + sources, | 
|  | stdout=subprocess.PIPE, stderr=subprocess.PIPE, | 
|  | universal_newlines=True) | 
|  |  | 
|  | stdout, stderr = process.communicate() | 
|  | if process.returncode: | 
|  | sys.stdout.write(stdout) | 
|  | sys.stderr.write(stderr) | 
|  | sys.exit(process.returncode) | 
|  |  | 
|  |  | 
|  | depfile_content = collections.OrderedDict() | 
|  | for key in output_file_map: | 
|  | for line in open(output_file_map[key]['dependencies']): | 
|  | output, inputs = line.split(' : ', 2) | 
|  | _, ext = os.path.splitext(output) | 
|  | if ext == '.o': | 
|  | key = output | 
|  | else: | 
|  | key = os.path.splitext(settings.module_path)[0] + ext | 
|  | if key not in depfile_content: | 
|  | depfile_content[key] = OrderedSet() | 
|  | for path in inputs.split(): | 
|  | depfile_content[key].add(path) | 
|  |  | 
|  | with open(settings.depfile, 'w') as depfile: | 
|  | for key in depfile_content: | 
|  | if not settings.depfile_filter or key in settings.depfile_filter: | 
|  | inputs = depfile_content[key] | 
|  | depfile.write('%s : %s\n' % (key, ' '.join(inputs))) | 
|  |  | 
|  |  | 
|  | def main(args): | 
|  | parser = argparse.ArgumentParser(add_help=False) | 
|  | parser.add_argument( | 
|  | '--module-name', | 
|  | help='name of the Swift module') | 
|  | parser.add_argument( | 
|  | '--include', '-I', action='append', dest='include_dirs', | 
|  | help='add directory to header search path') | 
|  | parser.add_argument( | 
|  | 'sources', nargs='+', | 
|  | help='Swift source file to compile') | 
|  | parser.add_argument( | 
|  | '--whole-module-optimization', action='store_true', | 
|  | help='enable whole module optimization') | 
|  | parser.add_argument( | 
|  | '--object-dir', '-o', | 
|  | help='path to the generated object files directory') | 
|  | parser.add_argument( | 
|  | '--module-path', '-m', | 
|  | help='path to the generated module file') | 
|  | parser.add_argument( | 
|  | '--header-path', '-h', | 
|  | help='path to the generated header file') | 
|  | parser.add_argument( | 
|  | '--bridge-header', '-b', | 
|  | help='path to the Objective-C bridge header') | 
|  | parser.add_argument( | 
|  | '--depfile', '-d', | 
|  | help='path to the generated depfile') | 
|  | parser.add_argument( | 
|  | '--depfile-filter', action='append', | 
|  | help='limit depfile to those files') | 
|  | parser.add_argument( | 
|  | '--target', action='store', | 
|  | help='generate code for the given target <triple>') | 
|  | parser.add_argument( | 
|  | '--sdk', action='store', | 
|  | help='compile against sdk') | 
|  |  | 
|  | parsed, extras = parser.parse_known_args(args) | 
|  | with tempfile.TemporaryDirectory() as tmpdir: | 
|  | compile_module( | 
|  | parsed.module_name, | 
|  | parsed.sources, | 
|  | parsed, | 
|  | extras, | 
|  | tmpdir) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main(sys.argv[1:])) |