-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate_compilation_database.py
99 lines (82 loc) · 3.19 KB
/
generate_compilation_database.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import analysis_pb2 as analysis
import os
import json
import subprocess
import sys
def make_absolute(path, execution_root):
if path.startswith('external'):
return os.path.abspath(os.path.join(execution_root, path))
else:
return path
def filter_argument(argument, execution_root):
if argument.startswith('/I'):
return filter_argument('-I' + argument[2:], execution_root)
if argument.startswith('/D'):
return filter_argument('-D' + argument[2:], execution_root)
if argument.startswith('/std:'):
return ['-std=' + argument[5:]]
if argument == '/c' or argument == '-c':
return ['-c']
if argument.startswith('/clang:'):
return [argument[7:]]
if argument.startswith('-I'):
return ['-I', make_absolute(argument[2:], execution_root)]
if argument.startswith('-D'):
return ['-D', argument[2:]]
if argument.startswith('-W'):
return [argument]
return []
def parse_arguments(arguments, execution_root):
results = []
for argument in arguments:
if not results:
results.append(argument.replace('clang-cl', 'clang')) # compiler is first arg
results.append('-xc++')
continue
if argument.endswith('.cc') or argument.endswith('.cpp'):
cc_file = make_absolute(argument, execution_root)
results.append(argument)
continue
results += filter_argument(argument, execution_root)
return {
'file': cc_file,
'arguments': results
}
def get_header_command(command_info):
cc_file = command_info['file']
if cc_file.endswith('.cc'):
header_file = cc_file.replace('.cc', '.h')
elif cc_file.endswith('.cpp'):
header_file = cc_file.replace('.cpp', '.hpp')
if not os.path.exists(header_file):
return None
header_command = command_info.copy()
header_command['file'] = header_file
header_command['arguments'] = command_info['arguments'].copy()
try:
file_arg = header_command['arguments'].index(command_info['file'])
header_command['arguments'][file_arg] = header_command['file']
except ValueError:
return None
return header_command
def get_commands(action_graph, execution_root):
results = []
for action in action_graph.actions:
command_info = parse_arguments(action.arguments, execution_root)
command_info['directory'] = os.path.abspath(os.curdir)
results.append(command_info)
header_command = get_header_command(command_info)
if header_command:
results.append(header_command)
return results
def main():
target = sys.argv[1]
execution_root = str(subprocess.check_output(['bazel', 'info', 'execution_root'], encoding='utf-8')).strip()
command = ['bazel', 'aquery', '--output=proto', '--compiler=clang-cl', 'mnemonic("CppCompile", deps(%s))' % target]
result = subprocess.check_output(command)
action_graph = analysis.ActionGraphContainer()
action_graph.ParseFromString(result)
with open('compile_commands.json', mode='w') as output_file:
json.dump(get_commands(action_graph, execution_root), output_file)
if __name__ == '__main__':
main()