kconfig: Show unsatisfied deps. when assignments don't take
Show which dependencies are unsatisfied when symbols don't get their assigned value. For example, assume that FOO below is assigned with CONFIG_FOO=y. Note that BAR, BAZ, and STR = "hmm" are 'n'. config FOO bool "foo" depends on BAR && BAZ && QAZ && STR = "hmm" config BAR def_bool n config BAZ def_bool n config QAZ def_bool y config STR def_string "zmh" This now prints this warning: warning: FOO (defined at /home/ulf/z/z/Kconfig:10) was assigned the value 'y' but got the value 'n'. Check these unsatisfied dependencies: BAR (=n), BAZ (=n), STR = "hmm" (=n). See ... Fixes: #21888 Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
parent
d3a8fd40b9
commit
ba2f95ab39
1 changed files with 80 additions and 33 deletions
|
@ -5,7 +5,10 @@ import os
|
|||
import sys
|
||||
import textwrap
|
||||
|
||||
from kconfiglib import Kconfig, BOOL, TRISTATE, TRI_TO_STR
|
||||
# Zephyr doesn't use tristate symbols. They're supported here just to make the
|
||||
# script a bit more generic.
|
||||
from kconfiglib import Kconfig, split_expr, expr_value, expr_str, BOOL, \
|
||||
TRISTATE, TRI_TO_STR, AND
|
||||
|
||||
|
||||
# Warnings that won't be turned into errors (but that will still be printed),
|
||||
|
@ -58,18 +61,11 @@ def main():
|
|||
# output and also assigns promptless symbols.
|
||||
check_no_promptless_assign(kconf)
|
||||
|
||||
# Print warnings for symbols whose actual value doesn't match the assigned
|
||||
# value
|
||||
for sym in kconf.unique_defined_syms:
|
||||
# Was the symbol assigned to? Choice symbols are checked separately.
|
||||
if sym.user_value is not None and not sym.choice:
|
||||
check_assigned_sym_value(sym)
|
||||
|
||||
# Print warnings for choices whose actual selection doesn't match the user
|
||||
# selection
|
||||
for choice in kconf.unique_choices:
|
||||
if choice.user_selection:
|
||||
check_assigned_choice_value(choice)
|
||||
# Print warnings for symbols that didn't get the assigned value. Only
|
||||
# do this for handwritten input too, to avoid likely unhelpful warnings
|
||||
# when using an old configuration and updating Kconfig files.
|
||||
check_assigned_sym_values(kconf)
|
||||
check_assigned_choice_values(kconf)
|
||||
|
||||
# Hack: Force all symbols to be evaluated, to catch warnings generated
|
||||
# during evaluation. Wait till the end to write the actual output files, so
|
||||
|
@ -119,27 +115,75 @@ other symbols. \
|
|||
""" + SYM_INFO_HINT).format(sym))
|
||||
|
||||
|
||||
def check_assigned_sym_value(sym):
|
||||
# Verifies that the value assigned to 'sym' "took" (matches the value the
|
||||
# symbol actually got), printing a warning otherwise
|
||||
def check_assigned_sym_values(kconf):
|
||||
# Verifies that the values assigned to symbols "took" (matches the value
|
||||
# the symbols actually got), printing warnings otherwise. Choice symbols
|
||||
# are checked separately, in check_assigned_choice_values().
|
||||
|
||||
for sym in kconf.unique_defined_syms:
|
||||
if sym.choice:
|
||||
continue
|
||||
|
||||
# Tristate values are represented as 0, 1, 2. Having them as
|
||||
# "n", "m", "y" is more convenient here, so convert.
|
||||
if sym.type in (BOOL, TRISTATE):
|
||||
user_value = TRI_TO_STR[sym.user_value]
|
||||
else:
|
||||
user_value = sym.user_value
|
||||
if user_value is None:
|
||||
continue
|
||||
|
||||
if user_value != sym.str_value:
|
||||
warn(("""\
|
||||
{0.name_and_loc} was assigned the value '{1}' but got the value
|
||||
'{0.str_value}'. Check its dependencies. \
|
||||
""" + SYM_INFO_HINT).format(sym, user_value))
|
||||
# Tristate values are represented as 0, 1, 2. Having them as "n", "m",
|
||||
# "y" is more convenient here, so convert.
|
||||
if sym.type in (BOOL, TRISTATE):
|
||||
user_value = TRI_TO_STR[user_value]
|
||||
|
||||
if user_value != sym.str_value:
|
||||
msg = f"{sym.name_and_loc} was assigned the value '{user_value}' " \
|
||||
f"but got the value '{sym.str_value}'. "
|
||||
|
||||
# List any unsatisfied 'depends on' dependencies in the warning
|
||||
mdeps = missing_deps(sym)
|
||||
if mdeps:
|
||||
expr_strs = []
|
||||
for expr in mdeps:
|
||||
estr = expr_str(expr)
|
||||
if isinstance(expr, tuple):
|
||||
# Add () around dependencies that aren't plain symbols.
|
||||
# Gives '(FOO || BAR) (=n)' instead of
|
||||
# 'FOO || BAR (=n)', which might be clearer.
|
||||
estr = f"({estr})"
|
||||
expr_strs.append(f"{estr} (={TRI_TO_STR[expr_value(expr)]})")
|
||||
|
||||
msg += "Check these unsatisfied dependencies: " + \
|
||||
", ".join(expr_strs) + ". "
|
||||
|
||||
warn(msg + SYM_INFO_HINT.format(sym))
|
||||
|
||||
|
||||
def check_assigned_choice_value(choice):
|
||||
# Verifies that the choice symbol that was selected (by setting it to y)
|
||||
# ended up as the selection, printing a warning otherwise.
|
||||
def missing_deps(sym):
|
||||
# check_assigned_sym_values() helper for finding unsatisfied dependencies.
|
||||
#
|
||||
# Given direct dependencies
|
||||
#
|
||||
# depends on <expr> && <expr> && ... && <expr>
|
||||
#
|
||||
# on 'sym' (which can also come from e.g. a surrounding 'if'), returns a
|
||||
# list of all <expr>s with a value less than the value 'sym' was assigned
|
||||
# ("less" instead of "not equal" just to be general and handle tristates,
|
||||
# even though Zephyr doesn't use them).
|
||||
#
|
||||
# For string/int/hex symbols, just looks for <expr> = n.
|
||||
#
|
||||
# Note that <expr>s can be something more complicated than just a symbol,
|
||||
# like 'FOO || BAR' or 'FOO = "string"'.
|
||||
|
||||
deps = split_expr(sym.direct_dep, AND)
|
||||
|
||||
if sym.type in (BOOL, TRISTATE):
|
||||
return [dep for dep in deps if expr_value(dep) < sym.user_value]
|
||||
# string/int/hex
|
||||
return [dep for dep in deps if expr_value(dep) == 0]
|
||||
|
||||
|
||||
def check_assigned_choice_values(kconf):
|
||||
# Verifies that any choice symbols that were selected (by setting them to
|
||||
# y) ended up as the selection, printing warnings otherwise.
|
||||
#
|
||||
# We check choice symbols separately to avoid warnings when two different
|
||||
# choice symbols within the same choice are set to y. This might happen if
|
||||
|
@ -150,8 +194,11 @@ def check_assigned_choice_value(choice):
|
|||
# Without special-casing choices, we'd detect that the first symbol set to
|
||||
# y ended up as n, and print a spurious warning.
|
||||
|
||||
if choice.user_selection is not choice.selection:
|
||||
warn(("""\
|
||||
for choice in kconf.unique_choices:
|
||||
if choice.user_selection and \
|
||||
choice.user_selection is not choice.selection:
|
||||
|
||||
warn(("""\
|
||||
the choice symbol {0.name_and_loc} was selected (set =y), but {1} ended up as
|
||||
the choice selection. \
|
||||
""" + SYM_INFO_HINT).format(
|
||||
|
@ -159,8 +206,8 @@ the choice selection. \
|
|||
choice.selection.name_and_loc if choice.selection else "no symbol"))
|
||||
|
||||
|
||||
# Hint on where to find symbol information. Expects the first argument of
|
||||
# format() to be the symbol.
|
||||
# Hint on where to find symbol information. Used like
|
||||
# SYM_INFO_HINT.format(sym).
|
||||
SYM_INFO_HINT = """\
|
||||
See http://docs.zephyrproject.org/latest/reference/kconfig/CONFIG_{0.name}.html
|
||||
and/or look up {0.name} in the menuconfig/guiconfig interface. The Application
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue