@@ -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