From 0087b40f6de0d3050fde131588b92e4ea175bd12 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Wed, 24 Jan 2018 00:44:14 +0100 Subject: Warn if a symbol with unsatisfied deps is selected Mirrors a warning in the C implementation. Make it a bit more informative and simpler to decode for people who aren't super familiar with Kconfig. The warning is printed when/if the symbol is evaluated, e.g. when writing a .config or C header or accessing Symbol.str/tri_value. It is not printed if the symbol value has already been calculated and is cached and up-to-date, which avoids warning spam. Example: config Y_SYMBOL_1 def_bool y config Y_SYMBOL_2 def_bool y config SELECTED bool depends on !Y_SYMBOL_1 config SELECTING_1 def_bool y select SELECTED # Skipped in warning, because n config SELECTING_2 def_bool n select SELECTED config SELECTING_3 def_bool y select SELECTED if Y_SYMBOL_1 depends on Y_SYMBOL_2 # Defined in multiple locations config SELECTING_3 Generated warning: warning: SELECTED (defined at Kconfig:7) has unsatisfied direct dependencies (!Y_SYMBOL_1), but is currently being selected by the following symbols: SELECTING_3 (value: y, defined at Kconfig:20, Kconfig:26), with direct dependencies "y" (value: y) and select condition Y_SYMBOL_1 && Y_SYMBOL_2 (value: y) SELECTING_1 (value: y, defined at Kconfig:11), with direct dependencies "y" (value: y) Real-world example from test suite: warning: NOT_COHERENT_CACHE (defined at arch/powerpc/platforms/Kconfig.cputype:381) has unsatisfied direct dependencies (4xx || PPC_8xx || E200 || PPC_MPC512x || GAMECUBE_COMMON), but is currently being selected by the following symbols: AMIGAONE (value: y, defined at arch/powerpc/platforms/amigaone/Kconfig:2), with direct dependencies 6xx && BROKEN_ON_SMP (value: y) and select condition 6xx && BROKEN_ON_SMP (value: y) --- kconfiglib.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/kconfiglib.py b/kconfiglib.py index b08fff0..0deda87 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -1942,6 +1942,7 @@ class Kconfig(object): (target, self._make_and(cond, node.dep))) # Modify the dependencies of the selected symbol + # Warning: See _warn_select_unsatisfied_deps() target.rev_dep = \ self._make_or(target.rev_dep, self._make_and(node.item, @@ -2582,6 +2583,9 @@ class Symbol(object): val = max(rev_dep_val, val) self._write_to_conf = True + if not expr_value(self.direct_dep): + self._warn_select_unsatisfied_deps() + # m is promoted to y for (1) bool symbols and (2) symbols with a # weak_rev_dep (from imply) of y if val == 1 and \ @@ -2976,6 +2980,74 @@ class Symbol(object): self.kconfig._warn(self.name + " has no prompt, meaning user " "values have no effect on it") + def _warn_select_unsatisfied_deps(self): + """ + Helper for printing an informative warning when a symbol with + unsatisfied direct dependencies (dependencies from 'depends on', ifs, + and menus) is selected by some other symbol + """ + def location_str(sym): + return "defined at " + \ + ", ".join("{}:{}".format(node.filename, node.linenr) + for node in sym.nodes) + + warn_msg = "{} ({}) has unsatisfied direct dependencies ({}), but " \ + "is currently being selected by the following symbols:" \ + .format(self.name, + location_str(self), + expr_str(self.direct_dep)) + + # Returns a warning string if 'select' is actually selecting us, and + # the empty string otherwise + def check_select(select): + # No 'nonlocal' in Python 2. Just return the string to append to + # warn_msg instead. + select_val = expr_value(select) + if not select_val: + # Only include selects that are not n + return "" + + if isinstance(select, tuple): + # (AND, , ) + selecting_sym = select[1] + else: + # + selecting_sym = select + + msg = "\n{} (value: {}, {}), with direct dependencies {} " \ + "(value: {})" \ + .format(selecting_sym.name, + selecting_sym.str_value, + location_str(selecting_sym), + expr_str(selecting_sym.direct_dep), + TRI_TO_STR[expr_value(selecting_sym.direct_dep)]) + + if isinstance(select, tuple): + msg += " and select condition {} (value: {})" \ + .format(expr_str(select[2]), + TRI_TO_STR[expr_value(select[2])]) + + return msg + + expr = self.rev_dep + while 1: + # This relies on us using the following format for the select + # expression (which is nice in that it preserves the order of the + # selecting symbols): + # + # (OR, (OR, (OR, , ), ), ) + # + # We could do fancier expression processing later if needed. + if isinstance(expr, tuple) and expr[0] == OR: + warn_msg += check_select(expr[2]) + # Go to the next select + expr = expr[1] + else: + warn_msg += check_select(expr) + break + + self.kconfig._warn(warn_msg) + class Choice(object): """ Represents a choice statement: -- cgit v1.2.3