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