summaryrefslogtreecommitdiff
path: root/util/kconfig_check.py
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2021-04-30 15:39:47 -0600
committerCommit Bot <commit-bot@chromium.org>2022-01-28 22:02:44 +0000
commitda38ba6b8abe06d2c67505b05fdce6b093cadd07 (patch)
tree039b4e6cb19e73dc4b82536c80774bcc3ad92075 /util/kconfig_check.py
parentda3488be27eb0ce7fedbae2414ef8755f46c6c4e (diff)
downloadchrome-ec-da38ba6b8abe06d2c67505b05fdce6b093cadd07.tar.gz
util: Support using kconfiglib in the CONFIG checker
Update this to use kconfiglib so that it might be easier to maintain. This needs a more correct Kconfig setup in the tests. Also we need to provide the root Kconfig instead of just the directory. Overall this takes about 50% more time, but the total is only about 50ms, so this is not a significant factor in build performance. We must leave it optional, since U-Boot is unlikely to want this extra dependency. BUG=b:181323955 BRANCH=none TEST=python3 util/test_kconfig_check.py Signed-off-by: Simon Glass <sjg@chromium.org> Change-Id: I5cce2ca1fa16a7c334cef15b1f66dd7ede2644bd Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2923227 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Diffstat (limited to 'util/kconfig_check.py')
-rwxr-xr-xutil/kconfig_check.py141
1 files changed, 109 insertions, 32 deletions
diff --git a/util/kconfig_check.py b/util/kconfig_check.py
index b6b9fda8de..e61e604c5a 100755
--- a/util/kconfig_check.py
+++ b/util/kconfig_check.py
@@ -6,6 +6,18 @@
Checks that the .config file provided does not introduce any new ad-hoc CONFIG
options
+
+This tool is also present in U-Boot, so we should keep the two in sync.
+
+The tool supports two formats for the 'configs' file:
+
+ CONFIG_SOMETHING=xx
+
+and
+
+ #define CONFIG_SOMETHING xx
+
+Use the -d flag to select the second format.
"""
import argparse
@@ -13,6 +25,16 @@ import os
import re
import sys
+# Try to use kconfiglib if available, but fall back to a simple recursive grep.
+# This is used by U-Boot in some situations so we keep it to avoid forking this
+# script.
+USE_KCONFIGLIB = False
+try:
+ import kconfiglib
+ USE_KCONFIGLIB = True
+except ImportError:
+ pass
+
def parse_args(argv):
"""Parse the program arguments
@@ -23,8 +45,8 @@ def parse_args(argv):
Returns:
argparse.Namespace object containing the results
"""
- epilog = """Checks that new ad-hoc CONFIG options are not introduced without
-a corresponding Kconfig option for Zephyr"""
+ epilog = '''Checks that new ad-hoc CONFIG options are not introduced without
+a corresponding Kconfig option for Zephyr'''
parser = argparse.ArgumentParser(epilog=epilog)
parser.add_argument('-a', '--allowed', type=str,
@@ -32,12 +54,16 @@ a corresponding Kconfig option for Zephyr"""
help='File containing list of allowed ad-hoc CONFIGs')
parser.add_argument('-c', '--configs', type=str, default='.config',
help='File containing CONFIG options to check')
+ parser.add_argument('-d', '--use-defines', action='store_true',
+ help='Lines in the configs file use #define')
parser.add_argument(
'-D', '--debug', action='store_true',
help='Enabling debugging (provides a full traceback on error)')
+ parser.add_argument('-I', '--search-path', type=str, action='append',
+ help='Search paths to look for Kconfigs')
parser.add_argument('-p', '--prefix', type=str, default='PLATFORM_EC_',
help='Prefix to string from Kconfig options')
- parser.add_argument('-s', '--srctree', type=str, default='.',
+ parser.add_argument('-s', '--srctree', type=str, default='zephyr/',
help='Path to source tree to look for Kconfigs')
subparsers = parser.add_subparsers(dest='cmd', required=True)
@@ -83,20 +109,42 @@ class KconfigCheck:
Returns:
List of new CONFIG options, with the CONFIG_ prefix removed
"""
- return sorted(list(set(configs) - set(kconfigs) - set(allowed)))
+ return sorted(set(configs) - set(kconfigs) - set(allowed))
@classmethod
- def read_configs(cls, configs_file):
+ def read_configs(cls, configs_file, use_defines=False):
"""Read CONFIG options from a file
+ The file consists of a number of lines, each containing a CONFIG
+ option
+
Args:
- configs_file: Filename to read from
+ configs_file: Filename to read from (e.g. u-boot.cfg)
+ use_defines: True if each line of the file starts with #define
Returns:
List of CONFIG_xxx options found in the file, with the 'CONFIG_'
- prefixremoved
+ prefix removed
"""
with open(configs_file, 'r') as inf:
+ configs = re.findall('%sCONFIG_([A-Za-z0-9_]*)%s' %
+ ((use_defines and '#define ' or ''),
+ (use_defines and ' ' or '')),
+ inf.read())
+ return configs
+
+ @classmethod
+ def read_allowed(cls, allowed_file):
+ """Read allowed CONFIG options from a file
+
+ Args:
+ allowed_file: Filename to read from
+
+ Returns:
+ List of CONFIG_xxx options found in the file, with the 'CONFIG_'
+ prefix removed
+ """
+ with open(allowed_file, 'r') as inf:
configs = re.findall('CONFIG_([A-Za-z0-9_]*)', inf.read())
return configs
@@ -121,29 +169,47 @@ class KconfigCheck:
dirs.remove('Kconfig')
return kconfig_files
- def scan_kconfigs(self, srcdir, prefix=''):
+ @classmethod
+ def scan_kconfigs(cls, srcdir, prefix='', search_paths=None,
+ try_kconfiglib=True):
"""Scan a source tree for Kconfig options
Args:
- srcdir: Directory to scan
+ srcdir: Directory to scan (containing top-level Kconfig file)
prefix: Prefix to strip from the name (e.g. 'PLATFORM_EC_')
+ search_paths: List of project paths to search for Kconfig files, in
+ addition to the current directory
+ try_kconfiglib: Use kconfiglib if available
Returns:
- List of config and menuconfig options found,
+ List of config and menuconfig options found
"""
- kconfigs = []
-
- # Remove the prefix if present
- expr = re.compile(r'(config|menuconfig) (%s)?([A-Za-z0-9_]*)\n' %
- prefix)
- for fname in self.find_kconfigs(srcdir):
- with open(fname) as inf:
- found = re.findall(expr, inf.read())
- kconfigs += [name for kctype, _, name in found]
- return kconfigs
+ if USE_KCONFIGLIB and try_kconfiglib:
+ os.environ['srctree'] = srcdir
+ kconf = kconfiglib.Kconfig('Kconfig', warn=False,
+ search_paths=search_paths,
+ allow_empty_macros=True)
+
+ # There is always a MODULES config, since kconfiglib is designed for
+ # linux, but we don't want it
+ kconfigs = [name for name in kconf.syms if name != 'MODULES']
+
+ if prefix:
+ re_drop_prefix = re.compile(r'^%s' % prefix)
+ kconfigs = [re_drop_prefix.sub('', name) for name in kconfigs]
+ else:
+ kconfigs = []
+ # Remove the prefix if present
+ expr = re.compile(r'\n(config|menuconfig) (%s)?([A-Za-z0-9_]*)\n' %
+ prefix)
+ for fname in cls.find_kconfigs(srcdir):
+ with open(fname) as inf:
+ found = re.findall(expr, inf.read())
+ kconfigs += [name for kctype, _, name in found]
+ return sorted(kconfigs)
def find_new_adhoc_configs(self, configs_file, srcdir, allowed_file,
- prefix=''):
+ prefix='', use_defines=False, search_paths=None):
"""Find new ad-hoc configs in the configs_file
Args:
@@ -152,14 +218,18 @@ class KconfigCheck:
allowed_file: File containing allowed CONFIG options
prefix: Prefix to strip from the start of each Kconfig
(e.g. 'PLATFORM_EC_')
+ use_defines: True if each line of the file starts with #define
+ search_paths: List of project paths to search for Kconfig files, in
+ addition to the current directory
"""
- configs = self.read_configs(configs_file)
- kconfigs = self.scan_kconfigs(srcdir, prefix)
- allowed = self.read_configs(allowed_file)
+ configs = self.read_configs(configs_file, use_defines)
+ kconfigs = self.scan_kconfigs(srcdir, prefix, search_paths)
+ allowed = self.read_allowed(allowed_file)
new_adhoc = self.find_new_adhoc(configs, kconfigs, allowed)
return new_adhoc
- def do_check(self, configs_file, srcdir, allowed_file, prefix):
+ def do_check(self, configs_file, srcdir, allowed_file, prefix, use_defines,
+ search_paths):
"""Find new ad-hoc configs in the configs_file
Args:
@@ -168,27 +238,32 @@ class KconfigCheck:
allowed_file: File containing allowed CONFIG options
prefix: Prefix to strip from the start of each Kconfig
(e.g. 'PLATFORM_EC_')
+ use_defines: True if each line of the file starts with #define
+ search_paths: List of project paths to search for Kconfig files, in
+ addition to the current directory
Returns:
Exit code: 0 if OK, 1 if a problem was found
"""
- new_adhoc = self.find_new_adhoc_configs(configs_file, srcdir,
- allowed_file, prefix)
+ new_adhoc = self.find_new_adhoc_configs(
+ configs_file, srcdir, allowed_file, prefix, use_defines,
+ search_paths)
if new_adhoc:
- print("""Error:\tThe EC is in the process of migrating to Zephyr.
+ file_list = '\n'.join(['CONFIG_%s' % name for name in new_adhoc])
+ print(f'''Error:\tThe EC is in the process of migrating to Zephyr.
\tZephyr uses Kconfig for configuration rather than ad-hoc #defines.
\tAny new EC CONFIG options must ALSO be added to Zephyr so that new
\tfunctionality is available in Zephyr also. The following new ad-hoc
\tCONFIG options were detected:
-%s
+{file_list}
Please add these via Kconfig instead. Find a suitable Kconfig
file in zephyr/ and add a 'config' or 'menuconfig' option.
Also see details in http://issuetracker.google.com/181253613
To temporarily disable this, use: ALLOW_CONFIG=1 make ...
-""" % '\n'.join(['CONFIG_%s' % name for name in new_adhoc]), file=sys.stderr)
+''', file=sys.stderr)
return 1
return 0
@@ -200,8 +275,10 @@ def main(argv):
sys.tracebacklimit = 0
checker = KconfigCheck()
if args.cmd == 'check':
- return checker.do_check(args.configs, args.srctree, args.allowed,
- args.prefix)
+ return checker.do_check(
+ configs_file=args.configs, srcdir=args.srctree,
+ allowed_file=args.allowed, prefix=args.prefix,
+ use_defines=args.use_defines, search_paths=args.search_path)
return 2