summaryrefslogtreecommitdiffstats
path: root/kernel/scripts/checkkconfigsymbols.py
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/scripts/checkkconfigsymbols.py')
-rwxr-xr-xkernel/scripts/checkkconfigsymbols.py86
1 files changed, 73 insertions, 13 deletions
diff --git a/kernel/scripts/checkkconfigsymbols.py b/kernel/scripts/checkkconfigsymbols.py
index 74086a583..2f4b7ffd5 100755
--- a/kernel/scripts/checkkconfigsymbols.py
+++ b/kernel/scripts/checkkconfigsymbols.py
@@ -1,8 +1,8 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
"""Find Kconfig symbols that are referenced but not defined."""
-# (c) 2014-2015 Valentin Rothberg <Valentin.Rothberg@lip6.fr>
+# (c) 2014-2015 Valentin Rothberg <valentinrothberg@gmail.com>
# (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
#
# Licensed under the terms of the GNU GPL License version 2
@@ -20,18 +20,20 @@ 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
+DEFAULT = r"default\s+.*?(?:if\s.+){,1}"
+STMT = r"^\s*(?:if|select|depends\s+on|(?:" + DEFAULT + r"))\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_FEATURE = re.compile(r'(?!\B"[^"]*)' + FEATURE + r'(?![^"]*"\B)')
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]$")
+REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+")
def parse_options():
@@ -58,6 +60,17 @@ def parse_options():
"input format bases on Git log's "
"\'commmit1..commit2\'.")
+ parser.add_option('-f', '--find', dest='find', action='store_true',
+ default=False,
+ help="Find and show commits that may cause symbols to be "
+ "missing. Required to run with --diff.")
+
+ parser.add_option('-i', '--ignore', dest='ignore', action='store',
+ default="",
+ help="Ignore files matching this pattern. Note that "
+ "the pattern needs to be a Python regex. To "
+ "ignore defconfigs, specify -i '.*defconfig'.")
+
parser.add_option('', '--force', dest='force', action='store_true',
default=False,
help="Reset current Git tree even when it's dirty.")
@@ -80,6 +93,15 @@ def parse_options():
"'--force' if you\nwant to ignore this warning and "
"continue.")
+ if opts.commit:
+ opts.find = False
+
+ if opts.ignore:
+ try:
+ re.match(opts.ignore, "this/is/just/a/test.c")
+ except:
+ sys.exit("Please specify a valid Python regex.")
+
return opts
@@ -105,34 +127,54 @@ def main():
# get undefined items before the commit
execute("git reset --hard %s" % commit_a)
- undefined_a = check_symbols()
+ undefined_a = check_symbols(opts.ignore)
# get undefined items for the commit
execute("git reset --hard %s" % commit_b)
- undefined_b = check_symbols()
+ undefined_b = check_symbols(opts.ignore)
# report cases that are present for the commit but not before
for feature in sorted(undefined_b):
# feature has not been undefined before
if not feature in undefined_a:
files = sorted(undefined_b.get(feature))
- print "%s\t%s" % (feature, ", ".join(files))
+ print "%s\t%s" % (yel(feature), ", ".join(files))
+ if opts.find:
+ commits = find_commits(feature, opts.diff)
+ print red(commits)
# check if there are new files that reference the undefined feature
else:
files = sorted(undefined_b.get(feature) -
undefined_a.get(feature))
if files:
- print "%s\t%s" % (feature, ", ".join(files))
+ print "%s\t%s" % (yel(feature), ", ".join(files))
+ if opts.find:
+ commits = find_commits(feature, opts.diff)
+ print red(commits)
# reset to head
execute("git reset --hard %s" % head)
# default to check the entire tree
else:
- undefined = check_symbols()
+ undefined = check_symbols(opts.ignore)
for feature in sorted(undefined):
files = sorted(undefined.get(feature))
- print "%s\t%s" % (feature, ", ".join(files))
+ print "%s\t%s" % (yel(feature), ", ".join(files))
+
+
+def yel(string):
+ """
+ Color %string yellow.
+ """
+ return "\033[33m%s\033[0m" % string
+
+
+def red(string):
+ """
+ Color %string red.
+ """
+ return "\033[31m%s\033[0m" % string
def execute(cmd):
@@ -144,6 +186,13 @@ def execute(cmd):
return stdout
+def find_commits(symbol, diff):
+ """Find commits changing %symbol in the given range of %diff."""
+ commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s"
+ % (symbol, diff))
+ return commits
+
+
def tree_is_dirty():
"""Return true if the current working tree is dirty (i.e., if any file has
been added, deleted, modified, renamed or copied but not committed)."""
@@ -160,9 +209,10 @@ def get_head():
return stdout.strip('\n')
-def check_symbols():
+def check_symbols(ignore):
"""Find undefined Kconfig symbols and return a dict with the symbol as key
- and a list of referencing files as value."""
+ and a list of referencing files as value. Files matching %ignore are not
+ checked for undefined symbols."""
source_files = []
kconfig_files = []
defined_features = set()
@@ -185,10 +235,17 @@ def check_symbols():
source_files.append(gitfile)
for sfile in source_files:
+ if ignore and re.match(ignore, sfile):
+ # do not check files matching %ignore
+ continue
parse_source_file(sfile, referenced_features)
for kfile in kconfig_files:
- parse_kconfig_file(kfile, defined_features, referenced_features)
+ if ignore and re.match(ignore, kfile):
+ # do not collect references for files matching %ignore
+ parse_kconfig_file(kfile, defined_features, dict())
+ else:
+ parse_kconfig_file(kfile, defined_features, referenced_features)
undefined = {} # {feature: [files]}
for feature in sorted(referenced_features):
@@ -259,6 +316,9 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
line = line.strip('\n')
features.extend(get_features_in_line(line))
for feature in set(features):
+ if REGEX_NUMERIC.match(feature):
+ # ignore numeric values
+ continue
paths = referenced_features.get(feature, set())
paths.add(kfile)
referenced_features[feature] = paths