Skip to content

Commit f58717e

Browse files
pillo79tejlmand
authored andcommitted
kconfiglib: track origin for symbol values
Track information about what caused a value to be set in the 'origin' property of Symbol. 'imply' and 'select' dependencies do not have a location associated with them, so in those cases the location is a string representation of the dependency expression. For defaults and user values, the location in the Kconfig file is stored. Signed-off-by: Luca Burelli <[email protected]>
1 parent 0276d10 commit f58717e

File tree

1 file changed

+83
-4
lines changed

1 file changed

+83
-4
lines changed

kconfiglib.py

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4075,6 +4075,24 @@ class Symbol(object):
40754075
The visibility of the symbol. One of 0, 1, 2, representing n, m, y. See
40764076
the module documentation for an overview of symbol values and visibility.
40774077
4078+
origin:
4079+
A (kind, loc) tuple containing information about how and where a symbol's
4080+
final value is derived, or None if the symbol is hidden from the
4081+
configuration and can't be given a value.
4082+
4083+
There can be 5 kinds of origins of a symbol's value:
4084+
- "assign", when it was set by the user (via CONFIG_xx=y)
4085+
- "default", when it was set by a 'default' property
4086+
- "select", when it was set by a 'select' statement on another symbol
4087+
- "imply", when it was set by an 'imply' statement on another symbol
4088+
- "unset", when none of the above applied
4089+
The location can be either:
4090+
- None, if the value is unset, has an implicit default, or no location
4091+
was provided in set_value();
4092+
- a (filename, linenr) tuple, if the value was set by a single line;
4093+
- a list of strings describing the conditions that resulted in the
4094+
value being set, in case of reverse dependencies (select and imply).
4095+
40784096
config_string:
40794097
The .config assignment string that would get written out for the symbol
40804098
by Kconfig.write_config(). Returns the empty string if no .config
@@ -4243,6 +4261,7 @@ class Symbol(object):
42434261
"_cached_vis",
42444262
"_dependents",
42454263
"_old_val",
4264+
"_origin",
42464265
"_visited",
42474266
"_was_set",
42484267
"_write_to_conf",
@@ -4303,6 +4322,7 @@ def str_value(self):
43034322
return self.name
43044323

43054324
val = ""
4325+
self._origin = None
43064326
# Warning: See Symbol._rec_invalidate(), and note that this is a hidden
43074327
# function call (property magic)
43084328
vis = self.visibility
@@ -4354,18 +4374,20 @@ def str_value(self):
43544374
# specified in the assignment (with or without "0x", etc.)
43554375
val = self.user_value
43564376
use_defaults = False
4377+
self._origin = _T_CONFIG, self.user_loc
43574378

43584379
if use_defaults:
43594380
# No user value or invalid user value. Look at defaults.
43604381

43614382
# Used to implement the warning below
43624383
has_default = False
43634384

4364-
for sym, cond, _ in self.defaults:
4385+
for sym, cond, loc in self.defaults:
43654386
if expr_value(cond):
43664387
has_default = self._write_to_conf = True
43674388

43684389
val = sym.str_value
4390+
self._origin = _T_DEFAULT, loc
43694391

43704392
if _is_base_n(val, base):
43714393
val_num = int(val, base)
@@ -4375,6 +4397,7 @@ def str_value(self):
43754397
break
43764398
else:
43774399
val_num = 0 # strtoll() on empty string
4400+
self._origin = _T_DEFAULT, None
43784401

43794402
# This clamping procedure runs even if there's no default
43804403
if has_active_range:
@@ -4404,12 +4427,14 @@ def str_value(self):
44044427
if vis and self.user_value is not None:
44054428
# If the symbol is visible and has a user value, use that
44064429
val = self.user_value
4430+
self._origin = _T_CONFIG, self.user_loc
44074431
else:
44084432
# Otherwise, look at defaults
4409-
for sym, cond, _ in self.defaults:
4433+
for sym, cond, loc in self.defaults:
44104434
if expr_value(cond):
44114435
val = sym.str_value
44124436
self._write_to_conf = True
4437+
self._origin = _T_DEFAULT, loc
44134438
break
44144439

44154440
# env_var corresponds to SYMBOL_AUTO in the C implementation, and is
@@ -4455,17 +4480,19 @@ def tri_value(self):
44554480
if vis and self.user_value is not None:
44564481
# If the symbol is visible and has a user value, use that
44574482
val = min(self.user_value, vis)
4483+
self._origin = _T_CONFIG, self.user_loc
44584484

44594485
else:
44604486
# Otherwise, look at defaults and weak reverse dependencies
44614487
# (implies)
44624488

4463-
for default, cond, _ in self.defaults:
4489+
for default, cond, loc in self.defaults:
44644490
dep_val = expr_value(cond)
44654491
if dep_val:
44664492
val = min(expr_value(default), dep_val)
44674493
if val:
44684494
self._write_to_conf = True
4495+
self._origin = _T_DEFAULT, loc
44694496
break
44704497

44714498
# Weak reverse dependencies are only considered if our
@@ -4474,6 +4501,7 @@ def tri_value(self):
44744501
if dep_val and expr_value(self.direct_dep):
44754502
val = max(dep_val, val)
44764503
self._write_to_conf = True
4504+
self._origin = _T_IMPLY, None # expanded later
44774505

44784506
# Reverse (select-related) dependencies take precedence
44794507
dep_val = expr_value(self.rev_dep)
@@ -4483,6 +4511,7 @@ def tri_value(self):
44834511

44844512
val = max(dep_val, val)
44854513
self._write_to_conf = True
4514+
self._origin = _T_SELECT, None # expanded later
44864515

44874516
# m is promoted to y for (1) bool symbols and (2) symbols with a
44884517
# weak_rev_dep (from imply) of y
@@ -4495,6 +4524,8 @@ def tri_value(self):
44954524
# the visibility of choice symbols, so it's sufficient to just
44964525
# check the visibility of the choice symbols themselves.
44974526
val = 2 if self.choice.selection is self else 0
4527+
self._origin = self.choice._origin \
4528+
if self.choice.selection is self else None
44984529

44994530
elif vis and self.user_value:
45004531
# Visible choice symbol in m-mode choice, with set non-0 user value
@@ -4521,6 +4552,38 @@ def visibility(self):
45214552
self._cached_vis = _visibility(self)
45224553
return self._cached_vis
45234554

4555+
@property
4556+
def origin(self):
4557+
"""
4558+
See the class documentation.
4559+
"""
4560+
# Reading 'str_value' computes _write_to_conf and _origin.
4561+
_ = self.str_value
4562+
if not self._write_to_conf:
4563+
return None
4564+
4565+
if not self._origin:
4566+
return (KIND_TO_STR[UNKNOWN], None)
4567+
4568+
kind, loc = self._origin
4569+
4570+
if kind == _T_SELECT:
4571+
# calculate subexpressions that contribute to the value
4572+
loc = [ expr_str(subexpr)
4573+
for subexpr in split_expr(self.rev_dep, OR)
4574+
if expr_value(subexpr) ]
4575+
elif kind == _T_IMPLY:
4576+
# calculate subexpressions that contribute to the value
4577+
loc = [ expr_str(subexpr)
4578+
for subexpr in split_expr(self.weak_rev_dep, OR)
4579+
if expr_value(subexpr) ]
4580+
elif isinstance(loc, tuple) and not os.path.isabs(loc[0]):
4581+
# convert filename to absolute
4582+
fn, ln = loc
4583+
loc = os.path.abspath(os.path.join(self.kconfig.srctree, fn)), ln
4584+
4585+
return (KIND_TO_STR[kind], loc)
4586+
45244587
@property
45254588
def config_string(self):
45264589
"""
@@ -4802,6 +4865,7 @@ def __init__(self):
48024865
self.user_value = \
48034866
self.choice = \
48044867
self.env_var = \
4868+
self._origin = \
48054869
self._cached_str_val = self._cached_tri_val = self._cached_vis = \
48064870
self._cached_assignable = None
48074871

@@ -5160,6 +5224,7 @@ class Choice(object):
51605224
"_cached_selection",
51615225
"_cached_vis",
51625226
"_dependents",
5227+
"_origin",
51635228
"_visited",
51645229
"_was_set",
51655230
"defaults",
@@ -5403,6 +5468,7 @@ def __init__(self):
54035468

54045469
self.name = \
54055470
self.user_value = self.user_selection = \
5471+
self.user_loc = self._origin = \
54065472
self._cached_vis = self._cached_assignable = None
54075473

54085474
self._cached_selection = _NO_CACHED_SELECTION
@@ -5444,27 +5510,31 @@ def _selection(self):
54445510

54455511
# Use the user selection if it's visible
54465512
if self.user_selection and self.user_selection.visibility:
5513+
self._origin = _T_CONFIG, self.user_loc
54475514
return self.user_selection
54485515

54495516
# Otherwise, check if we have a default
54505517
return self._selection_from_defaults()
54515518

54525519
def _selection_from_defaults(self):
54535520
# Check if we have a default
5454-
for sym, cond, _ in self.defaults:
5521+
for sym, cond, loc in self.defaults:
54555522
# The default symbol must be visible too
54565523
if expr_value(cond) and sym.visibility:
5524+
self._origin = _T_DEFAULT, loc
54575525
return sym
54585526

54595527
# Otherwise, pick the first visible symbol, if any
54605528
for sym in self.syms:
54615529
if sym.visibility:
5530+
self._origin = _T_DEFAULT, None
54625531
return sym
54635532

54645533
# Couldn't find a selection
54655534
return None
54665535

54675536
def _invalidate(self):
5537+
self.user_loc = self._origin = \
54685538
self._cached_vis = self._cached_assignable = None
54695539
self._cached_selection = _NO_CACHED_SELECTION
54705540

@@ -7133,6 +7203,15 @@ def _shell_fn(kconf, _, command):
71337203
GREATER_EQUAL,
71347204
})
71357205

7206+
# Origin kinds map
7207+
KIND_TO_STR = {
7208+
UNKNOWN: "unset", # value not set
7209+
_T_CONFIG: "assign", # explicit assignment
7210+
_T_DEFAULT: "default", # 'default' statement
7211+
_T_SELECT: "select", # 'select' statement
7212+
_T_IMPLY: "imply", # 'imply' statement
7213+
}
7214+
71367215
# Helper functions for getting compiled regular expressions, with the needed
71377216
# matching function returned directly as a small optimization.
71387217
#

0 commit comments

Comments
 (0)