Merge branch 'bugfix/update_menuconfig' into 'master'
Update kconfiglib from v12.14.0 to v13.3.2 See merge request espressif/esp-idf!6816
This commit is contained in:
commit
af382a1b8e
2 changed files with 324 additions and 208 deletions
|
@ -554,7 +554,7 @@ from glob import iglob
|
||||||
from os.path import dirname, exists, expandvars, islink, join, realpath
|
from os.path import dirname, exists, expandvars, islink, join, realpath
|
||||||
|
|
||||||
|
|
||||||
VERSION = (12, 14, 0)
|
VERSION = (13, 3, 2)
|
||||||
|
|
||||||
|
|
||||||
# File layout:
|
# File layout:
|
||||||
|
@ -773,8 +773,8 @@ class Kconfig(object):
|
||||||
See Kconfig.load_config() as well.
|
See Kconfig.load_config() as well.
|
||||||
|
|
||||||
srctree:
|
srctree:
|
||||||
The value of the $srctree environment variable when the configuration was
|
The value the $srctree environment variable had when the Kconfig instance
|
||||||
loaded, or the empty string if $srctree wasn't set. This gives nice
|
was created, or the empty string if $srctree wasn't set. This gives nice
|
||||||
behavior with os.path.join(), which treats "" as the current directory,
|
behavior with os.path.join(), which treats "" as the current directory,
|
||||||
without adding "./".
|
without adding "./".
|
||||||
|
|
||||||
|
@ -789,13 +789,22 @@ class Kconfig(object):
|
||||||
if multiple configurations are loaded with different values for $srctree.
|
if multiple configurations are loaded with different values for $srctree.
|
||||||
|
|
||||||
config_prefix:
|
config_prefix:
|
||||||
The value of the $CONFIG_ environment variable when the configuration was
|
The value the CONFIG_ environment variable had when the Kconfig instance
|
||||||
loaded. This is the prefix used (and expected) on symbol names in .config
|
was created, or "CONFIG_" if CONFIG_ wasn't set. This is the prefix used
|
||||||
files and C headers. Defaults to "CONFIG_". Used in the same way in the C
|
(and expected) on symbol names in .config files and C headers. Used in
|
||||||
tools.
|
the same way in the C tools.
|
||||||
|
|
||||||
Like for srctree, only the value of $CONFIG_ when the configuration is
|
config_header:
|
||||||
loaded matters.
|
The value the KCONFIG_CONFIG_HEADER environment variable had when the
|
||||||
|
Kconfig instance was created, or the empty string if
|
||||||
|
KCONFIG_CONFIG_HEADER wasn't set. This string is inserted verbatim at the
|
||||||
|
beginning of configuration files. See write_config().
|
||||||
|
|
||||||
|
header_header:
|
||||||
|
The value the KCONFIG_AUTOHEADER_HEADER environment variable had when the
|
||||||
|
Kconfig instance was created, or the empty string if
|
||||||
|
KCONFIG_AUTOHEADER_HEADER wasn't set. This string is inserted verbatim at
|
||||||
|
the beginning of header files. See write_autoconf().
|
||||||
|
|
||||||
filename/linenr:
|
filename/linenr:
|
||||||
The current parsing location, for use in Python preprocessor functions.
|
The current parsing location, for use in Python preprocessor functions.
|
||||||
|
@ -810,11 +819,13 @@ class Kconfig(object):
|
||||||
"_warn_assign_no_prompt",
|
"_warn_assign_no_prompt",
|
||||||
"choices",
|
"choices",
|
||||||
"comments",
|
"comments",
|
||||||
|
"config_header",
|
||||||
"config_prefix",
|
"config_prefix",
|
||||||
"const_syms",
|
"const_syms",
|
||||||
"defconfig_list",
|
"defconfig_list",
|
||||||
"defined_syms",
|
"defined_syms",
|
||||||
"env_vars",
|
"env_vars",
|
||||||
|
"header_header",
|
||||||
"kconfig_filenames",
|
"kconfig_filenames",
|
||||||
"m",
|
"m",
|
||||||
"menus",
|
"menus",
|
||||||
|
@ -943,6 +954,9 @@ class Kconfig(object):
|
||||||
self._unset_match = _re_match(r"# {}([^ ]+) is not set".format(
|
self._unset_match = _re_match(r"# {}([^ ]+) is not set".format(
|
||||||
self.config_prefix))
|
self.config_prefix))
|
||||||
|
|
||||||
|
self.config_header = os.getenv("KCONFIG_CONFIG_HEADER", "")
|
||||||
|
self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "")
|
||||||
|
|
||||||
self.syms = {}
|
self.syms = {}
|
||||||
self.const_syms = {}
|
self.const_syms = {}
|
||||||
self.defined_syms = []
|
self.defined_syms = []
|
||||||
|
@ -1245,7 +1259,7 @@ class Kconfig(object):
|
||||||
self._warn("'{}' is not a valid value for the {} "
|
self._warn("'{}' is not a valid value for the {} "
|
||||||
"symbol {}. Assignment ignored."
|
"symbol {}. Assignment ignored."
|
||||||
.format(val, TYPE_TO_STR[sym.orig_type],
|
.format(val, TYPE_TO_STR[sym.orig_type],
|
||||||
_name_and_loc(sym)),
|
sym.name_and_loc),
|
||||||
filename, linenr)
|
filename, linenr)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1272,7 +1286,7 @@ class Kconfig(object):
|
||||||
if not match:
|
if not match:
|
||||||
self._warn("malformed string literal in "
|
self._warn("malformed string literal in "
|
||||||
"assignment to {}. Assignment ignored."
|
"assignment to {}. Assignment ignored."
|
||||||
.format(_name_and_loc(sym)),
|
.format(sym.name_and_loc),
|
||||||
filename, linenr)
|
filename, linenr)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1341,7 +1355,7 @@ class Kconfig(object):
|
||||||
user_val = sym.user_value
|
user_val = sym.user_value
|
||||||
|
|
||||||
msg = '{} set more than once. Old value "{}", new value "{}".'.format(
|
msg = '{} set more than once. Old value "{}", new value "{}".'.format(
|
||||||
_name_and_loc(sym), user_val, new_val)
|
sym.name_and_loc, user_val, new_val)
|
||||||
|
|
||||||
if user_val == new_val:
|
if user_val == new_val:
|
||||||
if self.warn_assign_redun:
|
if self.warn_assign_redun:
|
||||||
|
@ -1349,8 +1363,7 @@ class Kconfig(object):
|
||||||
elif self.warn_assign_override:
|
elif self.warn_assign_override:
|
||||||
self._warn(msg, filename, linenr)
|
self._warn(msg, filename, linenr)
|
||||||
|
|
||||||
def write_autoconf(self, filename,
|
def write_autoconf(self, filename=None, header=None):
|
||||||
header="/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"):
|
|
||||||
r"""
|
r"""
|
||||||
Writes out symbol values as a C header file, matching the format used
|
Writes out symbol values as a C header file, matching the format used
|
||||||
by include/generated/autoconf.h in the kernel.
|
by include/generated/autoconf.h in the kernel.
|
||||||
|
@ -1364,22 +1377,37 @@ class Kconfig(object):
|
||||||
like the modification time and possibly triggering redundant work in
|
like the modification time and possibly triggering redundant work in
|
||||||
build tools.
|
build tools.
|
||||||
|
|
||||||
filename:
|
filename (default: None):
|
||||||
Self-explanatory.
|
Path to write header to.
|
||||||
|
|
||||||
header (default: "/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"):
|
If None (the default), the path in the environment variable
|
||||||
Text that will be inserted verbatim at the beginning of the file. You
|
KCONFIG_AUTOHEADER is used if set, and "include/generated/autoconf.h"
|
||||||
would usually want it enclosed in '/* */' to make it a C comment,
|
otherwise. This is compatible with the C tools.
|
||||||
and include a final terminating newline.
|
|
||||||
|
header (default: None):
|
||||||
|
Text inserted verbatim at the beginning of the file. You would
|
||||||
|
usually want it enclosed in '/* */' to make it a C comment, and
|
||||||
|
include a trailing newline.
|
||||||
|
|
||||||
|
If None (the default), the value of the environment variable
|
||||||
|
KCONFIG_AUTOHEADER_HEADER had when the Kconfig instance was created
|
||||||
|
will be used if it was set, and no header otherwise. See the
|
||||||
|
Kconfig.header_header attribute.
|
||||||
"""
|
"""
|
||||||
|
if filename is None:
|
||||||
|
filename = os.getenv("KCONFIG_AUTOHEADER",
|
||||||
|
"include/generated/autoconf.h")
|
||||||
|
|
||||||
self._write_if_changed(filename, self._autoconf_contents(header))
|
self._write_if_changed(filename, self._autoconf_contents(header))
|
||||||
|
|
||||||
def _autoconf_contents(self, header):
|
def _autoconf_contents(self, header):
|
||||||
# write_autoconf() helper. Returns the contents to write as a string,
|
# write_autoconf() helper. Returns the contents to write as a string,
|
||||||
# with 'header' at the beginning.
|
# with 'header' or KCONFIG_AUTOHEADER_HEADER at the beginning.
|
||||||
|
|
||||||
# "".join()ed later
|
if header is None:
|
||||||
chunks = [header]
|
header = self.header_header
|
||||||
|
|
||||||
|
chunks = [header] # "".join()ed later
|
||||||
add = chunks.append
|
add = chunks.append
|
||||||
|
|
||||||
for sym in self.unique_defined_syms:
|
for sym in self.unique_defined_syms:
|
||||||
|
@ -1415,9 +1443,8 @@ class Kconfig(object):
|
||||||
|
|
||||||
return "".join(chunks)
|
return "".join(chunks)
|
||||||
|
|
||||||
def write_config(self, filename=None,
|
def write_config(self, filename=None, header=None, save_old=True,
|
||||||
header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n",
|
verbose=None):
|
||||||
save_old=True, verbose=None):
|
|
||||||
r"""
|
r"""
|
||||||
Writes out symbol values in the .config format. The format matches the
|
Writes out symbol values in the .config format. The format matches the
|
||||||
C implementation, including ordering.
|
C implementation, including ordering.
|
||||||
|
@ -1439,16 +1466,21 @@ class Kconfig(object):
|
||||||
(OSError/IOError). KconfigError is never raised here.
|
(OSError/IOError). KconfigError is never raised here.
|
||||||
|
|
||||||
filename (default: None):
|
filename (default: None):
|
||||||
Filename to save configuration to (a string).
|
Path to write configuration to (a string).
|
||||||
|
|
||||||
If None (the default), the filename in the environment variable
|
If None (the default), the path in the environment variable
|
||||||
KCONFIG_CONFIG is used if set, and ".config" otherwise. See
|
KCONFIG_CONFIG is used if set, and ".config" otherwise. See
|
||||||
standard_config_filename().
|
standard_config_filename().
|
||||||
|
|
||||||
header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"):
|
header (default: None):
|
||||||
Text that will be inserted verbatim at the beginning of the file. You
|
Text inserted verbatim at the beginning of the file. You would
|
||||||
would usually want each line to start with '#' to make it a comment,
|
usually want each line to start with '#' to make it a comment, and
|
||||||
and include a final terminating newline.
|
include a trailing newline.
|
||||||
|
|
||||||
|
if None (the default), the value of the environment variable
|
||||||
|
KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will
|
||||||
|
be used if it was set, and no header otherwise. See the
|
||||||
|
Kconfig.config_header attribute.
|
||||||
|
|
||||||
save_old (default: True):
|
save_old (default: True):
|
||||||
If True and <filename> already exists, a copy of it will be saved to
|
If True and <filename> already exists, a copy of it will be saved to
|
||||||
|
@ -1493,7 +1525,7 @@ class Kconfig(object):
|
||||||
|
|
||||||
def _config_contents(self, header):
|
def _config_contents(self, header):
|
||||||
# write_config() helper. Returns the contents to write as a string,
|
# write_config() helper. Returns the contents to write as a string,
|
||||||
# with 'header' at the beginning.
|
# with 'header' or KCONFIG_CONFIG_HEADER at the beginning.
|
||||||
#
|
#
|
||||||
# More memory friendly would be to 'yield' the strings and
|
# More memory friendly would be to 'yield' the strings and
|
||||||
# "".join(_config_contents()), but it was a bit slower on my system.
|
# "".join(_config_contents()), but it was a bit slower on my system.
|
||||||
|
@ -1505,13 +1537,15 @@ class Kconfig(object):
|
||||||
for sym in self.unique_defined_syms:
|
for sym in self.unique_defined_syms:
|
||||||
sym._visited = False
|
sym._visited = False
|
||||||
|
|
||||||
|
if header is None:
|
||||||
|
header = self.config_header
|
||||||
|
|
||||||
|
chunks = [header] # "".join()ed later
|
||||||
|
add = chunks.append
|
||||||
|
|
||||||
# Did we just print an '# end of ...' comment?
|
# Did we just print an '# end of ...' comment?
|
||||||
after_end_comment = False
|
after_end_comment = False
|
||||||
|
|
||||||
# "".join()ed later
|
|
||||||
chunks = [header]
|
|
||||||
add = chunks.append
|
|
||||||
|
|
||||||
node = self.top_node
|
node = self.top_node
|
||||||
while 1:
|
while 1:
|
||||||
# Jump to the next node with an iterative tree walk
|
# Jump to the next node with an iterative tree walk
|
||||||
|
@ -1564,8 +1598,7 @@ class Kconfig(object):
|
||||||
add("\n#\n# {}\n#\n".format(node.prompt[0]))
|
add("\n#\n# {}\n#\n".format(node.prompt[0]))
|
||||||
after_end_comment = False
|
after_end_comment = False
|
||||||
|
|
||||||
def write_min_config(self, filename,
|
def write_min_config(self, filename, header=None):
|
||||||
header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"):
|
|
||||||
"""
|
"""
|
||||||
Writes out a "minimal" configuration file, omitting symbols whose value
|
Writes out a "minimal" configuration file, omitting symbols whose value
|
||||||
matches their default value. The format matches the one produced by
|
matches their default value. The format matches the one produced by
|
||||||
|
@ -1581,12 +1614,17 @@ class Kconfig(object):
|
||||||
(OSError/IOError). KconfigError is never raised here.
|
(OSError/IOError). KconfigError is never raised here.
|
||||||
|
|
||||||
filename:
|
filename:
|
||||||
Self-explanatory.
|
Path to write minimal configuration to.
|
||||||
|
|
||||||
header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"):
|
header (default: None):
|
||||||
Text that will be inserted verbatim at the beginning of the file. You
|
Text inserted verbatim at the beginning of the file. You would
|
||||||
would usually want each line to start with '#' to make it a comment,
|
usually want each line to start with '#' to make it a comment, and
|
||||||
and include a final terminating newline.
|
include a final terminating newline.
|
||||||
|
|
||||||
|
if None (the default), the value of the environment variable
|
||||||
|
KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will
|
||||||
|
be used if it was set, and no header otherwise. See the
|
||||||
|
Kconfig.config_header attribute.
|
||||||
|
|
||||||
Returns a string with a message saying which file got saved. This is
|
Returns a string with a message saying which file got saved. This is
|
||||||
meant to reduce boilerplate in tools, which can do e.g.
|
meant to reduce boilerplate in tools, which can do e.g.
|
||||||
|
@ -1603,9 +1641,12 @@ class Kconfig(object):
|
||||||
|
|
||||||
def _min_config_contents(self, header):
|
def _min_config_contents(self, header):
|
||||||
# write_min_config() helper. Returns the contents to write as a string,
|
# write_min_config() helper. Returns the contents to write as a string,
|
||||||
# with 'header' at the beginning.
|
# with 'header' or KCONFIG_CONFIG_HEADER at the beginning.
|
||||||
|
|
||||||
chunks = [header]
|
if header is None:
|
||||||
|
header = self.config_header
|
||||||
|
|
||||||
|
chunks = [header] # "".join()ed later
|
||||||
add = chunks.append
|
add = chunks.append
|
||||||
|
|
||||||
for sym in self.unique_defined_syms:
|
for sym in self.unique_defined_syms:
|
||||||
|
@ -2603,10 +2644,9 @@ class Kconfig(object):
|
||||||
while 1:
|
while 1:
|
||||||
match = _name_special_search(s, i)
|
match = _name_special_search(s, i)
|
||||||
|
|
||||||
if match.group() == "$(":
|
if match.group() != "$(":
|
||||||
s, i = self._expand_macro(s, match.start(), ())
|
|
||||||
else:
|
|
||||||
return (s, match.start())
|
return (s, match.start())
|
||||||
|
s, i = self._expand_macro(s, match.start(), ())
|
||||||
|
|
||||||
def _expand_str(self, s, i):
|
def _expand_str(self, s, i):
|
||||||
# Expands a quoted string starting at index 'i' in 's'. Handles both
|
# Expands a quoted string starting at index 'i' in 's'. Handles both
|
||||||
|
@ -2649,14 +2689,12 @@ class Kconfig(object):
|
||||||
# Returns the expanded 's' (including the part before the macro) and
|
# Returns the expanded 's' (including the part before the macro) and
|
||||||
# the index of the first character after the expanded macro in 's'.
|
# the index of the first character after the expanded macro in 's'.
|
||||||
|
|
||||||
start = i
|
res = s[:i]
|
||||||
i += 2 # Skip over "$("
|
i += 2 # Skip over "$("
|
||||||
|
|
||||||
# Start of current macro argument
|
arg_start = i # Start of current macro argument
|
||||||
arg_start = i
|
new_args = [] # Arguments of this macro call
|
||||||
|
nesting = 0 # Current parentheses nesting level
|
||||||
# Arguments of this macro call
|
|
||||||
new_args = []
|
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
match = _macro_special_search(s, i)
|
match = _macro_special_search(s, i)
|
||||||
|
@ -2664,32 +2702,42 @@ class Kconfig(object):
|
||||||
self._parse_error("missing end parenthesis in macro expansion")
|
self._parse_error("missing end parenthesis in macro expansion")
|
||||||
|
|
||||||
|
|
||||||
if match.group() == ")":
|
if match.group() == "(":
|
||||||
|
nesting += 1
|
||||||
|
i = match.end()
|
||||||
|
|
||||||
|
elif match.group() == ")":
|
||||||
|
if nesting:
|
||||||
|
nesting -= 1
|
||||||
|
i = match.end()
|
||||||
|
continue
|
||||||
|
|
||||||
# Found the end of the macro
|
# Found the end of the macro
|
||||||
|
|
||||||
new_args.append(s[arg_start:match.start()])
|
new_args.append(s[arg_start:match.start()])
|
||||||
|
|
||||||
prefix = s[:start]
|
|
||||||
|
|
||||||
# $(1) is replaced by the first argument to the function, etc.,
|
# $(1) is replaced by the first argument to the function, etc.,
|
||||||
# provided at least that many arguments were passed
|
# provided at least that many arguments were passed
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Does the macro look like an integer, with a corresponding
|
# Does the macro look like an integer, with a corresponding
|
||||||
# argument? If so, expand it to the value of the argument.
|
# argument? If so, expand it to the value of the argument.
|
||||||
prefix += args[int(new_args[0])]
|
res += args[int(new_args[0])]
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
# Regular variables are just functions without arguments,
|
# Regular variables are just functions without arguments,
|
||||||
# and also go through the function value path
|
# and also go through the function value path
|
||||||
prefix += self._fn_val(new_args)
|
res += self._fn_val(new_args)
|
||||||
|
|
||||||
return (prefix + s[match.end():],
|
return (res + s[match.end():], len(res))
|
||||||
len(prefix))
|
|
||||||
|
|
||||||
elif match.group() == ",":
|
elif match.group() == ",":
|
||||||
|
i = match.end()
|
||||||
|
if nesting:
|
||||||
|
continue
|
||||||
|
|
||||||
# Found the end of a macro argument
|
# Found the end of a macro argument
|
||||||
new_args.append(s[arg_start:match.start()])
|
new_args.append(s[arg_start:match.start()])
|
||||||
arg_start = i = match.end()
|
arg_start = i
|
||||||
|
|
||||||
else: # match.group() == "$("
|
else: # match.group() == "$("
|
||||||
# A nested macro call within the macro
|
# A nested macro call within the macro
|
||||||
|
@ -2836,7 +2884,7 @@ class Kconfig(object):
|
||||||
|
|
||||||
if node.is_menuconfig and not node.prompt:
|
if node.is_menuconfig and not node.prompt:
|
||||||
self._warn("the menuconfig symbol {} has no prompt"
|
self._warn("the menuconfig symbol {} has no prompt"
|
||||||
.format(_name_and_loc(sym)))
|
.format(sym.name_and_loc))
|
||||||
|
|
||||||
# Equivalent to
|
# Equivalent to
|
||||||
#
|
#
|
||||||
|
@ -3173,8 +3221,7 @@ class Kconfig(object):
|
||||||
# UNKNOWN is falsy
|
# UNKNOWN is falsy
|
||||||
if node.item.orig_type and node.item.orig_type is not new_type:
|
if node.item.orig_type and node.item.orig_type is not new_type:
|
||||||
self._warn("{} defined with multiple types, {} will be used"
|
self._warn("{} defined with multiple types, {} will be used"
|
||||||
.format(_name_and_loc(node.item),
|
.format(node.item.name_and_loc, TYPE_TO_STR[new_type]))
|
||||||
TYPE_TO_STR[new_type]))
|
|
||||||
|
|
||||||
node.item.orig_type = new_type
|
node.item.orig_type = new_type
|
||||||
|
|
||||||
|
@ -3184,7 +3231,7 @@ class Kconfig(object):
|
||||||
# multiple times
|
# multiple times
|
||||||
|
|
||||||
if node.prompt:
|
if node.prompt:
|
||||||
self._warn(_name_and_loc(node.item) +
|
self._warn(node.item.name_and_loc +
|
||||||
" defined with multiple prompts in single location")
|
" defined with multiple prompts in single location")
|
||||||
|
|
||||||
prompt = self._tokens[1]
|
prompt = self._tokens[1]
|
||||||
|
@ -3194,7 +3241,7 @@ class Kconfig(object):
|
||||||
self._parse_error("expected prompt string")
|
self._parse_error("expected prompt string")
|
||||||
|
|
||||||
if prompt != prompt.strip():
|
if prompt != prompt.strip():
|
||||||
self._warn(_name_and_loc(node.item) +
|
self._warn(node.item.name_and_loc +
|
||||||
" has leading or trailing whitespace in its prompt")
|
" has leading or trailing whitespace in its prompt")
|
||||||
|
|
||||||
# This avoid issues for e.g. reStructuredText documentation, where
|
# This avoid issues for e.g. reStructuredText documentation, where
|
||||||
|
@ -3205,7 +3252,7 @@ class Kconfig(object):
|
||||||
|
|
||||||
def _parse_help(self, node):
|
def _parse_help(self, node):
|
||||||
if node.help is not None:
|
if node.help is not None:
|
||||||
self._warn(_name_and_loc(node.item) + " defined with more than "
|
self._warn(node.item.name_and_loc + " defined with more than "
|
||||||
"one help text -- only the last one will be used")
|
"one help text -- only the last one will be used")
|
||||||
|
|
||||||
# Micro-optimization. This code is pretty hot.
|
# Micro-optimization. This code is pretty hot.
|
||||||
|
@ -3261,7 +3308,7 @@ class Kconfig(object):
|
||||||
self._line_after_help(line)
|
self._line_after_help(line)
|
||||||
|
|
||||||
def _empty_help(self, node, line):
|
def _empty_help(self, node, line):
|
||||||
self._warn(_name_and_loc(node.item) +
|
self._warn(node.item.name_and_loc +
|
||||||
" has 'help' but empty help text")
|
" has 'help' but empty help text")
|
||||||
node.help = ""
|
node.help = ""
|
||||||
if line:
|
if line:
|
||||||
|
@ -3641,26 +3688,26 @@ class Kconfig(object):
|
||||||
if target_sym.orig_type not in _BOOL_TRISTATE_UNKNOWN:
|
if target_sym.orig_type not in _BOOL_TRISTATE_UNKNOWN:
|
||||||
self._warn("{} selects the {} symbol {}, which is not "
|
self._warn("{} selects the {} symbol {}, which is not "
|
||||||
"bool or tristate"
|
"bool or tristate"
|
||||||
.format(_name_and_loc(sym),
|
.format(sym.name_and_loc,
|
||||||
TYPE_TO_STR[target_sym.orig_type],
|
TYPE_TO_STR[target_sym.orig_type],
|
||||||
_name_and_loc(target_sym)))
|
target_sym.name_and_loc))
|
||||||
|
|
||||||
for target_sym, _ in sym.implies:
|
for target_sym, _ in sym.implies:
|
||||||
if target_sym.orig_type not in _BOOL_TRISTATE_UNKNOWN:
|
if target_sym.orig_type not in _BOOL_TRISTATE_UNKNOWN:
|
||||||
self._warn("{} implies the {} symbol {}, which is not "
|
self._warn("{} implies the {} symbol {}, which is not "
|
||||||
"bool or tristate"
|
"bool or tristate"
|
||||||
.format(_name_and_loc(sym),
|
.format(sym.name_and_loc,
|
||||||
TYPE_TO_STR[target_sym.orig_type],
|
TYPE_TO_STR[target_sym.orig_type],
|
||||||
_name_and_loc(target_sym)))
|
target_sym.name_and_loc))
|
||||||
|
|
||||||
elif sym.orig_type: # STRING/INT/HEX
|
elif sym.orig_type: # STRING/INT/HEX
|
||||||
for default, _ in sym.defaults:
|
for default, _ in sym.defaults:
|
||||||
if default.__class__ is not Symbol:
|
if default.__class__ is not Symbol:
|
||||||
raise KconfigError(
|
raise KconfigError(
|
||||||
"the {} symbol {} has a malformed default {} -- expected "
|
"the {} symbol {} has a malformed default {} -- "
|
||||||
"a single symbol"
|
"expected a single symbol"
|
||||||
.format(TYPE_TO_STR[sym.orig_type], _name_and_loc(sym),
|
.format(TYPE_TO_STR[sym.orig_type],
|
||||||
expr_str(default)))
|
sym.name_and_loc, expr_str(default)))
|
||||||
|
|
||||||
if sym.orig_type is STRING:
|
if sym.orig_type is STRING:
|
||||||
if not default.is_constant and not default.nodes and \
|
if not default.is_constant and not default.nodes and \
|
||||||
|
@ -3671,22 +3718,22 @@ class Kconfig(object):
|
||||||
# (and no symbol named 'foo' exists).
|
# (and no symbol named 'foo' exists).
|
||||||
self._warn("style: quotes recommended around "
|
self._warn("style: quotes recommended around "
|
||||||
"default value for string symbol "
|
"default value for string symbol "
|
||||||
+ _name_and_loc(sym))
|
+ sym.name_and_loc)
|
||||||
|
|
||||||
elif not num_ok(default, sym.orig_type): # INT/HEX
|
elif not num_ok(default, sym.orig_type): # INT/HEX
|
||||||
self._warn("the {0} symbol {1} has a non-{0} default {2}"
|
self._warn("the {0} symbol {1} has a non-{0} default {2}"
|
||||||
.format(TYPE_TO_STR[sym.orig_type],
|
.format(TYPE_TO_STR[sym.orig_type],
|
||||||
_name_and_loc(sym),
|
sym.name_and_loc,
|
||||||
_name_and_loc(default)))
|
default.name_and_loc))
|
||||||
|
|
||||||
if sym.selects or sym.implies:
|
if sym.selects or sym.implies:
|
||||||
self._warn("the {} symbol {} has selects or implies"
|
self._warn("the {} symbol {} has selects or implies"
|
||||||
.format(TYPE_TO_STR[sym.orig_type],
|
.format(TYPE_TO_STR[sym.orig_type],
|
||||||
_name_and_loc(sym)))
|
sym.name_and_loc))
|
||||||
|
|
||||||
else: # UNKNOWN
|
else: # UNKNOWN
|
||||||
self._warn("{} defined without a type"
|
self._warn("{} defined without a type"
|
||||||
.format(_name_and_loc(sym)))
|
.format(sym.name_and_loc))
|
||||||
|
|
||||||
|
|
||||||
if sym.ranges:
|
if sym.ranges:
|
||||||
|
@ -3694,7 +3741,7 @@ class Kconfig(object):
|
||||||
self._warn(
|
self._warn(
|
||||||
"the {} symbol {} has ranges, but is not int or hex"
|
"the {} symbol {} has ranges, but is not int or hex"
|
||||||
.format(TYPE_TO_STR[sym.orig_type],
|
.format(TYPE_TO_STR[sym.orig_type],
|
||||||
_name_and_loc(sym)))
|
sym.name_and_loc))
|
||||||
else:
|
else:
|
||||||
for low, high, _ in sym.ranges:
|
for low, high, _ in sym.ranges:
|
||||||
if not num_ok(low, sym.orig_type) or \
|
if not num_ok(low, sym.orig_type) or \
|
||||||
|
@ -3703,9 +3750,9 @@ class Kconfig(object):
|
||||||
self._warn("the {0} symbol {1} has a non-{0} "
|
self._warn("the {0} symbol {1} has a non-{0} "
|
||||||
"range [{2}, {3}]"
|
"range [{2}, {3}]"
|
||||||
.format(TYPE_TO_STR[sym.orig_type],
|
.format(TYPE_TO_STR[sym.orig_type],
|
||||||
_name_and_loc(sym),
|
sym.name_and_loc,
|
||||||
_name_and_loc(low),
|
low.name_and_loc,
|
||||||
_name_and_loc(high)))
|
high.name_and_loc))
|
||||||
|
|
||||||
def _check_choice_sanity(self):
|
def _check_choice_sanity(self):
|
||||||
# Checks various choice properties that are handiest to check after
|
# Checks various choice properties that are handiest to check after
|
||||||
|
@ -3714,43 +3761,43 @@ class Kconfig(object):
|
||||||
def warn_select_imply(sym, expr, expr_type):
|
def warn_select_imply(sym, expr, expr_type):
|
||||||
msg = "the choice symbol {} is {} by the following symbols, but " \
|
msg = "the choice symbol {} is {} by the following symbols, but " \
|
||||||
"select/imply has no effect on choice symbols" \
|
"select/imply has no effect on choice symbols" \
|
||||||
.format(_name_and_loc(sym), expr_type)
|
.format(sym.name_and_loc, expr_type)
|
||||||
|
|
||||||
# si = select/imply
|
# si = select/imply
|
||||||
for si in split_expr(expr, OR):
|
for si in split_expr(expr, OR):
|
||||||
msg += "\n - " + _name_and_loc(split_expr(si, AND)[0])
|
msg += "\n - " + split_expr(si, AND)[0].name_and_loc
|
||||||
|
|
||||||
self._warn(msg)
|
self._warn(msg)
|
||||||
|
|
||||||
for choice in self.unique_choices:
|
for choice in self.unique_choices:
|
||||||
if choice.orig_type not in _BOOL_TRISTATE:
|
if choice.orig_type not in _BOOL_TRISTATE:
|
||||||
self._warn("{} defined with type {}"
|
self._warn("{} defined with type {}"
|
||||||
.format(_name_and_loc(choice),
|
.format(choice.name_and_loc,
|
||||||
TYPE_TO_STR[choice.orig_type]))
|
TYPE_TO_STR[choice.orig_type]))
|
||||||
|
|
||||||
for node in choice.nodes:
|
for node in choice.nodes:
|
||||||
if node.prompt:
|
if node.prompt:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self._warn(_name_and_loc(choice) + " defined without a prompt")
|
self._warn(choice.name_and_loc + " defined without a prompt")
|
||||||
|
|
||||||
for default, _ in choice.defaults:
|
for default, _ in choice.defaults:
|
||||||
if default.__class__ is not Symbol:
|
if default.__class__ is not Symbol:
|
||||||
raise KconfigError(
|
raise KconfigError(
|
||||||
"{} has a malformed default {}"
|
"{} has a malformed default {}"
|
||||||
.format(_name_and_loc(choice), expr_str(default)))
|
.format(choice.name_and_loc, expr_str(default)))
|
||||||
|
|
||||||
if default.choice is not choice:
|
if default.choice is not choice:
|
||||||
self._warn("the default selection {} of {} is not "
|
self._warn("the default selection {} of {} is not "
|
||||||
"contained in the choice"
|
"contained in the choice"
|
||||||
.format(_name_and_loc(default),
|
.format(default.name_and_loc,
|
||||||
_name_and_loc(choice)))
|
choice.name_and_loc))
|
||||||
|
|
||||||
for sym in choice.syms:
|
for sym in choice.syms:
|
||||||
if sym.defaults:
|
if sym.defaults:
|
||||||
self._warn("default on the choice symbol {} will have "
|
self._warn("default on the choice symbol {} will have "
|
||||||
"no effect, as defaults do not affect choice "
|
"no effect, as defaults do not affect choice "
|
||||||
"symbols".format(_name_and_loc(sym)))
|
"symbols".format(sym.name_and_loc))
|
||||||
|
|
||||||
if sym.rev_dep is not sym.kconfig.n:
|
if sym.rev_dep is not sym.kconfig.n:
|
||||||
warn_select_imply(sym, sym.rev_dep, "selected")
|
warn_select_imply(sym, sym.rev_dep, "selected")
|
||||||
|
@ -3762,12 +3809,12 @@ class Kconfig(object):
|
||||||
if node.parent.item is choice:
|
if node.parent.item is choice:
|
||||||
if not node.prompt:
|
if not node.prompt:
|
||||||
self._warn("the choice symbol {} has no prompt"
|
self._warn("the choice symbol {} has no prompt"
|
||||||
.format(_name_and_loc(sym)))
|
.format(sym.name_and_loc))
|
||||||
|
|
||||||
elif node.prompt:
|
elif node.prompt:
|
||||||
self._warn("the choice symbol {} is defined with a "
|
self._warn("the choice symbol {} is defined with a "
|
||||||
"prompt outside the choice"
|
"prompt outside the choice"
|
||||||
.format(_name_and_loc(sym)))
|
.format(sym.name_and_loc))
|
||||||
|
|
||||||
def _parse_error(self, msg):
|
def _parse_error(self, msg):
|
||||||
raise KconfigError("{}couldn't parse '{}': {}".format(
|
raise KconfigError("{}couldn't parse '{}': {}".format(
|
||||||
|
@ -3907,6 +3954,13 @@ class Symbol(object):
|
||||||
The type as given in the Kconfig file, without any magic applied. Used
|
The type as given in the Kconfig file, without any magic applied. Used
|
||||||
when printing the symbol.
|
when printing the symbol.
|
||||||
|
|
||||||
|
tri_value:
|
||||||
|
The tristate value of the symbol as an integer. One of 0, 1, 2,
|
||||||
|
representing n, m, y. Always 0 (n) for non-bool/tristate symbols.
|
||||||
|
|
||||||
|
This is the symbol value that's used outside of relation expressions
|
||||||
|
(A, !A, A && B, A || B).
|
||||||
|
|
||||||
str_value:
|
str_value:
|
||||||
The value of the symbol as a string. Gives the value for string/int/hex
|
The value of the symbol as a string. Gives the value for string/int/hex
|
||||||
symbols. For bool/tristate symbols, gives "n", "m", or "y".
|
symbols. For bool/tristate symbols, gives "n", "m", or "y".
|
||||||
|
@ -3914,17 +3968,20 @@ class Symbol(object):
|
||||||
This is the symbol value that's used in relational expressions
|
This is the symbol value that's used in relational expressions
|
||||||
(A = B, A != B, etc.)
|
(A = B, A != B, etc.)
|
||||||
|
|
||||||
Gotcha: For int/hex symbols, the exact format of the value must often be
|
Gotcha: For int/hex symbols, the exact format of the value is often
|
||||||
preserved (e.g., when writing a .config file), hence why you can't get it
|
preserved (e.g. when writing a .config file), hence why you can't get it
|
||||||
directly as an int. Do int(int_sym.str_value) or
|
directly as an int. Do int(int_sym.str_value) or
|
||||||
int(hex_sym.str_value, 16) to get the integer value.
|
int(hex_sym.str_value, 16) to get the integer value.
|
||||||
|
|
||||||
tri_value:
|
user_value:
|
||||||
The tristate value of the symbol as an integer. One of 0, 1, 2,
|
The user value of the symbol. None if no user value has been assigned
|
||||||
representing n, m, y. Always 0 (n) for non-bool/tristate symbols.
|
(via Kconfig.load_config() or Symbol.set_value()).
|
||||||
|
|
||||||
This is the symbol value that's used outside of relation expressions
|
Holds 0, 1, or 2 for bool/tristate symbols, and a string for the other
|
||||||
(A, !A, A && B, A || B).
|
symbol types.
|
||||||
|
|
||||||
|
WARNING: Do not assign directly to this. It will break things. Use
|
||||||
|
Symbol.set_value().
|
||||||
|
|
||||||
assignable:
|
assignable:
|
||||||
A tuple containing the tristate user values that can currently be
|
A tuple containing the tristate user values that can currently be
|
||||||
|
@ -3965,16 +4022,6 @@ class Symbol(object):
|
||||||
The visibility of the symbol. One of 0, 1, 2, representing n, m, y. See
|
The visibility of the symbol. One of 0, 1, 2, representing n, m, y. See
|
||||||
the module documentation for an overview of symbol values and visibility.
|
the module documentation for an overview of symbol values and visibility.
|
||||||
|
|
||||||
user_value:
|
|
||||||
The user value of the symbol. None if no user value has been assigned
|
|
||||||
(via Kconfig.load_config() or Symbol.set_value()).
|
|
||||||
|
|
||||||
Holds 0, 1, or 2 for bool/tristate symbols, and a string for the other
|
|
||||||
symbol types.
|
|
||||||
|
|
||||||
WARNING: Do not assign directly to this. It will break things. Use
|
|
||||||
Symbol.set_value().
|
|
||||||
|
|
||||||
config_string:
|
config_string:
|
||||||
The .config assignment string that would get written out for the symbol
|
The .config assignment string that would get written out for the symbol
|
||||||
by Kconfig.write_config(). Returns the empty string if no .config
|
by Kconfig.write_config(). Returns the empty string if no .config
|
||||||
|
@ -4002,6 +4049,15 @@ class Symbol(object):
|
||||||
though you might get some special symbols and possibly some "redundant"
|
though you might get some special symbols and possibly some "redundant"
|
||||||
n-valued symbol entries in there.
|
n-valued symbol entries in there.
|
||||||
|
|
||||||
|
name_and_loc:
|
||||||
|
Holds a string like
|
||||||
|
|
||||||
|
"MY_SYMBOL (defined at foo/Kconfig:12, bar/Kconfig:14)"
|
||||||
|
|
||||||
|
, giving the name of the symbol and its definition location(s).
|
||||||
|
|
||||||
|
If the symbol is undefined, the location is given as "(undefined)".
|
||||||
|
|
||||||
nodes:
|
nodes:
|
||||||
A list of MenuNodes for this symbol. Will contain a single MenuNode for
|
A list of MenuNodes for this symbol. Will contain a single MenuNode for
|
||||||
most symbols. Undefined and constant symbols have an empty nodes list.
|
most symbols. Undefined and constant symbols have an empty nodes list.
|
||||||
|
@ -4232,7 +4288,7 @@ class Symbol(object):
|
||||||
"being outside the active range ([{}, {}]) -- falling "
|
"being outside the active range ([{}, {}]) -- falling "
|
||||||
"back on defaults"
|
"back on defaults"
|
||||||
.format(num2str(user_val), TYPE_TO_STR[self.orig_type],
|
.format(num2str(user_val), TYPE_TO_STR[self.orig_type],
|
||||||
_name_and_loc(self),
|
self.name_and_loc,
|
||||||
num2str(low), num2str(high)))
|
num2str(low), num2str(high)))
|
||||||
else:
|
else:
|
||||||
# If the user value is well-formed and satisfies range
|
# If the user value is well-formed and satisfies range
|
||||||
|
@ -4282,7 +4338,7 @@ class Symbol(object):
|
||||||
self.kconfig._warn(
|
self.kconfig._warn(
|
||||||
"default value {} on {} clamped to {} due to "
|
"default value {} on {} clamped to {} due to "
|
||||||
"being outside the active range ([{}, {}])"
|
"being outside the active range ([{}, {}])"
|
||||||
.format(val_num, _name_and_loc(self),
|
.format(val_num, self.name_and_loc,
|
||||||
num2str(clamp), num2str(low),
|
num2str(clamp), num2str(low),
|
||||||
num2str(high)))
|
num2str(high)))
|
||||||
|
|
||||||
|
@ -4323,7 +4379,7 @@ class Symbol(object):
|
||||||
self.kconfig._warn(
|
self.kconfig._warn(
|
||||||
"The {} symbol {} is being evaluated in a logical context "
|
"The {} symbol {} is being evaluated in a logical context "
|
||||||
"somewhere. It will always evaluate to n."
|
"somewhere. It will always evaluate to n."
|
||||||
.format(TYPE_TO_STR[self.orig_type], _name_and_loc(self)))
|
.format(TYPE_TO_STR[self.orig_type], self.name_and_loc))
|
||||||
|
|
||||||
self._cached_tri_val = 0
|
self._cached_tri_val = 0
|
||||||
return 0
|
return 0
|
||||||
|
@ -4433,6 +4489,13 @@ class Symbol(object):
|
||||||
return '{}{}="{}"\n' \
|
return '{}{}="{}"\n' \
|
||||||
.format(self.kconfig.config_prefix, self.name, escape(val))
|
.format(self.kconfig.config_prefix, self.name, escape(val))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name_and_loc(self):
|
||||||
|
"""
|
||||||
|
See the class documentation.
|
||||||
|
"""
|
||||||
|
return self.name + " " + _locs(self)
|
||||||
|
|
||||||
def set_value(self, value):
|
def set_value(self, value):
|
||||||
"""
|
"""
|
||||||
Sets the user value of the symbol.
|
Sets the user value of the symbol.
|
||||||
|
@ -4454,8 +4517,8 @@ class Symbol(object):
|
||||||
value:
|
value:
|
||||||
The user value to give to the symbol. For bool and tristate symbols,
|
The user value to give to the symbol. For bool and tristate symbols,
|
||||||
n/m/y can be specified either as 0/1/2 (the usual format for tristate
|
n/m/y can be specified either as 0/1/2 (the usual format for tristate
|
||||||
values in Kconfiglib) or as one of the strings "n"/"m"/"y". For other
|
values in Kconfiglib) or as one of the strings "n", "m", or "y". For
|
||||||
symbol types, pass a string.
|
other symbol types, pass a string.
|
||||||
|
|
||||||
Note that the value for an int/hex symbol is passed as a string, e.g.
|
Note that the value for an int/hex symbol is passed as a string, e.g.
|
||||||
"123" or "0x0123". The format of this string is preserved in the
|
"123" or "0x0123". The format of this string is preserved in the
|
||||||
|
@ -4502,7 +4565,7 @@ class Symbol(object):
|
||||||
"assignment ignored"
|
"assignment ignored"
|
||||||
.format(TRI_TO_STR[value] if value in TRI_TO_STR else
|
.format(TRI_TO_STR[value] if value in TRI_TO_STR else
|
||||||
"'{}'".format(value),
|
"'{}'".format(value),
|
||||||
_name_and_loc(self), TYPE_TO_STR[self.orig_type]))
|
self.name_and_loc, TYPE_TO_STR[self.orig_type]))
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -4790,7 +4853,7 @@ class Symbol(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.kconfig._warn_assign_no_prompt:
|
if self.kconfig._warn_assign_no_prompt:
|
||||||
self.kconfig._warn(_name_and_loc(self) + " has no prompt, meaning "
|
self.kconfig._warn(self.name_and_loc + " has no prompt, meaning "
|
||||||
"user values have no effect on it")
|
"user values have no effect on it")
|
||||||
|
|
||||||
def _str_default(self):
|
def _str_default(self):
|
||||||
|
@ -4836,7 +4899,7 @@ class Symbol(object):
|
||||||
|
|
||||||
msg = "{} has direct dependencies {} with value {}, but is " \
|
msg = "{} has direct dependencies {} with value {}, but is " \
|
||||||
"currently being {}-selected by the following symbols:" \
|
"currently being {}-selected by the following symbols:" \
|
||||||
.format(_name_and_loc(self), expr_str(self.direct_dep),
|
.format(self.name_and_loc, expr_str(self.direct_dep),
|
||||||
TRI_TO_STR[expr_value(self.direct_dep)],
|
TRI_TO_STR[expr_value(self.direct_dep)],
|
||||||
TRI_TO_STR[expr_value(self.rev_dep)])
|
TRI_TO_STR[expr_value(self.rev_dep)])
|
||||||
|
|
||||||
|
@ -4854,7 +4917,7 @@ class Symbol(object):
|
||||||
|
|
||||||
msg += "\n - {}, with value {}, direct dependencies {} " \
|
msg += "\n - {}, with value {}, direct dependencies {} " \
|
||||||
"(value: {})" \
|
"(value: {})" \
|
||||||
.format(_name_and_loc(selecting_sym),
|
.format(selecting_sym.name_and_loc,
|
||||||
selecting_sym.str_value,
|
selecting_sym.str_value,
|
||||||
expr_str(selecting_sym.direct_dep),
|
expr_str(selecting_sym.direct_dep),
|
||||||
TRI_TO_STR[expr_value(selecting_sym.direct_dep)])
|
TRI_TO_STR[expr_value(selecting_sym.direct_dep)])
|
||||||
|
@ -4938,19 +5001,9 @@ class Choice(object):
|
||||||
Corresponding attributes have the same name in the Symbol and Choice
|
Corresponding attributes have the same name in the Symbol and Choice
|
||||||
classes, for consistency and compatibility.
|
classes, for consistency and compatibility.
|
||||||
|
|
||||||
assignable:
|
str_value:
|
||||||
See the symbol class documentation. Gives the assignable values (modes).
|
Like choice.tri_value, but gives the value as one of the strings
|
||||||
|
"n", "m", or "y"
|
||||||
visibility:
|
|
||||||
See the Symbol class documentation. Acts on the value (mode).
|
|
||||||
|
|
||||||
selection:
|
|
||||||
The Symbol instance of the currently selected symbol. None if the Choice
|
|
||||||
is not in y mode or has no selected symbol (due to unsatisfied
|
|
||||||
dependencies on choice symbols).
|
|
||||||
|
|
||||||
WARNING: Do not assign directly to this. It will break things. Call
|
|
||||||
sym.set_value(2) on the choice symbol you want to select instead.
|
|
||||||
|
|
||||||
user_value:
|
user_value:
|
||||||
The value (mode) selected by the user through Choice.set_value(). Either
|
The value (mode) selected by the user through Choice.set_value(). Either
|
||||||
|
@ -4960,6 +5013,17 @@ class Choice(object):
|
||||||
WARNING: Do not assign directly to this. It will break things. Use
|
WARNING: Do not assign directly to this. It will break things. Use
|
||||||
Choice.set_value() instead.
|
Choice.set_value() instead.
|
||||||
|
|
||||||
|
assignable:
|
||||||
|
See the symbol class documentation. Gives the assignable values (modes).
|
||||||
|
|
||||||
|
selection:
|
||||||
|
The Symbol instance of the currently selected symbol. None if the Choice
|
||||||
|
is not in y mode or has no selected symbol (due to unsatisfied
|
||||||
|
dependencies on choice symbols).
|
||||||
|
|
||||||
|
WARNING: Do not assign directly to this. It will break things. Call
|
||||||
|
sym.set_value(2) on the choice symbol you want to select instead.
|
||||||
|
|
||||||
user_selection:
|
user_selection:
|
||||||
The symbol selected by the user (by setting it to y). Ignored if the
|
The symbol selected by the user (by setting it to y). Ignored if the
|
||||||
choice is not in y mode, but still remembered so that the choice "snaps
|
choice is not in y mode, but still remembered so that the choice "snaps
|
||||||
|
@ -4969,6 +5033,19 @@ class Choice(object):
|
||||||
WARNING: Do not assign directly to this. It will break things. Call
|
WARNING: Do not assign directly to this. It will break things. Call
|
||||||
sym.set_value(2) on the choice symbol to be selected instead.
|
sym.set_value(2) on the choice symbol to be selected instead.
|
||||||
|
|
||||||
|
visibility:
|
||||||
|
See the Symbol class documentation. Acts on the value (mode).
|
||||||
|
|
||||||
|
name_and_loc:
|
||||||
|
Holds a string like
|
||||||
|
|
||||||
|
"<choice MY_CHOICE> (defined at foo/Kconfig:12)"
|
||||||
|
|
||||||
|
, giving the name of the choice and its definition location(s). If the
|
||||||
|
choice has no name (isn't defined with 'choice MY_CHOICE'), then it will
|
||||||
|
be shown as "<choice>" before the list of locations (always a single one
|
||||||
|
in that case).
|
||||||
|
|
||||||
syms:
|
syms:
|
||||||
List of symbols contained in the choice.
|
List of symbols contained in the choice.
|
||||||
|
|
||||||
|
@ -5088,6 +5165,14 @@ class Choice(object):
|
||||||
self._cached_vis = _visibility(self)
|
self._cached_vis = _visibility(self)
|
||||||
return self._cached_vis
|
return self._cached_vis
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name_and_loc(self):
|
||||||
|
"""
|
||||||
|
See the class documentation.
|
||||||
|
"""
|
||||||
|
# Reuse the expression format, which is '<choice (name, if any)>'.
|
||||||
|
return standard_sc_expr_str(self) + " " + _locs(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selection(self):
|
def selection(self):
|
||||||
"""
|
"""
|
||||||
|
@ -5128,7 +5213,7 @@ class Choice(object):
|
||||||
"assignment ignored"
|
"assignment ignored"
|
||||||
.format(TRI_TO_STR[value] if value in TRI_TO_STR else
|
.format(TRI_TO_STR[value] if value in TRI_TO_STR else
|
||||||
"'{}'".format(value),
|
"'{}'".format(value),
|
||||||
_name_and_loc(self), TYPE_TO_STR[self.orig_type]))
|
self.name_and_loc, TYPE_TO_STR[self.orig_type]))
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -6050,21 +6135,36 @@ def unescape(s):
|
||||||
_unescape_sub = re.compile(r"\\(.)").sub
|
_unescape_sub = re.compile(r"\\(.)").sub
|
||||||
|
|
||||||
|
|
||||||
def standard_kconfig():
|
def standard_kconfig(description=None):
|
||||||
"""
|
"""
|
||||||
Helper for tools. Loads the top-level Kconfig specified as the first
|
Argument parsing helper for tools that take a single optional Kconfig file
|
||||||
command-line argument, or "Kconfig" if there are no command-line arguments.
|
argument (default: Kconfig). Returns the Kconfig instance for the parsed
|
||||||
Returns the Kconfig instance.
|
configuration. Uses argparse internally.
|
||||||
|
|
||||||
Exits with sys.exit() (which raises a SystemExit exception) and prints a
|
Exits with sys.exit() (which raises SystemExit) on errors.
|
||||||
usage note to stderr if more than one command-line argument is passed.
|
|
||||||
|
description (default: None):
|
||||||
|
The 'description' passed to argparse.ArgumentParser().
|
||||||
|
argparse.RawDescriptionHelpFormatter is used, so formatting is preserved.
|
||||||
"""
|
"""
|
||||||
if len(sys.argv) > 2:
|
import argparse
|
||||||
sys.exit("usage: {} [Kconfig]".format(sys.argv[0]))
|
|
||||||
|
|
||||||
# Only show backtraces for unexpected exceptions
|
parser = argparse.ArgumentParser(
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
description=description)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"kconfig",
|
||||||
|
metavar="KCONFIG",
|
||||||
|
default="Kconfig",
|
||||||
|
nargs="?",
|
||||||
|
help="Kconfig file (default: Kconfig)")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Suppress backtraces for expected exceptions
|
||||||
try:
|
try:
|
||||||
return Kconfig("Kconfig" if len(sys.argv) < 2 else sys.argv[1])
|
return Kconfig(args.kconfig)
|
||||||
except (EnvironmentError, KconfigError) as e:
|
except (EnvironmentError, KconfigError) as e:
|
||||||
# Some long exception messages have extra newlines for better
|
# Some long exception messages have extra newlines for better
|
||||||
# formatting when reported as an unhandled exception. Strip them here.
|
# formatting when reported as an unhandled exception. Strip them here.
|
||||||
|
@ -6286,20 +6386,16 @@ def _save_old(path):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _name_and_loc(sc):
|
def _locs(sc):
|
||||||
# Helper for giving the symbol/choice name and location(s) in e.g. warnings
|
# Symbol/Choice.name_and_loc helper. Returns the "(defined at ...)" part of
|
||||||
|
# the string. 'sc' is a Symbol or Choice.
|
||||||
|
|
||||||
# Reuse the expression format. That way choices show up as
|
if sc.nodes:
|
||||||
# '<choice (name, if any)>'
|
return "(defined at {})".format(
|
||||||
name = standard_sc_expr_str(sc)
|
", ".join("{0.filename}:{0.linenr}".format(node)
|
||||||
|
for node in sc.nodes))
|
||||||
|
|
||||||
if not sc.nodes:
|
return "(undefined)"
|
||||||
return name + " (undefined)"
|
|
||||||
|
|
||||||
return "{} (defined at {})".format(
|
|
||||||
name,
|
|
||||||
", ".join("{}:{}".format(node.filename, node.linenr)
|
|
||||||
for node in sc.nodes))
|
|
||||||
|
|
||||||
|
|
||||||
# Menu manipulation
|
# Menu manipulation
|
||||||
|
@ -6554,7 +6650,7 @@ def _found_dep_loop(loop, cur):
|
||||||
msg += "the choice symbol "
|
msg += "the choice symbol "
|
||||||
|
|
||||||
msg += "{}, with definition...\n\n{}\n\n" \
|
msg += "{}, with definition...\n\n{}\n\n" \
|
||||||
.format(_name_and_loc(item), item)
|
.format(item.name_and_loc, item)
|
||||||
|
|
||||||
# Small wart: Since we reuse the already calculated
|
# Small wart: Since we reuse the already calculated
|
||||||
# Symbol/Choice._dependents sets for recursive dependency detection, we
|
# Symbol/Choice._dependents sets for recursive dependency detection, we
|
||||||
|
@ -6578,7 +6674,7 @@ def _found_dep_loop(loop, cur):
|
||||||
msg += "(imply-related dependencies: {})\n\n" \
|
msg += "(imply-related dependencies: {})\n\n" \
|
||||||
.format(expr_str(item.rev_dep))
|
.format(expr_str(item.rev_dep))
|
||||||
|
|
||||||
msg += "...depends again on {}".format(_name_and_loc(loop[0]))
|
msg += "...depends again on " + loop[0].name_and_loc
|
||||||
|
|
||||||
raise KconfigError(msg)
|
raise KconfigError(msg)
|
||||||
|
|
||||||
|
@ -7015,8 +7111,8 @@ _assignment_lhs_fragment_match = _re_match("[A-Za-z0-9_-]*")
|
||||||
# variable assignment
|
# variable assignment
|
||||||
_assignment_rhs_match = _re_match(r"\s*(=|:=|\+=)\s*(.*)")
|
_assignment_rhs_match = _re_match(r"\s*(=|:=|\+=)\s*(.*)")
|
||||||
|
|
||||||
# Special characters/strings while expanding a macro (')', ',', and '$(')
|
# Special characters/strings while expanding a macro ('(', ')', ',', and '$(')
|
||||||
_macro_special_search = _re_search(r"\)|,|\$\(")
|
_macro_special_search = _re_search(r"\(|\)|,|\$\(")
|
||||||
|
|
||||||
# Special characters/strings while expanding a string (quotes, '\', and '$(')
|
# Special characters/strings while expanding a string (quotes, '\', and '$(')
|
||||||
_string_special_search = _re_search(r'"|\'|\\|\$\(')
|
_string_special_search = _re_search(r'"|\'|\\|\$\(')
|
||||||
|
|
|
@ -76,7 +76,7 @@ This is the current list of built-in styles:
|
||||||
- default classic Kconfiglib theme with a yellow accent
|
- default classic Kconfiglib theme with a yellow accent
|
||||||
- monochrome colorless theme (uses only bold and standout) attributes,
|
- monochrome colorless theme (uses only bold and standout) attributes,
|
||||||
this style is used if the terminal doesn't support colors
|
this style is used if the terminal doesn't support colors
|
||||||
- aquatic blue tinted style loosely resembling the lxdialog theme
|
- aquatic blue-tinted style loosely resembling the lxdialog theme
|
||||||
|
|
||||||
It is possible to customize the current style by changing colors of UI
|
It is possible to customize the current style by changing colors of UI
|
||||||
elements on the screen. This is the list of elements that can be stylized:
|
elements on the screen. This is the list of elements that can be stylized:
|
||||||
|
@ -140,13 +140,16 @@ If there's an error in the style definition or if a missing style is assigned
|
||||||
to, the assignment will be ignored, along with a warning being printed on
|
to, the assignment will be ignored, along with a warning being printed on
|
||||||
stderr.
|
stderr.
|
||||||
|
|
||||||
The 'default' theme is always implicitly parsed first (or the 'monochrome'
|
The 'default' theme is always implicitly parsed first, so the following two
|
||||||
theme if the terminal lacks colors), so the following two settings have the
|
settings have the same effect:
|
||||||
same effect:
|
|
||||||
|
|
||||||
MENUCONFIG_STYLE="selection=fg:white,bg:red"
|
MENUCONFIG_STYLE="selection=fg:white,bg:red"
|
||||||
MENUCONFIG_STYLE="default selection=fg:white,bg:red"
|
MENUCONFIG_STYLE="default selection=fg:white,bg:red"
|
||||||
|
|
||||||
|
If the terminal doesn't support colors, the 'monochrome' theme is used, and
|
||||||
|
MENUCONFIG_STYLE is ignored. The assumption is that the environment is broken
|
||||||
|
somehow, and that the important thing is to get something usable.
|
||||||
|
|
||||||
|
|
||||||
Other features
|
Other features
|
||||||
==============
|
==============
|
||||||
|
@ -177,27 +180,41 @@ Other features
|
||||||
Limitations
|
Limitations
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Doesn't work out of the box on Windows, but can be made to work with 'pip
|
Doesn't work out of the box on Windows, but can be made to work with
|
||||||
install windows-curses'. See the
|
|
||||||
https://github.com/zephyrproject-rtos/windows-curses repository.
|
|
||||||
|
|
||||||
'pip install kconfiglib' on Windows automatically installs windows-curses
|
pip install windows-curses
|
||||||
to make the menuconfig usable.
|
|
||||||
|
See the https://github.com/zephyrproject-rtos/windows-curses repository.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
_IS_WINDOWS = os.name == "nt" # Are we running on Windows?
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import curses
|
import curses
|
||||||
except ImportError:
|
except ImportError as e:
|
||||||
print('"windows-curses" package is required in Windows command line. Please install it by running '
|
if not _IS_WINDOWS:
|
||||||
'"{} -m pip install --user windows-curses" (or without the "--user" option)'
|
raise
|
||||||
''.format(sys.executable))
|
sys.exit("""\
|
||||||
exit(1)
|
menuconfig failed to import the standard Python 'curses' library. Try
|
||||||
|
installing a package like windows-curses
|
||||||
|
(https://github.com/zephyrproject-rtos/windows-curses) by running this command
|
||||||
|
in cmd.exe:
|
||||||
|
|
||||||
|
pip install windows-curses
|
||||||
|
|
||||||
|
Starting with Kconfiglib 13.0.0, windows-curses is no longer automatically
|
||||||
|
installed when installing Kconfiglib via pip on Windows (because it breaks
|
||||||
|
installation on MSYS2).
|
||||||
|
|
||||||
|
Exception:
|
||||||
|
{}: {}""".format(type(e).__name__, e))
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import locale
|
import locale
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
@ -309,19 +326,18 @@ _STYLES = {
|
||||||
text=
|
text=
|
||||||
""",
|
""",
|
||||||
|
|
||||||
# Blue tinted style loosely resembling lxdialog
|
# Blue-tinted style loosely resembling lxdialog
|
||||||
"aquatic": """
|
"aquatic": """
|
||||||
path=fg:cyan,bg:blue,bold
|
path=fg:cyan,bg:blue,bold
|
||||||
separator=fg:white,bg:cyan,bold
|
separator=fg:white,bg:cyan,bold
|
||||||
help=path
|
help=path
|
||||||
frame=fg:white,bg:cyan,bold
|
frame=fg:white,bg:cyan,bold
|
||||||
body=fg:brightwhite,bg:blue
|
body=fg:white,bg:blue
|
||||||
edit=fg:black,bg:white
|
edit=fg:black,bg:white
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Standard colors definition
|
_NAMED_COLORS = {
|
||||||
_STYLE_STD_COLORS = {
|
|
||||||
# Basic colors
|
# Basic colors
|
||||||
"black": curses.COLOR_BLACK,
|
"black": curses.COLOR_BLACK,
|
||||||
"red": curses.COLOR_RED,
|
"red": curses.COLOR_RED,
|
||||||
|
@ -547,9 +563,6 @@ def _style_to_curses(style_def):
|
||||||
def parse_color(color_def):
|
def parse_color(color_def):
|
||||||
color_def = color_def.split(":", 1)[1]
|
color_def = color_def.split(":", 1)[1]
|
||||||
|
|
||||||
if color_def in _STYLE_STD_COLORS:
|
|
||||||
return _color_from_num(_STYLE_STD_COLORS[color_def])
|
|
||||||
|
|
||||||
# HTML format, #RRGGBB
|
# HTML format, #RRGGBB
|
||||||
if re.match("#[A-Fa-f0-9]{6}", color_def):
|
if re.match("#[A-Fa-f0-9]{6}", color_def):
|
||||||
return _color_from_rgb((
|
return _color_from_rgb((
|
||||||
|
@ -557,19 +570,20 @@ def _style_to_curses(style_def):
|
||||||
int(color_def[3:5], 16),
|
int(color_def[3:5], 16),
|
||||||
int(color_def[5:7], 16)))
|
int(color_def[5:7], 16)))
|
||||||
|
|
||||||
try:
|
if color_def in _NAMED_COLORS:
|
||||||
color_num = _color_from_num(int(color_def, 0))
|
color_num = _color_from_num(_NAMED_COLORS[color_def])
|
||||||
except ValueError:
|
else:
|
||||||
_warn("Ignoring color ", color_def, "that's neither predefined "
|
try:
|
||||||
"nor a number")
|
color_num = _color_from_num(int(color_def, 0))
|
||||||
|
except ValueError:
|
||||||
return -1
|
_warn("Ignoring color", color_def, "that's neither "
|
||||||
|
"predefined nor a number")
|
||||||
|
return -1
|
||||||
|
|
||||||
if not -1 <= color_num < curses.COLORS:
|
if not -1 <= color_num < curses.COLORS:
|
||||||
_warn("Ignoring color {}, which is outside the range "
|
_warn("Ignoring color {}, which is outside the range "
|
||||||
"-1..curses.COLORS-1 (-1..{})"
|
"-1..curses.COLORS-1 (-1..{})"
|
||||||
.format(color_def, curses.COLORS - 1))
|
.format(color_def, curses.COLORS - 1))
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
return color_num
|
return color_num
|
||||||
|
@ -602,15 +616,26 @@ def _style_to_curses(style_def):
|
||||||
|
|
||||||
def _init_styles():
|
def _init_styles():
|
||||||
if curses.has_colors():
|
if curses.has_colors():
|
||||||
curses.use_default_colors()
|
try:
|
||||||
|
curses.use_default_colors()
|
||||||
|
except curses.error:
|
||||||
|
# Ignore errors on funky terminals that support colors but not
|
||||||
|
# using default colors. Worst it can do is break transparency and
|
||||||
|
# the like. Ran across this with the MSYS2/winpty setup in
|
||||||
|
# https://github.com/msys2/MINGW-packages/issues/5823, though there
|
||||||
|
# seems to be a lot of general brokenness there.
|
||||||
|
pass
|
||||||
|
|
||||||
# Use the 'monochrome' style template as the base on terminals without
|
# Use the 'default' theme as the base, and add any user-defined style
|
||||||
# color
|
# settings from the environment
|
||||||
_parse_style("default" if curses.has_colors() else "monochrome", True)
|
_parse_style("default", True)
|
||||||
|
if "MENUCONFIG_STYLE" in os.environ:
|
||||||
# Add any user-defined style from the environment
|
_parse_style(os.environ["MENUCONFIG_STYLE"], False)
|
||||||
if "MENUCONFIG_STYLE" in os.environ:
|
else:
|
||||||
_parse_style(os.environ["MENUCONFIG_STYLE"], False)
|
# Force the 'monochrome' theme if the terminal doesn't support colors.
|
||||||
|
# MENUCONFIG_STYLE is likely to mess things up here (though any colors
|
||||||
|
# would be ignored), so ignore it.
|
||||||
|
_parse_style("monochrome", True)
|
||||||
|
|
||||||
|
|
||||||
# color_attribs holds the color pairs we've already created, indexed by a
|
# color_attribs holds the color pairs we've already created, indexed by a
|
||||||
|
@ -644,7 +669,7 @@ def _style_attr(fg_color, bg_color, attribs, color_attribs={}):
|
||||||
|
|
||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
menuconfig(standard_kconfig())
|
menuconfig(standard_kconfig(__doc__))
|
||||||
|
|
||||||
|
|
||||||
def menuconfig(kconf):
|
def menuconfig(kconf):
|
||||||
|
@ -2210,9 +2235,7 @@ def _sorted_sc_nodes(cached_nodes=[]):
|
||||||
key=lambda choice: choice.name or "")
|
key=lambda choice: choice.name or "")
|
||||||
|
|
||||||
cached_nodes += sorted(
|
cached_nodes += sorted(
|
||||||
[node
|
[node for choice in choices for node in choice.nodes],
|
||||||
for choice in choices
|
|
||||||
for node in choice.nodes],
|
|
||||||
key=lambda node: node.prompt[0] if node.prompt else "")
|
key=lambda node: node.prompt[0] if node.prompt else "")
|
||||||
|
|
||||||
return cached_nodes
|
return cached_nodes
|
||||||
|
@ -3273,8 +3296,5 @@ def _change_c_lc_ctype_to_utf8():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# Are we running on Windows?
|
|
||||||
_IS_WINDOWS = os.name == "nt"
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
_main()
|
_main()
|
||||||
|
|
Loading…
Reference in a new issue