aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/checkkconfigsymbols.py142
-rwxr-xr-xscripts/checkkconfigsymbols.sh59
2 files changed, 142 insertions, 59 deletions
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py
new file mode 100644
index 000000000000..f9440891d048
--- /dev/null
+++ b/scripts/checkkconfigsymbols.py
@@ -0,0 +1,142 @@
1#!/usr/bin/env python
2
3"""Find Kconfig identifieres that are referenced but not defined."""
4
5# Copyright (C) 2014 Valentin Rothberg <valentinrothberg@gmail.com>
6# Copyright (C) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
7#
8# This program is free software; you can redistribute it and/or modify it
9# under the terms and conditions of the GNU General Public License,
10# version 2, as published by the Free Software Foundation.
11#
12# This program is distributed in the hope it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15# more details.
16
17
18import os
19import re
20from subprocess import Popen, PIPE, STDOUT
21
22# REGEX EXPRESSIONS
23OPERATORS = r"&|\(|\)|\||\!"
24FEATURE = r"\w*[A-Z]{1}\w*"
25CONFIG_DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*"
26EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+"
27STMT = r"^\s*(?:if|select|depends\s+on)\s+" + EXPR
28
29# REGEX OBJECTS
30REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
31REGEX_FEATURE = re.compile(r"(" + FEATURE + r")")
32REGEX_SOURCE_FEATURE = re.compile(r"(?:D|\W|\b)+CONFIG_(" + FEATURE + r")")
33REGEX_KCONFIG_DEF = re.compile(CONFIG_DEF)
34REGEX_KCONFIG_EXPR = re.compile(EXPR)
35REGEX_KCONFIG_STMT = re.compile(STMT)
36REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$")
37REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$")
38
39
40def main():
41 """Main function of this module."""
42 source_files = []
43 kconfig_files = []
44 defined_features = set()
45 referenced_features = dict()
46
47 # use 'git ls-files' to get the worklist
48 pop = Popen("git ls-files", stdout=PIPE, stderr=STDOUT, shell=True)
49 (stdout, _) = pop.communicate() # wait until finished
50 if len(stdout) > 0 and stdout[-1] == "\n":
51 stdout = stdout[:-1]
52
53 for gitfile in stdout.rsplit("\n"):
54 if ".git" in gitfile or "ChangeLog" in gitfile or \
55 os.path.isdir(gitfile):
56 continue
57 if REGEX_FILE_KCONFIG.match(gitfile):
58 kconfig_files.append(gitfile)
59 else:
60 # All non-Kconfig files are checked for consistency
61 source_files.append(gitfile)
62
63 for sfile in source_files:
64 parse_source_file(sfile, referenced_features)
65
66 for kfile in kconfig_files:
67 parse_kconfig_file(kfile, defined_features, referenced_features)
68
69 print "Undefined symbol used\tFile list"
70 for feature in sorted(referenced_features):
71 if feature not in defined_features:
72 if feature.endswith("_MODULE"):
73 # Avoid false positives for kernel modules
74 if feature[:-len("_MODULE")] in defined_features:
75 continue
76 if "FOO" in feature or "BAR" in feature:
77 continue
78 files = referenced_features.get(feature)
79 print "%s:\t%s" % (feature, ", ".join(files))
80
81
82def parse_source_file(sfile, referenced_features):
83 """Parse @sfile for referenced Kconfig features."""
84 lines = []
85 with open(sfile, "r") as stream:
86 lines = stream.readlines()
87
88 for line in lines:
89 if not "CONFIG_" in line:
90 continue
91 features = REGEX_SOURCE_FEATURE.findall(line)
92 for feature in features:
93 if not REGEX_FILTER_FEATURES.search(feature):
94 continue
95 paths = referenced_features.get(feature, set())
96 paths.add(sfile)
97 referenced_features[feature] = paths
98
99
100def get_features_in_line(line):
101 """Return mentioned Kconfig features in @line."""
102 return REGEX_FEATURE.findall(line)
103
104
105def parse_kconfig_file(kfile, defined_features, referenced_features):
106 """Parse @kfile and update feature definitions and references."""
107 lines = []
108 skip = False
109
110 with open(kfile, "r") as stream:
111 lines = stream.readlines()
112
113 for i in range(len(lines)):
114 line = lines[i]
115 line = line.strip('\n')
116 line = line.split("#")[0] # Ignore Kconfig comments
117
118 if REGEX_KCONFIG_DEF.match(line):
119 feature_def = REGEX_KCONFIG_DEF.findall(line)
120 defined_features.add(feature_def[0])
121 skip = False
122 elif REGEX_KCONFIG_HELP.match(line):
123 skip = True
124 elif skip:
125 # Ignore content of help messages
126 pass
127 elif REGEX_KCONFIG_STMT.match(line):
128 features = get_features_in_line(line)
129 # Multi-line statements
130 while line.endswith("\\"):
131 i += 1
132 line = lines[i]
133 line = line.strip('\n')
134 features.extend(get_features_in_line(line))
135 for feature in set(features):
136 paths = referenced_features.get(feature, set())
137 paths.add(kfile)
138 referenced_features[feature] = paths
139
140
141if __name__ == "__main__":
142 main()
diff --git a/scripts/checkkconfigsymbols.sh b/scripts/checkkconfigsymbols.sh
deleted file mode 100755
index ccb3391882d1..000000000000
--- a/scripts/checkkconfigsymbols.sh
+++ /dev/null
@@ -1,59 +0,0 @@
1#!/bin/sh
2# Find Kconfig variables used in source code but never defined in Kconfig
3# Copyright (C) 2007, Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
4
5# Tested with dash.
6paths="$@"
7[ -z "$paths" ] && paths=.
8
9# Doing this once at the beginning saves a lot of time, on a cache-hot tree.
10Kconfigs="`find . -name 'Kconfig' -o -name 'Kconfig*[^~]'`"
11
12printf "File list \tundefined symbol used\n"
13find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while read i
14do
15 # Output the bare Kconfig variable and the filename; the _MODULE part at
16 # the end is not removed here (would need perl an not-hungry regexp for that).
17 sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Za-z_]\+\).*!\2 '$i'!p' < $i
18done | \
19# Smart "sort|uniq" implemented in awk and tuned to collect the names of all
20# files which use a given symbol
21awk '{map[$1, count[$1]++] = $2; }
22END {
23 for (combIdx in map) {
24 split(combIdx, separate, SUBSEP);
25 # The value may have been removed.
26 if (! ( (separate[1], separate[2]) in map ) )
27 continue;
28 symb=separate[1];
29 printf "%s ", symb;
30 #Use gawk extension to delete the names vector
31 delete names;
32 #Portably delete the names vector
33 #split("", names);
34 for (i=0; i < count[symb]; i++) {
35 names[map[symb, i]] = 1;
36 # Unfortunately, we may still encounter symb, i in the
37 # outside iteration.
38 delete map[symb, i];
39 }
40 i=0;
41 for (name in names) {
42 if (i > 0)
43 printf ", %s", name;
44 else
45 printf "%s", name;
46 i++;
47 }
48 printf "\n";
49 }
50}' |
51while read symb files; do
52 # Remove the _MODULE suffix when checking the variable name. This should
53 # be done only on tristate symbols, actually, but Kconfig parsing is
54 # beyond the purpose of this script.
55 symb_bare=`echo $symb | sed -e 's/_MODULE//'`
56 if ! grep -q "\<$symb_bare\>" $Kconfigs; then
57 printf "$files: \t$symb\n"
58 fi
59done|sort