]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - scripts/checkkconfigsymbols.py
Merge branch 'linus' into x86/urgent, to merge dependent patch
[mirror_ubuntu-artful-kernel.git] / scripts / checkkconfigsymbols.py
1 #!/usr/bin/env python
2
3 """Find Kconfig identifiers that are referenced but not defined."""
4
5 # (c) 2014 Valentin Rothberg <valentinrothberg@gmail.com>
6 # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
7 #
8 # Licensed under the terms of the GNU GPL License version 2
9
10
11 import os
12 import re
13 from subprocess import Popen, PIPE, STDOUT
14
15
16 # regex expressions
17 OPERATORS = r"&|\(|\)|\||\!"
18 FEATURE = r"(?:\w*[A-Z0-9]\w*){2,}"
19 DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*"
20 EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+"
21 STMT = r"^\s*(?:if|select|depends\s+on)\s+" + EXPR
22 SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")"
23
24 # regex objects
25 REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
26 REGEX_FEATURE = re.compile(r"(" + FEATURE + r")")
27 REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE)
28 REGEX_KCONFIG_DEF = re.compile(DEF)
29 REGEX_KCONFIG_EXPR = re.compile(EXPR)
30 REGEX_KCONFIG_STMT = re.compile(STMT)
31 REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$")
32 REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$")
33
34
35 def main():
36 """Main function of this module."""
37 source_files = []
38 kconfig_files = []
39 defined_features = set()
40 referenced_features = dict() # {feature: [files]}
41
42 # use 'git ls-files' to get the worklist
43 pop = Popen("git ls-files", stdout=PIPE, stderr=STDOUT, shell=True)
44 (stdout, _) = pop.communicate() # wait until finished
45 if len(stdout) > 0 and stdout[-1] == "\n":
46 stdout = stdout[:-1]
47
48 for gitfile in stdout.rsplit("\n"):
49 if ".git" in gitfile or "ChangeLog" in gitfile or \
50 ".log" in gitfile or os.path.isdir(gitfile):
51 continue
52 if REGEX_FILE_KCONFIG.match(gitfile):
53 kconfig_files.append(gitfile)
54 else:
55 # all non-Kconfig files are checked for consistency
56 source_files.append(gitfile)
57
58 for sfile in source_files:
59 parse_source_file(sfile, referenced_features)
60
61 for kfile in kconfig_files:
62 parse_kconfig_file(kfile, defined_features, referenced_features)
63
64 print "Undefined symbol used\tFile list"
65 for feature in sorted(referenced_features):
66 # filter some false positives
67 if feature == "FOO" or feature == "BAR" or \
68 feature == "FOO_BAR" or feature == "XXX":
69 continue
70 if feature not in defined_features:
71 if feature.endswith("_MODULE"):
72 # avoid false positives for kernel modules
73 if feature[:-len("_MODULE")] in defined_features:
74 continue
75 files = referenced_features.get(feature)
76 print "%s\t%s" % (feature, ", ".join(files))
77
78
79 def parse_source_file(sfile, referenced_features):
80 """Parse @sfile for referenced Kconfig features."""
81 lines = []
82 with open(sfile, "r") as stream:
83 lines = stream.readlines()
84
85 for line in lines:
86 if not "CONFIG_" in line:
87 continue
88 features = REGEX_SOURCE_FEATURE.findall(line)
89 for feature in features:
90 if not REGEX_FILTER_FEATURES.search(feature):
91 continue
92 sfiles = referenced_features.get(feature, set())
93 sfiles.add(sfile)
94 referenced_features[feature] = sfiles
95
96
97 def get_features_in_line(line):
98 """Return mentioned Kconfig features in @line."""
99 return REGEX_FEATURE.findall(line)
100
101
102 def parse_kconfig_file(kfile, defined_features, referenced_features):
103 """Parse @kfile and update feature definitions and references."""
104 lines = []
105 skip = False
106
107 with open(kfile, "r") as stream:
108 lines = stream.readlines()
109
110 for i in range(len(lines)):
111 line = lines[i]
112 line = line.strip('\n')
113 line = line.split("#")[0] # ignore comments
114
115 if REGEX_KCONFIG_DEF.match(line):
116 feature_def = REGEX_KCONFIG_DEF.findall(line)
117 defined_features.add(feature_def[0])
118 skip = False
119 elif REGEX_KCONFIG_HELP.match(line):
120 skip = True
121 elif skip:
122 # ignore content of help messages
123 pass
124 elif REGEX_KCONFIG_STMT.match(line):
125 features = get_features_in_line(line)
126 # multi-line statements
127 while line.endswith("\\"):
128 i += 1
129 line = lines[i]
130 line = line.strip('\n')
131 features.extend(get_features_in_line(line))
132 for feature in set(features):
133 paths = referenced_features.get(feature, set())
134 paths.add(kfile)
135 referenced_features[feature] = paths
136
137
138 if __name__ == "__main__":
139 main()