-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathcheck_ifdefs.py
116 lines (87 loc) · 3.06 KB
/
check_ifdefs.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
107
108
109
110
111
112
113
114
115
116
#!/bin/env python
import re
import sys
from pathlib import Path
def find_source_files():
p = Path("./")
files = list(p.glob(r"**/*.cpp"))
files += list(p.glob(r"**/*.H"))
return files
def check_file(filename):
# this is a general check to see if we should further examine a line
if_general_re = re.compile(r"^(?:#if|#elif)", re.IGNORECASE|re.DOTALL)
# this checks something of the form "#ifdef NAME"
ifdef_re = re.compile(r"^#if[n]*def\s+([a-z_0-9]+)", re.IGNORECASE|re.DOTALL)
# this checks something of the form
# #if (NAME == X)
if_re = re.compile(r"^(?:#if|#elif)\s+[\(]?([a-z_0-9]+)", re.IGNORECASE|re.DOTALL)
# together these check something of the form
# #if defined(NAME1) || !defined(NAME2)
if_defined_re1 = re.compile(r"^(?:#if|#elif)\s+[!]?(?:defined)", re.IGNORECASE|re.DOTALL)
if_defined_re2 = re.compile(r"[!]?(?:defined)\s*[\(]?([a-z_0-9]+)[\)]?", re.IGNORECASE|re.DOTALL)
ierr = 0
defines = []
with open(filename) as cf:
for line in cf:
if if_general_re.search(line):
# check each of the patterns
if if_defined_re1.search(line):
g = if_defined_re2.findall(line)
defines += g
continue
if g := ifdef_re.search(line):
defines.append(g.group(1))
continue
if g := if_re.search(line):
defines.append(g.group(1))
continue
# if we made it here, then we didn't handle things
ierr = 1
print(f"unhandled, file: {filename} | {line}")
return ierr, set(defines)
if __name__ == "__main__":
try:
good_defines_file = sys.argv[1]
except IndexError:
good_defines_file = None
# read in the list of good defines
good_defines = []
if good_defines_file:
with open(good_defines_file) as gd:
for line in gd:
good_defines.append(line.strip())
all_defines = []
total_errors = 0
for f in find_source_files():
if "tmp_build_dir" in f.parts:
# skip generated files
continue
if f.parts[:2] == ("util", "autodiff"):
# skip third-party autodiff files
continue
ierr, defines = check_file(f)
all_defines += defines
total_errors += ierr
# remove any header guards
defines = []
for d in all_defines:
if d.endswith("_H") or d.endswith("_H_"):
continue
if len(d) == 1 and d.isdigit():
continue
defines.append(d)
defines = sorted(set(defines))
print("found defines:")
for d in defines:
print(d)
# now check to make sure that all the defines we found are okay
invalid = []
for d in defines:
if d not in good_defines:
invalid.append(d)
if invalid or total_errors > 0:
if invalid:
print("\ninvalid defines:")
for bad in invalid:
print(bad)
sys.exit(1)