From f8a5ebfd20ec47e4f450769d0357b093d859fec8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 18 Sep 2024 08:53:31 +0100 Subject: [PATCH] scripts: ci: check_compliance: Add check for disallowed Kconfigs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a check for Kconfig settings that are disallowed from being used in defconfig files (because it is the complete wrong place for them), with the default entry being PINCTRL Signed-off-by: Jamie McCrae Co-authored-by: Benjamin Cabé --- scripts/ci/check_compliance.py | 79 ++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 8dd4fc5db12..32aecb0d697 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -400,6 +400,7 @@ class KconfigCheck(ComplianceTest): self.check_no_enable_in_boolean_prompt(kconf) self.check_soc_name_sync(kconf) self.check_no_undef_outside_kconfig(kconf) + self.check_disallowed_defconfigs(kconf) def get_modules(self, modules_file, sysbuild_modules_file, settings_file): """ @@ -674,6 +675,84 @@ class KconfigCheck(ComplianceTest): return set(kconf_syms) + def check_disallowed_defconfigs(self, kconf): + """ + Checks that there are no disallowed Kconfigs used in board/SoC defconfig files + """ + # Grep for symbol references. + # + # Example output line for a reference to CONFIG_FOO at line 17 of + # foo/bar.c: + # + # foo/bar.c17#ifdef CONFIG_FOO + # + # 'git grep --only-matching' would get rid of the surrounding context + # ('#ifdef '), but it was added fairly recently (second half of 2018), + # so we extract the references from each line ourselves instead. + # + # The regex uses word boundaries (\b) to isolate the reference, and + # negative lookahead to automatically allowlist the following: + # + # - ##, for token pasting (CONFIG_FOO_##X) + # + # - $, e.g. for CMake variable expansion (CONFIG_FOO_${VAR}) + # + # - @, e.g. for CMakes's configure_file() (CONFIG_FOO_@VAR@) + # + # - {, e.g. for Python scripts ("CONFIG_FOO_{}_BAR".format(...)") + # + # - *, meant for comments like '#endif /* CONFIG_FOO_* */ + + disallowed_symbols = { + "PINCTRL": "Drivers requiring PINCTRL must SELECT it instead.", + } + + disallowed_regex = "(" + "|".join(disallowed_symbols.keys()) + ")$" + + # Warning: Needs to work with both --perl-regexp and the 're' module + regex_boards = r"\bCONFIG_[A-Z0-9_]+\b(?!\s*##|[$@{(.*])" + regex_socs = r"\bconfig\s+[A-Z0-9_]+$" + + grep_stdout_boards = git("grep", "--line-number", "-I", "--null", + "--perl-regexp", regex_boards, "--", ":boards", + cwd=Path(GIT_TOP)) + grep_stdout_socs = git("grep", "--line-number", "-I", "--null", + "--perl-regexp", regex_socs, "--", ":soc", + cwd=Path(GIT_TOP)) + + # Board processing + # splitlines() supports various line terminators + for grep_line in grep_stdout_boards.splitlines(): + path, lineno, line = grep_line.split("\0") + + # Extract symbol references (might be more than one) within the line + for sym_name in re.findall(regex_boards, line): + sym_name = sym_name[len("CONFIG_"):] + # Only check in Kconfig fragment files, references might exist in documentation + if re.match(disallowed_regex, sym_name) and (path[-len("conf"):] == "conf" or + path[-len("defconfig"):] == "defconfig"): + reason = disallowed_symbols.get(sym_name) + self.fmtd_failure("error", "BoardDisallowedKconfigs", path, lineno, desc=f""" +Found disallowed Kconfig symbol in board Kconfig files: CONFIG_{sym_name:35} +{reason} +""") + + # SoCs processing + # splitlines() supports various line terminators + for grep_line in grep_stdout_socs.splitlines(): + path, lineno, line = grep_line.split("\0") + + # Extract symbol references (might be more than one) within the line + for sym_name in re.findall(regex_socs, line): + sym_name = sym_name[len("config"):].strip() + # Only check in Kconfig defconfig files + if re.match(disallowed_regex, sym_name) and "defconfig" in path: + reason = disallowed_symbols.get(sym_name, "Unknown reason") + self.fmtd_failure("error", "SoCDisallowedKconfigs", path, lineno, desc=f""" +Found disallowed Kconfig symbol in SoC Kconfig files: {sym_name:35} +{reason} +""") + def get_defined_syms(self, kconf): # Returns a set() with the names of all defined Kconfig symbols (with no # 'CONFIG_' prefix). This is complicated by samples and tests defining