summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/checkkconfigsymbols.py139
-rwxr-xr-xscripts/checkkconfigsymbols.sh59
2 files changed, 139 insertions, 59 deletions
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py
new file mode 100644
index 000000000000..e9cc689033fe
--- /dev/null
+++ b/scripts/checkkconfigsymbols.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+
+"""Find Kconfig identifiers that are referenced but not defined."""
+
+# (c) 2014 Valentin Rothberg <valentinrothberg@gmail.com>
+# (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
+#
+# Licensed under the terms of the GNU GPL License version 2
+
+
+import os
+import re
+from subprocess import Popen, PIPE, STDOUT
+
+
+# regex expressions
+OPERATORS = r"&|\(|\)|\||\!"
+FEATURE = r"(?:\w*[A-Z0-9]\w*){2,}"
+DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*"
+EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+"
+STMT = r"^\s*(?:if|select|depends\s+on)\s+" + EXPR
+SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")"
+
+# regex objects
+REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
+REGEX_FEATURE = re.compile(r"(" + FEATURE + r")")
+REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE)
+REGEX_KCONFIG_DEF = re.compile(DEF)
+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()
+ referenced_features = dict() # {feature: [files]}
+
+ # 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] == "\n":
+ stdout = stdout[:-1]
+
+ for gitfile in stdout.rsplit("\n"):
+ if ".git" in gitfile or "ChangeLog" in gitfile or \
+ ".log" in gitfile or os.path.isdir(gitfile):
+ continue
+ if REGEX_FILE_KCONFIG.match(gitfile):
+ kconfig_files.append(gitfile)
+ else:
+ # all non-Kconfig files are checked for consistency
+ 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):
+ # filter some false positives
+ if feature == "FOO" or feature == "BAR" or \
+ feature == "FOO_BAR" or feature == "XXX":
+ continue
+ if feature not in defined_features:
+ if feature.endswith("_MODULE"):
+ # avoid false positives for kernel modules
+ if feature[:-len("_MODULE")] in defined_features:
+ continue
+ files = referenced_features.get(feature)
+ print "%s\t%s" % (feature, ", ".join(files))
+
+
+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
+ sfiles = referenced_features.get(feature, set())
+ sfiles.add(sfile)
+ referenced_features[feature] = sfiles
+
+
+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('\n')
+ line = line.split("#")[0] # ignore comments
+
+ 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:
+ # ignore content of help messages
+ pass
+ elif REGEX_KCONFIG_STMT.match(line):
+ features = get_features_in_line(line)
+ # multi-line statements
+ while line.endswith("\\"):
+ i += 1
+ line = lines[i]
+ line = line.strip('\n')
+ 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()
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 @@
-#!/bin/sh
-# Find Kconfig variables used in source code but never defined in Kconfig
-# Copyright (C) 2007, Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
-
-# Tested with dash.
-paths="$@"
-[ -z "$paths" ] && paths=.
-
-# Doing this once at the beginning saves a lot of time, on a cache-hot tree.
-Kconfigs="`find . -name 'Kconfig' -o -name 'Kconfig*[^~]'`"
-
-printf "File list \tundefined symbol used\n"
-find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while read i
-do
- # Output the bare Kconfig variable and the filename; the _MODULE part at
- # the end is not removed here (would need perl an not-hungry regexp for that).
- sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Za-z_]\+\).*!\2 '$i'!p' < $i
-done | \
-# Smart "sort|uniq" implemented in awk and tuned to collect the names of all
-# files which use a given symbol
-awk '{map[$1, count[$1]++] = $2; }
-END {
- for (combIdx in map) {
- split(combIdx, separate, SUBSEP);
- # The value may have been removed.
- if (! ( (separate[1], separate[2]) in map ) )
- continue;
- symb=separate[1];
- printf "%s ", symb;
- #Use gawk extension to delete the names vector
- delete names;
- #Portably delete the names vector
- #split("", names);
- for (i=0; i < count[symb]; i++) {
- names[map[symb, i]] = 1;
- # Unfortunately, we may still encounter symb, i in the
- # outside iteration.
- delete map[symb, i];
- }
- i=0;
- for (name in names) {
- if (i > 0)
- printf ", %s", name;
- else
- printf "%s", name;
- i++;
- }
- printf "\n";
- }
-}' |
-while read symb files; do
- # Remove the _MODULE suffix when checking the variable name. This should
- # be done only on tristate symbols, actually, but Kconfig parsing is
- # beyond the purpose of this script.
- symb_bare=`echo $symb | sed -e 's/_MODULE//'`
- if ! grep -q "\<$symb_bare\>" $Kconfigs; then
- printf "$files: \t$symb\n"
- fi
-done|sort