kconfiglib: update with 'imply' support

Corresponds to 375506d (File writing nit) from upstream
(https://github.com/ulfalizer/Kconfiglib).

Adds proper 'imply' support and fixes a few minor issues, one of which
previously triggered the following weird warning:

  configs/taurus_defconfig: /tmp/tmpisI45S:6: warning: assignment to SPL_LDSCRIPT changes mode of containing choice from "arch/$(ARCH)/cpu/u-boot-spl.lds" to "y"

The change in 8639f69 (genconfig.py: Print defconfig next to warnings)
was reapplied.

tools/moveconfig.py previously depended on a hack that merged 'select's
with 'imply's. It was modified to look at the union of
Symbol.get_selected_symbols() and Symbol.get_implied_symbols(), which
should give the same behavior.

tools/genboardscfg.py was verified to produce identical board.cfg's
before and after the change.

Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
master
Ulf Magnusson 7 years ago committed by Tom Rini
parent 2719ae3346
commit 4e1102f6de
  1. 333
      tools/buildman/kconfiglib.py
  2. 2
      tools/moveconfig.py

@ -73,6 +73,7 @@ email service. Don't wrestle with internal APIs. Tell me what you need and I
might add it in a safe way as a client API instead."""
import os
import platform
import re
import sys
@ -137,10 +138,8 @@ class Config(object):
# The set of all symbols, indexed by name (a string)
self.syms = {}
# Python 2/3 compatibility hack. This is the only one needed.
if sys.version_info[0] >= 3:
self.syms_iter = self.syms.values
else:
self.syms_iter = self.syms.itervalues
self.syms_iter = self.syms.values if sys.version_info[0] >= 3 else \
self.syms.itervalues
# The set of all defined symbols in the configuration in the order they
# appear in the Kconfig files. This excludes the special symbols n, m,
@ -173,7 +172,7 @@ class Config(object):
self.m = register_special_symbol(TRISTATE, "m", "m")
self.y = register_special_symbol(TRISTATE, "y", "y")
# DEFCONFIG_LIST uses this
register_special_symbol(STRING, "UNAME_RELEASE", os.uname()[2])
register_special_symbol(STRING, "UNAME_RELEASE", platform.uname()[2])
# The symbol with "option defconfig_list" set, containing a list of
# default .config files
@ -183,16 +182,20 @@ class Config(object):
self.arch = os.environ.get("ARCH")
self.srcarch = os.environ.get("SRCARCH")
# If you set CONFIG_ in the environment, Kconfig will prefix all symbols
# with its value when saving the configuration, instead of using the default, "CONFIG_".
self.config_prefix = os.environ.get("CONFIG_")
if self.config_prefix is None:
self.config_prefix = "CONFIG_"
# See Config.__init__(). We need this for get_defconfig_filename().
self.srctree = os.environ.get("srctree")
if self.srctree is None:
self.srctree = "."
self.filename = filename
if base_dir is None:
self.base_dir = self.srctree
else:
self.base_dir = os.path.expandvars(base_dir)
self.base_dir = self.srctree if base_dir is None else \
os.path.expandvars(base_dir)
# The 'mainmenu' text
self.mainmenu_text = None
@ -222,7 +225,8 @@ class Config(object):
self._transform_m = None
# Parse the Kconfig files
self.top_block = self._parse_file(filename, None, None, None)
self.top_block = []
self._parse_file(filename, None, None, None, self.top_block)
# Build Symbol.dep for all symbols
self._build_dep()
@ -405,6 +409,10 @@ class Config(object):
"""
self._warnings = []
# Regular expressions for parsing .config files
_set_re_match = re.compile(r"{}(\w+)=(.*)".format(self.config_prefix)).match
_unset_re_match = re.compile(r"# {}(\w+) is not set".format(self.config_prefix)).match
# Put this first so that a missing file doesn't screw up our state
filename = os.path.expandvars(filename)
line_feeder = _FileFeed(filename)
@ -524,14 +532,12 @@ class Config(object):
with open(filename, "w") as f:
# Write header
if header is not None:
f.write(_comment(header))
f.write("\n")
f.write(_comment(header) + "\n")
# Build and write configuration
conf_strings = []
_make_block_conf(self.top_block, conf_strings.append)
f.write("\n".join(conf_strings))
f.write("\n")
f.write("\n".join(conf_strings) + "\n")
def eval(self, s):
"""Returns the value of the expression 's' -- where 's' is represented
@ -609,16 +615,18 @@ class Config(object):
# Kconfig parsing
#
def _parse_file(self, filename, parent, deps, visible_if_deps, res=None):
"""Parses the Kconfig file 'filename'. Returns a list with the Items in
the file. See _parse_block() for the meaning of the parameters."""
return self._parse_block(_FileFeed(filename), None, parent, deps,
visible_if_deps, res)
def _parse_file(self, filename, parent, deps, visible_if_deps, block):
"""Parses the Kconfig file 'filename'. Appends the Items in the file
(and any file it sources) to the list passed in the 'block' parameter.
See _parse_block() for the meaning of the parameters."""
self._parse_block(_FileFeed(filename), None, parent, deps,
visible_if_deps, block)
def _parse_block(self, line_feeder, end_marker, parent, deps,
visible_if_deps, res=None):
visible_if_deps, block):
"""Parses a block, which is the contents of either a file or an if,
menu, or choice statement. Returns a list with the Items in the block.
menu, or choice statement. Appends the Items to the list passed in the
'block' parameter.
line_feeder: A _FileFeed instance feeding lines from a file. The
Kconfig language is line-based in practice.
@ -634,10 +642,7 @@ class Config(object):
visible_if_deps (default: None): 'visible if' dependencies from
enclosing menus.
res (default: None): The list to add items to. If None, a new list is
created to hold the items."""
block = [] if res is None else res
block: The list to add items to."""
while 1:
# Do we already have a tokenized line that we determined wasn't
@ -656,7 +661,7 @@ class Config(object):
if end_marker is not None:
raise Kconfig_Syntax_Error("Unexpected end of file {0}"
.format(line_feeder.filename))
return block
return
tokens = self._tokenize(line, False, line_feeder.filename,
line_feeder.linenr)
@ -679,14 +684,13 @@ class Config(object):
# choice statements, the choice statement takes precedence.
if not sym.is_defined_ or isinstance(parent, Choice):
sym.parent = parent
sym.is_defined_ = True
self._parse_properties(line_feeder, sym, deps, visible_if_deps)
self.kconfig_syms.append(sym)
block.append(sym)
self._parse_properties(line_feeder, sym, deps, visible_if_deps)
elif t0 == T_SOURCE:
kconfig_file = tokens.get_next()
exp_kconfig_file = self._expand_sym_refs(kconfig_file)
@ -705,7 +709,7 @@ class Config(object):
elif t0 == end_marker:
# We have reached the end of the block
return block
return
elif t0 == T_IF:
# If statements are treated as syntactic sugar for adding
@ -722,38 +726,39 @@ class Config(object):
elif t0 == T_COMMENT:
comment = Comment()
comment.config = self
comment.parent = parent
comment.filename = line_feeder.filename
comment.linenr = line_feeder.linenr
comment.text = tokens.get_next()
self.comments.append(comment)
block.append(comment)
self._parse_properties(line_feeder, comment, deps,
visible_if_deps)
self.comments.append(comment)
block.append(comment)
elif t0 == T_MENU:
menu = Menu()
menu.config = self
menu.parent = parent
menu.filename = line_feeder.filename
menu.linenr = line_feeder.linenr
menu.title = tokens.get_next()
self.menus.append(menu)
block.append(menu)
# Parse properties and contents
self._parse_properties(line_feeder, menu, deps,
visible_if_deps)
menu.block = self._parse_block(line_feeder, T_ENDMENU, menu,
menu.dep_expr,
_make_and(visible_if_deps,
menu.visible_if_expr))
# This needs to go before _parse_block() so that we get the
# proper menu ordering in the case of nested functions
self.menus.append(menu)
# Parse contents and put Items in menu.block
self._parse_block(line_feeder, T_ENDMENU, menu, menu.dep_expr,
_make_and(visible_if_deps,
menu.visible_if_expr),
menu.block)
block.append(menu)
elif t0 == T_CHOICE:
name = tokens.get_next()
@ -775,11 +780,12 @@ class Config(object):
choice.def_locations.append((line_feeder.filename,
line_feeder.linenr))
# Parse properties and contents
self._parse_properties(line_feeder, choice, deps,
visible_if_deps)
choice.block = self._parse_block(line_feeder, T_ENDCHOICE,
choice, deps, visible_if_deps)
# Parse contents and put Items in choice.block
self._parse_block(line_feeder, T_ENDCHOICE, choice, deps,
visible_if_deps, choice.block)
choice._determine_actual_symbols()
@ -819,19 +825,19 @@ class Config(object):
"""Parses '<expr1> if <expr2>' constructs, where the 'if' part is
optional. Returns a tuple containing the parsed expressions, with
None as the second element if the 'if' part is missing."""
val = self._parse_expr(tokens, stmt, line, filename, linenr, False)
if tokens.check(T_IF):
return (val, self._parse_expr(tokens, stmt, line, filename,
linenr))
return (val, None)
return (self._parse_expr(tokens, stmt, line, filename, linenr,
False),
self._parse_expr(tokens, stmt, line, filename, linenr)
if tokens.check(T_IF) else None)
# In case the symbol is defined in multiple locations, we need to
# remember what prompts, defaults, and selects are new for this
# definition, as "depends on" should only apply to the local
# remember what prompts, defaults, selects, and implies are new for
# this definition, as "depends on" should only apply to the local
# definition.
new_prompt = None
new_def_exprs = []
new_selects = []
new_implies = []
# Dependencies from 'depends on' statements
depends_on_expr = None
@ -897,18 +903,27 @@ class Config(object):
line_feeder.unget()
elif t0 == T_SELECT or t0 == T_IMPLY:
elif t0 == T_SELECT:
target = tokens.get_next()
stmt.referenced_syms.add(target)
stmt.selected_syms.add(target)
if tokens.check(T_IF):
new_selects.append((target,
self._parse_expr(tokens, stmt, line,
filename, linenr)))
else:
new_selects.append((target, None))
new_selects.append(
(target,
self._parse_expr(tokens, stmt, line, filename, linenr)
if tokens.check(T_IF) else None))
elif t0 == T_IMPLY:
target = tokens.get_next()
stmt.referenced_syms.add(target)
stmt.implied_syms.add(target)
new_implies.append(
(target,
self._parse_expr(tokens, stmt, line, filename, linenr)
if tokens.check(T_IF) else None))
elif t0 in (T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING):
stmt.type = TOKEN_TO_TYPE[t0]
@ -939,12 +954,10 @@ class Config(object):
stmt.referenced_syms.add(low)
stmt.referenced_syms.add(high)
if tokens.check(T_IF):
stmt.ranges.append((low, high,
self._parse_expr(tokens, stmt, line,
filename, linenr)))
else:
stmt.ranges.append((low, high, None))
stmt.ranges.append(
(low, high,
self._parse_expr(tokens, stmt, line, filename, linenr)
if tokens.check(T_IF) else None))
elif t0 == T_DEF_TRISTATE:
stmt.type = TRISTATE
@ -1051,21 +1064,20 @@ class Config(object):
# Symbol or Choice
# See comment for 'menu_dep'
stmt.menu_dep = depends_on_expr
stmt.menu_dep = _make_and(deps, depends_on_expr)
# Propagate dependencies to prompts
if new_prompt is not None:
# Propagate 'visible if' dependencies from enclosing menus
prompt, cond_expr = new_prompt
cond_expr = _make_and(cond_expr, visible_if_deps)
# Propagate 'depends on' dependencies
new_prompt = (prompt, _make_and(cond_expr, depends_on_expr))
# Propagate 'visible if' dependencies from menus and local
# 'depends on' dependencies
cond_expr = _make_and(_make_and(cond_expr, visible_if_deps),
depends_on_expr)
# Save original
stmt.orig_prompts.append(new_prompt)
stmt.orig_prompts.append((prompt, cond_expr))
# Finalize with dependencies from enclosing menus and ifs
stmt.prompts.append((new_prompt[0],
_make_and(new_prompt[1], deps)))
stmt.prompts.append((prompt, _make_and(cond_expr, deps)))
# Propagate dependencies to defaults
@ -1078,20 +1090,27 @@ class Config(object):
stmt.def_exprs.extend([(val_expr, _make_and(cond_expr, deps))
for val_expr, cond_expr in new_def_exprs])
# Propagate dependencies to selects
# Propagate dependencies to selects and implies
# Only symbols can select
# Only symbols can select and imply
if isinstance(stmt, Symbol):
# Propagate 'depends on' dependencies
new_selects = [(target, _make_and(cond_expr, depends_on_expr))
for target, cond_expr in new_selects]
new_implies = [(target, _make_and(cond_expr, depends_on_expr))
for target, cond_expr in new_implies]
# Save original
stmt.orig_selects.extend(new_selects)
stmt.orig_implies.extend(new_implies)
# Finalize with dependencies from enclosing menus and ifs
for target, cond in new_selects:
target.rev_dep = _make_or(target.rev_dep,
_make_and(stmt,
_make_and(cond, deps)))
target.rev_dep = \
_make_or(target.rev_dep,
_make_and(stmt, _make_and(cond, deps)))
for target, cond in new_implies:
target.weak_rev_dep = \
_make_or(target.weak_rev_dep,
_make_and(stmt, _make_and(cond, deps)))
def _parse_expr(self, feed, cur_item, line, filename=None, linenr=None,
transform_m=True):
@ -1483,7 +1502,8 @@ class Config(object):
# The directly dependent symbols of a symbol are:
# - Any symbols whose prompts, default values, rev_dep (select
# condition), or ranges depend on the symbol
# condition), weak_rev_dep (imply condition) or ranges depend on the
# symbol
# - Any symbols that belong to the same choice statement as the symbol
# (these won't be included in 'dep' as that makes the dependency
# graph unwieldy, but Symbol._get_dependent() will include them)
@ -1497,6 +1517,7 @@ class Config(object):
add_expr_deps(e, sym)
add_expr_deps(sym.rev_dep, sym)
add_expr_deps(sym.weak_rev_dep, sym)
for l, u, e in sym.ranges:
add_expr_deps(l, sym)
@ -1625,20 +1646,16 @@ class Config(object):
else:
prompts_str_rows = []
for prompt, cond_expr in sc.orig_prompts:
if cond_expr is None:
prompts_str_rows.append(' "{0}"'.format(prompt))
else:
prompts_str_rows.append(
' "{0}" if {1}'.format(prompt,
self._expr_val_str(cond_expr)))
prompts_str_rows.append(
' "{0}"'.format(prompt) if cond_expr is None else
' "{0}" if {1}'.format(prompt,
self._expr_val_str(cond_expr)))
prompts_str = "\n".join(prompts_str_rows)
# Build locations string
if not sc.def_locations:
locations_str = "(no locations)"
else:
locations_str = " ".join(["{0}:{1}".format(filename, linenr) for
(filename, linenr) in sc.def_locations])
locations_str = "(no locations)" if not sc.def_locations else \
" ".join(["{0}:{1}".format(filename, linenr) for
filename, linenr in sc.def_locations])
# Build additional-dependencies-from-menus-and-ifs string
additional_deps_str = " " + \
@ -1657,13 +1674,11 @@ class Config(object):
else:
ranges_str_rows = []
for l, u, cond_expr in sc.ranges:
if cond_expr is None:
ranges_str_rows.append(" [{0}, {1}]".format(s(l),
s(u)))
else:
ranges_str_rows.append(" [{0}, {1}] if {2}"
.format(s(l), s(u),
self._expr_val_str(cond_expr)))
ranges_str_rows.append(
" [{0}, {1}]".format(s(l), s(u))
if cond_expr is None else
" [{0}, {1}] if {2}"
.format(s(l), s(u), self._expr_val_str(cond_expr)))
ranges_str = "\n".join(ranges_str_rows)
# Build default values string
@ -1685,14 +1700,24 @@ class Config(object):
else:
selects_str_rows = []
for target, cond_expr in sc.orig_selects:
if cond_expr is None:
selects_str_rows.append(" {0}".format(target.name))
else:
selects_str_rows.append(
" {0} if {1}".format(target.name,
self._expr_val_str(cond_expr)))
selects_str_rows.append(
" {0}".format(target.name) if cond_expr is None else
" {0} if {1}".format(target.name,
self._expr_val_str(cond_expr)))
selects_str = "\n".join(selects_str_rows)
# Build implies string
if not sc.orig_implies:
implies_str = " (no implies)"
else:
implies_str_rows = []
for target, cond_expr in sc.orig_implies:
implies_str_rows.append(
" {0}".format(target.name) if cond_expr is None else
" {0} if {1}".format(target.name,
self._expr_val_str(cond_expr)))
implies_str = "\n".join(implies_str_rows)
res = _lines("Symbol " +
("(no name)" if sc.name is None else sc.name),
"Type : " + TYPENAME[sc.type],
@ -1711,9 +1736,16 @@ class Config(object):
defaults_str,
"Selects:",
selects_str,
"Implies:",
implies_str,
"Reverse (select-related) dependencies:",
" (no reverse dependencies)" if sc.rev_dep == "n"
else " " + self._expr_val_str(sc.rev_dep),
" (no reverse dependencies)"
if sc.rev_dep == "n"
else " " + self._expr_val_str(sc.rev_dep),
"Weak reverse (imply-related) dependencies:",
" (no weak reverse dependencies)"
if sc.weak_rev_dep == "n"
else " " + self._expr_val_str(sc.weak_rev_dep),
"Additional dependencies from enclosing menus "
"and ifs:",
additional_deps_str,
@ -1735,11 +1767,10 @@ class Config(object):
else:
defaults_str_rows = []
for sym, cond_expr in sc.orig_def_exprs:
if cond_expr is None:
defaults_str_rows.append(" {0}".format(sym.name))
else:
defaults_str_rows.append(" {0} if {1}".format(sym.name,
self._expr_val_str(cond_expr)))
defaults_str_rows.append(
" {0}".format(sym.name) if cond_expr is None else
" {0} if {1}".format(sym.name,
self._expr_val_str(cond_expr)))
defaults_str = "\n".join(defaults_str_rows)
# Build contained symbols string
@ -1919,26 +1950,25 @@ class Symbol(Item):
self.write_to_conf = (mode != "n")
if mode == "y":
if choice.get_selection() is self:
new_val = "y"
else:
new_val = "n"
new_val = "y" if choice.get_selection() is self \
else "n"
elif mode == "m":
if self.user_val == "m" or self.user_val == "y":
new_val = "m"
else:
# If the symbol is visible and has a user value, use that.
# Otherwise, look at defaults.
use_defaults = True
# Otherwise, look at defaults and weak reverse dependencies
# (implies).
use_defaults_and_weak_rev_deps = True
if vis != "n":
self.write_to_conf = True
if self.user_val is not None:
new_val = self.config._eval_min(self.user_val, vis)
use_defaults = False
use_defaults_and_weak_rev_deps = False
if use_defaults:
if use_defaults_and_weak_rev_deps:
for val_expr, cond_expr in self.def_exprs:
cond_eval = self.config._eval_expr(cond_expr)
if cond_eval != "n":
@ -1947,14 +1977,25 @@ class Symbol(Item):
cond_eval)
break
weak_rev_dep_val = \
self.config._eval_expr(self.weak_rev_dep)
if weak_rev_dep_val != "n":
self.write_to_conf = True
new_val = self.config._eval_max(new_val,
weak_rev_dep_val)
# Reverse (select-related) dependencies take precedence
rev_dep_val = self.config._eval_expr(self.rev_dep)
if rev_dep_val != "n":
self.write_to_conf = True
new_val = self.config._eval_max(new_val, rev_dep_val)
# Promote "m" to "y" for booleans
if new_val == "m" and self.type == BOOL:
# We need to promote "m" to "y" in two circumstances:
# 1) If our type is boolean
# 2) If our weak_rev_dep (from IMPLY) is "y"
if new_val == "m" and \
(self.type == BOOL or
self.config._eval_expr(self.weak_rev_dep) == "y"):
new_val = "y"
elif self.type == INT or self.type == HEX:
@ -2189,6 +2230,13 @@ class Symbol(Item):
get_referenced_symbols()."""
return self.selected_syms
def get_implied_symbols(self):
"""Returns the set() of all symbols X for which this symbol has an
'imply X' or 'imply X if Y' (regardless of whether Y is satisfied or
not). This is a subset of the symbols returned by
get_referenced_symbols()."""
return self.implied_syms
def set_user_value(self, v):
"""Sets the user value of the symbol.
@ -2304,16 +2352,18 @@ class Symbol(Item):
self.ranges = [] # 'range' properties (for int and hex)
self.help = None # Help text
self.rev_dep = "n" # Reverse (select-related) dependencies
self.weak_rev_dep = "n" # Weak reverse (imply-related) dependencies
self.config = None
self.parent = None
self.user_val = None # Value set by user
# The prompt, default value and select conditions without any
# The prompt, default value, select, and imply conditions without any
# dependencies from menus and ifs propagated to them
self.orig_prompts = []
self.orig_def_exprs = []
self.orig_selects = []
self.orig_implies = []
# Dependencies inherited from containing menus and ifs
self.deps_from_containing = None
@ -2323,13 +2373,15 @@ class Symbol(Item):
# The set of symbols selected by this symbol (see
# get_selected_symbols())
self.selected_syms = set()
# The set of symbols implied by this symbol (see get_implied_symbols())
self.implied_syms = set()
# Like 'referenced_syms', but includes symbols from
# dependencies inherited from enclosing menus and ifs
self.all_referenced_syms = set()
# This records only dependencies specified with 'depends on'. Needed
# when determining actual choice items (hrrrr...). See also
# Choice._determine_actual_symbols().
# This records only dependencies from enclosing ifs and menus together
# with local 'depends on' dependencies. Needed when determining actual
# choice items (hrrrr...). See Choice._determine_actual_symbols().
self.menu_dep = None
# See Symbol.get_ref/def_locations().
@ -2470,18 +2522,17 @@ class Symbol(Item):
return
if self.type == BOOL or self.type == TRISTATE:
if val == "y" or val == "m":
append_fn("CONFIG_{0}={1}".format(self.name, val))
else:
append_fn("# CONFIG_{0} is not set".format(self.name))
append_fn("{0}{1}={2}".format(self.config.config_prefix, self.name, val)
if val == "y" or val == "m" else
"# {0}{1} is not set".format(self.config.config_prefix, self.name))
elif self.type == INT or self.type == HEX:
append_fn("CONFIG_{0}={1}".format(self.name, val))
append_fn("{0}{1}={2}".format(self.config.config_prefix, self.name, val))
elif self.type == STRING:
# Escape \ and "
append_fn('CONFIG_{0}="{1}"'
.format(self.name,
append_fn('{0}{1}="{2}"'
.format(self.config.config_prefix, self.name,
val.replace("\\", "\\\\").replace('"', '\\"')))
else:
@ -2635,7 +2686,7 @@ class Menu(Item):
self.title = None
self.dep_expr = None
self.visible_if_expr = None
self.block = None
self.block = [] # List of contained items
self.config = None
self.parent = None
@ -2852,7 +2903,7 @@ class Choice(Item):
self.prompts = []
self.def_exprs = [] # 'default' properties
self.help = None # Help text
self.block = None # List of contained items
self.block = [] # List of contained items
self.config = None
self.parent = None
@ -3177,7 +3228,13 @@ def _get_visibility(sc):
vis = sc.config._eval_max(vis, cond_expr)
if isinstance(sc, Symbol) and sc.is_choice_sym:
vis = sc.config._eval_min(vis, _get_visibility(sc.parent))
if sc.type == TRISTATE and vis == "m" and \
sc.parent.get_mode() == "y":
# Choice symbols with visibility "m" are not visible if the
# choice has mode "y"
vis = "n"
else:
vis = sc.config._eval_min(vis, _get_visibility(sc.parent))
# Promote "m" to "y" if we're dealing with a non-tristate
if vis == "m" and sc.type != TRISTATE:
@ -3434,7 +3491,7 @@ _get_keyword = \
"prompt": T_PROMPT, "default": T_DEFAULT, "bool": T_BOOL, "boolean": T_BOOL,
"tristate": T_TRISTATE, "int": T_INT, "hex": T_HEX, "def_bool": T_DEF_BOOL,
"def_tristate": T_DEF_TRISTATE, "string": T_STRING, "select": T_SELECT,
"imply": T_IMPLY, "range": T_RANGE, "option": T_OPTION,
"imply" : T_IMPLY, "range": T_RANGE, "option": T_OPTION,
"allnoconfig_y": T_ALLNOCONFIG_Y, "env": T_ENV,
"defconfig_list": T_DEFCONFIG_LIST, "modules": T_MODULES,
"visible": T_VISIBLE}.get
@ -3455,10 +3512,6 @@ _initial_token_re_match = re.compile(r"[^\w]*(\w+)\s*").match
# trailing whitespace as an optimization.
_id_keyword_re_match = re.compile(r"\s*([\w./-]+)\s*").match
# Regular expressions for parsing .config files
_set_re_match = re.compile(r"CONFIG_(\w+)=(.*)").match
_unset_re_match = re.compile(r"# CONFIG_(\w+) is not set").match
# Regular expression for finding $-references to symbols in strings
_sym_ref_re_search = re.compile(r"\$[A-Za-z0-9_]+").search

@ -1472,7 +1472,7 @@ def find_kconfig_rules(kconf, config, imply_config):
"""
sym = kconf.get_symbol(imply_config)
if sym:
for sel in sym.get_selected_symbols():
for sel in sym.get_selected_symbols() | sym.get_implied_symbols():
if sel.get_name() == config:
return sym
return None

Loading…
Cancel
Save