1#!/usr/bin/env python3
2
3# Converts clang-scan-deps output into response files.
4#   * For modules, arguments in the resulting response file are enough to build a PCM.
5#   * For translation units, the response file needs to be added to the original Clang invocation from compilation
6#     database.
7#
8# Usage:
9#
10#   clang-scan-deps -compilation-database compile_commands.json ... > deps.json
11#   module-deps-to-rsp.py deps.json --module-name=ModuleName > module_name.cc1.rsp
12#   module-deps-to-rsp.py deps.json --tu-index=0 > tu.rsp
13#   clang @module_name.cc1.rsp
14#   clang ... @tu.rsp
15
16import argparse
17import json
18import sys
19
20class ModuleNotFoundError(Exception):
21  def __init__(self, module_name):
22    self.module_name = module_name
23
24class FullDeps:
25  def __init__(self):
26    self.modules = {}
27    self.translation_units = []
28
29def findModule(module_name, full_deps):
30  for m in full_deps.modules.values():
31    if m['name'] == module_name:
32      return m
33  raise ModuleNotFoundError(module_name)
34
35def parseFullDeps(json):
36  ret = FullDeps()
37  for m in json['modules']:
38    ret.modules[m['name'] + '-' + m['context-hash']] = m
39  ret.translation_units = json['translation-units']
40  return ret
41
42def quote(str):
43  return '"' + str.replace("\\", "\\\\") + '"'
44
45def main():
46  parser = argparse.ArgumentParser()
47  parser.add_argument("full_deps_file", help="Path to the full dependencies json file",
48                      type=str)
49  action = parser.add_mutually_exclusive_group(required=True)
50  action.add_argument("--module-name", help="The name of the module to get arguments for",
51                      type=str)
52  action.add_argument("--tu-index", help="The index of the translation unit to get arguments for",
53                      type=int)
54  args = parser.parse_args()
55
56  full_deps = parseFullDeps(json.load(open(args.full_deps_file, 'r')))
57
58  try:
59    cmd = []
60
61    if args.module_name:
62      cmd = findModule(args.module_name, full_deps)['command-line']
63    elif args.tu_index != None:
64      cmd = full_deps.translation_units[args.tu_index]['command-line']
65
66    print(" ".join(map(quote, cmd)))
67  except:
68    print("Unexpected error:", sys.exc_info()[0])
69    raise
70
71if __name__ == '__main__':
72  main()
73