-
Notifications
You must be signed in to change notification settings - Fork 25
/
generate_compdb.py
106 lines (81 loc) · 2.77 KB
/
generate_compdb.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
100
101
102
103
104
105
106
from __future__ import print_function
import argparse
import json
import os
import re
import shlex
import sys
RULE_PATTERN = re.compile(r'^\s*rule\s+(\S+)$')
COMMAND_PATTERN = re.compile(r'^\s*command\s*=\s*(.+)$')
BUILD_PATTERN = re.compile(r'^\s*build\s+.*:\s*(?P<rule>\S+)\s+(?P<file>\S+)')
CAT_PATTERN = re.compile(r'\\\$\$\(\s*cat\s+([^\)]+)\)')
SUBCOMMAND_PATTERN = re.compile(r'\(([^\)]*)\)')
rules = {}
compdb = []
directory = os.path.abspath(os.getcwd())
cat_cache = {}
def cat_expand(match):
file_name = match.group(1).strip()
if file_name in cat_cache:
return cat_cache[file_name]
try:
with open(file_name) as cat_file:
content = cat_file.read().replace('\n', ' ').strip()
except IOError as ex:
print(ex, file=sys.stderr)
content = None
cat_cache[file_name] = content
return content
def parse_command(command, file):
while command:
first_space = command.find(' ', 1)
if (first_space == -1):
first_space = len(command)
if command[0:first_space].endswith('/clang') or command[0:first_space].endswith('/clang++'):
break
command = command[first_space:]
command = command.strip()
if not command:
return False
compdb.append({
'directory': directory,
'command': command,
'file': file
})
return True
parser = argparse.ArgumentParser(description='Generate compile_commands.json for AOSP')
target_product = os.getenv('TARGET_PRODUCT')
if target_product:
parser.add_argument('ninja_file', nargs='?', default='out/build-{}.ninja'.format(target_product))
else:
parser.add_argument('ninja_file')
args = parser.parse_args()
with open(args.ninja_file) as ninja_file:
for line in ninja_file:
rule_match = RULE_PATTERN.match(line)
if rule_match:
rule_name = rule_match.group(1)
continue
command_match = COMMAND_PATTERN.match(line)
if command_match:
rules[rule_name] = command_match.group(1)
continue
build_match = BUILD_PATTERN.match(line)
if not build_match:
continue
command = rules.get(build_match.group('rule'))
if not command:
continue
file = build_match.group('file')
if file.endswith('.S'): # Skip asm files
continue
command = CAT_PATTERN.sub(cat_expand, command)
has_subcommands = False
for subcommand in SUBCOMMAND_PATTERN.finditer(command):
has_subcommands = True
if parse_command(subcommand.group(1), file):
break
if not has_subcommands:
parse_command(command, file)
with open('compile_commands.json', 'w') as compdb_file:
json.dump(compdb, compdb_file, indent=1)