summaryrefslogtreecommitdiff
path: root/util/kconfig_check.py
diff options
context:
space:
mode:
Diffstat (limited to 'util/kconfig_check.py')
-rwxr-xr-xutil/kconfig_check.py116
1 files changed, 102 insertions, 14 deletions
diff --git a/util/kconfig_check.py b/util/kconfig_check.py
index 1b67f0c846..48060f6782 100755
--- a/util/kconfig_check.py
+++ b/util/kconfig_check.py
@@ -2,6 +2,7 @@
# Copyright 2021 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+
"""Kconfig checker
Checks that the .config file provided does not introduce any new ad-hoc CONFIG
@@ -21,6 +22,7 @@ Use the -d flag to select the second format.
"""
import argparse
+import glob
import os
import pathlib
import re
@@ -118,6 +120,9 @@ a corresponding Kconfig option for Zephyr"""
subparsers.add_parser("build", help="Build new list of ad-hoc CONFIGs")
subparsers.add_parser("check", help="Check for new ad-hoc CONFIGs")
+ subparsers.add_parser(
+ "check_undef", help="Verify #undef directives in ec headers"
+ )
return parser.parse_args(argv)
@@ -285,21 +290,37 @@ class KconfigCheck:
List of config and menuconfig options found
"""
if USE_KCONFIGLIB and try_kconfiglib:
- os.environ["srctree"] = srcdir
- kconf = kconfiglib.Kconfig(
- "Kconfig",
- warn=False,
- search_paths=search_paths,
- allow_empty_macros=True,
+ os.environ.update(
+ {
+ "srctree": srcdir,
+ "SOC_DIR": "soc",
+ "ARCH_DIR": "arch",
+ "BOARD_DIR": "boards/*/*",
+ "ARCH": "*",
+ }
)
-
- # 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]
+ kconfigs = []
+ for filename in [
+ "Kconfig",
+ os.path.join(os.environ["ZEPHYR_BASE"], "Kconfig.zephyr"),
+ ]:
+ kconf = kconfiglib.Kconfig(
+ filename,
+ warn=False,
+ search_paths=search_paths,
+ allow_empty_macros=True,
+ )
+
+ symbols = [
+ node.item.name
+ for node in kconf.node_iter()
+ if isinstance(node.item, kconfiglib.Symbol)
+ ]
+
+ if prefix:
+ re_drop_prefix = re.compile(r"^%s" % prefix)
+ symbols = [re_drop_prefix.sub("", name) for name in symbols]
+ kconfigs += symbols
else:
kconfigs = []
# Remove the prefix if present
@@ -479,6 +500,68 @@ update in your CL:
print(f"CONFIG_{config}", file=out)
print(f"New list is in {NEW_ALLOWED_FNAME}")
+ def check_undef(
+ self,
+ srcdir,
+ search_paths,
+ ):
+ """Parse the ec header files and find zephyr Kconfigs that are
+ incorrectly undefined or defined to a default value.
+
+ Args:
+ srcdir: Source directory to scan for Kconfig files
+ 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
+ """
+ kconfigs = set(self.scan_kconfigs(srcdir, "", search_paths))
+
+ if_re = re.compile(r"^\s*#\s*if(ndef CONFIG_ZEPHYR)?")
+ endif_re = re.compile(r"^\s*#\s*endif")
+ modify_config_re = re.compile(r"^\s*#\s*(define|undef)\s+CONFIG_(\S*)")
+ exit_code = 0
+ files_to_check = glob.glob(
+ os.path.join(srcdir, "include/**/*.h"), recursive=True
+ )
+ files_to_check += glob.glob(
+ os.path.join(srcdir, "common/**/public/*.h"), recursive=True
+ )
+ files_to_check += glob.glob(
+ os.path.join(srcdir, "driver/**/*.h"), recursive=True
+ )
+ for filename in files_to_check:
+ with open(filename, "r") as config_h:
+ depth = 0
+ ignore_depth = 0
+ line_count = 0
+ for line in config_h.readlines():
+ line_count += 1
+ line = line.strip("\n")
+ match = if_re.match(line)
+ if match:
+ depth += 1
+ if match[1] or ignore_depth > 0:
+ ignore_depth += 1
+ if endif_re.match(line):
+ if depth > 0:
+ depth -= 1
+ if ignore_depth > 0:
+ ignore_depth -= 1
+ if ignore_depth == 0:
+ match = modify_config_re.match(line)
+ if match:
+ if match[2] in kconfigs:
+ print(
+ f"ERROR: Modifying CONFIG_{match[2]} "
+ "outside of #ifndef CONFIG_ZEPHYR not "
+ f"allowed at {filename}:{line_count}",
+ file=sys.stderr,
+ )
+ exit_code = 1
+ return exit_code
+
def main(argv):
"""Main function"""
@@ -505,6 +588,11 @@ def main(argv):
use_defines=args.use_defines,
search_paths=args.search_path,
)
+ if args.cmd == "check_undef":
+ return checker.check_undef(
+ srcdir=args.srctree,
+ search_paths=args.search_path,
+ )
return 2