16d528ed9Sopenharmony_ci#!/usr/bin/python3
26d528ed9Sopenharmony_ci
36d528ed9Sopenharmony_ci
46d528ed9Sopenharmony_ciimport argparse
56d528ed9Sopenharmony_ciimport collections
66d528ed9Sopenharmony_ciimport json
76d528ed9Sopenharmony_ciimport os
86d528ed9Sopenharmony_ciimport subprocess
96d528ed9Sopenharmony_ciimport sys
106d528ed9Sopenharmony_ciimport tempfile
116d528ed9Sopenharmony_ci
126d528ed9Sopenharmony_ci
136d528ed9Sopenharmony_ciclass OrderedSet(collections.OrderedDict):
146d528ed9Sopenharmony_ci
156d528ed9Sopenharmony_ci  def add(self, value):
166d528ed9Sopenharmony_ci    self[value] = True
176d528ed9Sopenharmony_ci
186d528ed9Sopenharmony_ci
196d528ed9Sopenharmony_cidef compile_module(module, sources, settings, extras, tmpdir):
206d528ed9Sopenharmony_ci  output_file_map = {}
216d528ed9Sopenharmony_ci  if settings.whole_module_optimization:
226d528ed9Sopenharmony_ci    output_file_map[''] = {
236d528ed9Sopenharmony_ci        'object': os.path.join(settings.object_dir, module + '.o'),
246d528ed9Sopenharmony_ci        'dependencies': os.path.join(tmpdir, module + '.d'),
256d528ed9Sopenharmony_ci    }
266d528ed9Sopenharmony_ci  else:
276d528ed9Sopenharmony_ci    for source in sources:
286d528ed9Sopenharmony_ci      name, _ = os.path.splitext(os.path.basename(source))
296d528ed9Sopenharmony_ci      output_file_map[source] = {
306d528ed9Sopenharmony_ci          'object': os.path.join(settings.object_dir, name + '.o'),
316d528ed9Sopenharmony_ci          'dependencies': os.path.join(tmpdir, name + '.d'),
326d528ed9Sopenharmony_ci      }
336d528ed9Sopenharmony_ci
346d528ed9Sopenharmony_ci  for key in ('module_path', 'header_path', 'depfile'):
356d528ed9Sopenharmony_ci    path = getattr(settings, key)
366d528ed9Sopenharmony_ci    if os.path.exists(path):
376d528ed9Sopenharmony_ci      os.unlink(path)
386d528ed9Sopenharmony_ci    if key == 'module_path':
396d528ed9Sopenharmony_ci      for ext in '.swiftdoc', '.swiftsourceinfo':
406d528ed9Sopenharmony_ci        path = os.path.splitext(getattr(settings, key))[0] + ext
416d528ed9Sopenharmony_ci        if os.path.exists(path):
426d528ed9Sopenharmony_ci          os.unlink(path)
436d528ed9Sopenharmony_ci    directory = os.path.dirname(path)
446d528ed9Sopenharmony_ci    if not os.path.exists(directory):
456d528ed9Sopenharmony_ci      os.makedirs(directory)
466d528ed9Sopenharmony_ci
476d528ed9Sopenharmony_ci  if not os.path.exists(settings.object_dir):
486d528ed9Sopenharmony_ci    os.makedirs(settings.object_dir)
496d528ed9Sopenharmony_ci
506d528ed9Sopenharmony_ci  for key in output_file_map:
516d528ed9Sopenharmony_ci    path = output_file_map[key]['object']
526d528ed9Sopenharmony_ci    if os.path.exists(path):
536d528ed9Sopenharmony_ci      os.unlink(path)
546d528ed9Sopenharmony_ci
556d528ed9Sopenharmony_ci  output_file_map_path = os.path.join(tmpdir, module + '.json')
566d528ed9Sopenharmony_ci  with open(output_file_map_path, 'w') as output_file_map_file:
576d528ed9Sopenharmony_ci    output_file_map_file.write(json.dumps(output_file_map))
586d528ed9Sopenharmony_ci    output_file_map_file.flush()
596d528ed9Sopenharmony_ci
606d528ed9Sopenharmony_ci  extra_args = []
616d528ed9Sopenharmony_ci  if settings.bridge_header:
626d528ed9Sopenharmony_ci    extra_args.extend([
636d528ed9Sopenharmony_ci        '-import-objc-header',
646d528ed9Sopenharmony_ci        os.path.abspath(settings.bridge_header),
656d528ed9Sopenharmony_ci    ])
666d528ed9Sopenharmony_ci
676d528ed9Sopenharmony_ci  if settings.whole_module_optimization:
686d528ed9Sopenharmony_ci    extra_args.append('-whole-module-optimization')
696d528ed9Sopenharmony_ci
706d528ed9Sopenharmony_ci  if settings.target:
716d528ed9Sopenharmony_ci    extra_args.extend([
726d528ed9Sopenharmony_ci        '-target',
736d528ed9Sopenharmony_ci        settings.target,
746d528ed9Sopenharmony_ci    ])
756d528ed9Sopenharmony_ci
766d528ed9Sopenharmony_ci  if settings.sdk:
776d528ed9Sopenharmony_ci    extra_args.extend([
786d528ed9Sopenharmony_ci        '-sdk',
796d528ed9Sopenharmony_ci        os.path.abspath(settings.sdk),
806d528ed9Sopenharmony_ci    ])
816d528ed9Sopenharmony_ci
826d528ed9Sopenharmony_ci  if settings.include_dirs:
836d528ed9Sopenharmony_ci    for include_dir in settings.include_dirs:
846d528ed9Sopenharmony_ci      extra_args.append('-I' + include_dir)
856d528ed9Sopenharmony_ci
866d528ed9Sopenharmony_ci  process = subprocess.Popen(
876d528ed9Sopenharmony_ci      ['swiftc',
886d528ed9Sopenharmony_ci       '-parse-as-library',
896d528ed9Sopenharmony_ci       '-module-name',
906d528ed9Sopenharmony_ci       module,
916d528ed9Sopenharmony_ci       '-emit-object',
926d528ed9Sopenharmony_ci       '-emit-dependencies',
936d528ed9Sopenharmony_ci       '-emit-module',
946d528ed9Sopenharmony_ci       '-emit-module-path',
956d528ed9Sopenharmony_ci       settings.module_path,
966d528ed9Sopenharmony_ci       '-emit-objc-header',
976d528ed9Sopenharmony_ci       '-emit-objc-header-path',
986d528ed9Sopenharmony_ci       settings.header_path,
996d528ed9Sopenharmony_ci       '-output-file-map',
1006d528ed9Sopenharmony_ci       output_file_map_path,
1016d528ed9Sopenharmony_ci      ] + extra_args + extras + sources,
1026d528ed9Sopenharmony_ci      stdout=subprocess.PIPE, stderr=subprocess.PIPE,
1036d528ed9Sopenharmony_ci      universal_newlines=True)
1046d528ed9Sopenharmony_ci
1056d528ed9Sopenharmony_ci  stdout, stderr = process.communicate()
1066d528ed9Sopenharmony_ci  if process.returncode:
1076d528ed9Sopenharmony_ci    sys.stdout.write(stdout)
1086d528ed9Sopenharmony_ci    sys.stderr.write(stderr)
1096d528ed9Sopenharmony_ci    sys.exit(process.returncode)
1106d528ed9Sopenharmony_ci
1116d528ed9Sopenharmony_ci
1126d528ed9Sopenharmony_ci  depfile_content = collections.OrderedDict()
1136d528ed9Sopenharmony_ci  for key in output_file_map:
1146d528ed9Sopenharmony_ci    for line in open(output_file_map[key]['dependencies']):
1156d528ed9Sopenharmony_ci      output, inputs = line.split(' : ', 2)
1166d528ed9Sopenharmony_ci      _, ext = os.path.splitext(output)
1176d528ed9Sopenharmony_ci      if ext == '.o':
1186d528ed9Sopenharmony_ci        key = output
1196d528ed9Sopenharmony_ci      else:
1206d528ed9Sopenharmony_ci        key = os.path.splitext(settings.module_path)[0] + ext
1216d528ed9Sopenharmony_ci      if key not in depfile_content:
1226d528ed9Sopenharmony_ci        depfile_content[key] = OrderedSet()
1236d528ed9Sopenharmony_ci      for path in inputs.split():
1246d528ed9Sopenharmony_ci        depfile_content[key].add(path)
1256d528ed9Sopenharmony_ci
1266d528ed9Sopenharmony_ci  with open(settings.depfile, 'w') as depfile:
1276d528ed9Sopenharmony_ci    for key in depfile_content:
1286d528ed9Sopenharmony_ci      if not settings.depfile_filter or key in settings.depfile_filter:
1296d528ed9Sopenharmony_ci        inputs = depfile_content[key]
1306d528ed9Sopenharmony_ci        depfile.write('%s : %s\n' % (key, ' '.join(inputs)))
1316d528ed9Sopenharmony_ci
1326d528ed9Sopenharmony_ci
1336d528ed9Sopenharmony_cidef main(args):
1346d528ed9Sopenharmony_ci  parser = argparse.ArgumentParser(add_help=False)
1356d528ed9Sopenharmony_ci  parser.add_argument(
1366d528ed9Sopenharmony_ci      '--module-name',
1376d528ed9Sopenharmony_ci      help='name of the Swift module')
1386d528ed9Sopenharmony_ci  parser.add_argument(
1396d528ed9Sopenharmony_ci      '--include', '-I', action='append', dest='include_dirs',
1406d528ed9Sopenharmony_ci      help='add directory to header search path')
1416d528ed9Sopenharmony_ci  parser.add_argument(
1426d528ed9Sopenharmony_ci      'sources', nargs='+',
1436d528ed9Sopenharmony_ci      help='Swift source file to compile')
1446d528ed9Sopenharmony_ci  parser.add_argument(
1456d528ed9Sopenharmony_ci      '--whole-module-optimization', action='store_true',
1466d528ed9Sopenharmony_ci      help='enable whole module optimization')
1476d528ed9Sopenharmony_ci  parser.add_argument(
1486d528ed9Sopenharmony_ci      '--object-dir', '-o',
1496d528ed9Sopenharmony_ci      help='path to the generated object files directory')
1506d528ed9Sopenharmony_ci  parser.add_argument(
1516d528ed9Sopenharmony_ci      '--module-path', '-m',
1526d528ed9Sopenharmony_ci      help='path to the generated module file')
1536d528ed9Sopenharmony_ci  parser.add_argument(
1546d528ed9Sopenharmony_ci      '--header-path', '-h',
1556d528ed9Sopenharmony_ci      help='path to the generated header file')
1566d528ed9Sopenharmony_ci  parser.add_argument(
1576d528ed9Sopenharmony_ci      '--bridge-header', '-b',
1586d528ed9Sopenharmony_ci      help='path to the Objective-C bridge header')
1596d528ed9Sopenharmony_ci  parser.add_argument(
1606d528ed9Sopenharmony_ci      '--depfile', '-d',
1616d528ed9Sopenharmony_ci      help='path to the generated depfile')
1626d528ed9Sopenharmony_ci  parser.add_argument(
1636d528ed9Sopenharmony_ci      '--depfile-filter', action='append',
1646d528ed9Sopenharmony_ci      help='limit depfile to those files')
1656d528ed9Sopenharmony_ci  parser.add_argument(
1666d528ed9Sopenharmony_ci      '--target', action='store',
1676d528ed9Sopenharmony_ci      help='generate code for the given target <triple>')
1686d528ed9Sopenharmony_ci  parser.add_argument(
1696d528ed9Sopenharmony_ci      '--sdk', action='store',
1706d528ed9Sopenharmony_ci      help='compile against sdk')
1716d528ed9Sopenharmony_ci
1726d528ed9Sopenharmony_ci  parsed, extras = parser.parse_known_args(args)
1736d528ed9Sopenharmony_ci  with tempfile.TemporaryDirectory() as tmpdir:
1746d528ed9Sopenharmony_ci    compile_module(
1756d528ed9Sopenharmony_ci        parsed.module_name,
1766d528ed9Sopenharmony_ci        parsed.sources,
1776d528ed9Sopenharmony_ci        parsed,
1786d528ed9Sopenharmony_ci        extras,
1796d528ed9Sopenharmony_ci        tmpdir)
1806d528ed9Sopenharmony_ci
1816d528ed9Sopenharmony_ci
1826d528ed9Sopenharmony_ciif __name__ == '__main__':
1836d528ed9Sopenharmony_ci  sys.exit(main(sys.argv[1:]))
184