kconfiglib: Update to add warning for malformed .config lines
Update Kconfiglib to upstream revision ed3ceaa056262 (+ local Zephyr
modifications) to get commits c1c5ef2eb1009 ("Print a warning for
malformed .config lines") and ed3ceaa05626f ("Make warnings available in
a list") in.
This warning for malformed .config lines will be turned into an error in
kconfig.py, which is made easier by making the warnings available in a
list in Kconfiglib.
It's now configurable whether warnings are printed to stderr or not. In
this case, it still makes sense to print them to stderr as well.
Suggested by Marti Bolivar.
Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py
index 6f979ac..1cb5a09 100644
--- a/scripts/kconfig/kconfiglib.py
+++ b/scripts/kconfig/kconfiglib.py
@@ -479,6 +479,19 @@
C tools). Can be changed with the 'mainmenu' statement (see
kconfig-language.txt).
+ warnings:
+ A list of strings containing all warnings that have been generated. This
+ allows flexibility in how warnings are printed and processed.
+
+ See the 'warn_to_stderr' parameter to Kconfig.__init__() and the
+ Kconfig.enable/disable_stderr_warnings() functions as well. Note that
+ warnings still get added to Kconfig.warnings when 'warn_to_stderr' is
+ True.
+
+ Just as for warnings printed to stderr, only optional warnings that are
+ enabled will get added to Kconfig.warnings. See the various
+ Kconfig.enable/disable_*_warnings() functions.
+
srctree:
The value of the $srctree environment variable when the configuration was
loaded, or None if $srctree wasn't set. Kconfig and .config files are
@@ -501,12 +514,13 @@
"""
__slots__ = (
"_choices",
- "_print_undef_assign",
- "_print_redun_assign",
- "_print_warnings",
"_set_re_match",
"_unset_re_match",
- "_warn_no_prompt",
+ "_warn_for_no_prompt",
+ "_warn_for_redun_assign",
+ "_warn_for_undef_assign",
+ "_warn_to_stderr",
+ "_warnings_enabled",
"config_prefix",
"const_syms",
"defconfig_list",
@@ -518,6 +532,7 @@
"srctree",
"syms",
"top_node",
+ "warnings",
"y",
# Parsing-related
@@ -537,7 +552,7 @@
# Public interface
#
- def __init__(self, filename="Kconfig", warn=True):
+ def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True):
"""
Creates a new Kconfig object by parsing Kconfig files. Raises
KconfigSyntaxError on syntax errors. Note that Kconfig files are not
@@ -557,10 +572,23 @@
set. See the class documentation.
warn (default: True):
- True if warnings related to this configuration should be printed to
- stderr. This can be changed later with
- Kconfig.enable/disable_warnings(). It is provided as a constructor
- argument since warnings might be generated during parsing.
+ True if warnings related to this configuration should be generated.
+ This can be changed later with Kconfig.enable/disable_warnings(). It
+ is provided as a constructor argument since warnings might be
+ generated during parsing.
+
+ See the other Kconfig.enable_*_warnings() functions as well, which
+ enable or suppress certain warnings when warnings are enabled.
+
+ All generated warnings are added to the Kconfig.warnings list. See
+ the class documentation.
+
+ warn_to_stderr (default: True):
+ True if warnings should be printed to stderr in addition to being
+ added to Kconfig.warnings.
+
+ This can be changed later with
+ Kconfig.enable/disable_stderr_warnings().
"""
self.srctree = os.environ.get("srctree")
@@ -581,9 +609,13 @@
_RE_ASCII).match
- self._print_warnings = warn
- self._print_undef_assign = False
- self._print_redun_assign = True
+ self.warnings = []
+
+ self._warnings_enabled = warn
+ self._warn_to_stderr = warn_to_stderr
+ self._warn_for_undef_assign = False
+ self._warn_for_redun_assign = True
+
self.syms = {}
self.const_syms = {}
@@ -657,10 +689,14 @@
self._file = self._open(filename)
- self._parse_block(None, # end_token
- self.top_node, # parent
- self.top_node, # prev
- self.y) # visible_if_deps
+ try:
+ self._parse_block(None, # end_token
+ self.top_node, # parent
+ self.top_node, # prev
+ self.y) # visible_if_deps
+ except UnicodeDecodeError as e:
+ _decoding_error(e, self._filename)
+
self.top_node.list = self.top_node.next
self.top_node.next = None
@@ -683,7 +719,7 @@
# Build Symbol._dependents for all symbols
self._build_dep()
- self._warn_no_prompt = True
+ self._warn_for_no_prompt = True
@property
def mainmenu_text(self):
@@ -733,13 +769,15 @@
"""
# Disable the warning about assigning to symbols without prompts. This
# is normal and expected within a .config file.
- self._warn_no_prompt = False
+ self._warn_for_no_prompt = False
- # This stub only exists to make sure _warn_no_prompt gets reenabled
+ # This stub only exists to make sure _warn_for_no_prompt gets reenabled
try:
self._load_config(filename, replace)
+ except UnicodeDecodeError as e:
+ _decoding_error(e, filename)
finally:
- self._warn_no_prompt = True
+ self._warn_for_no_prompt = True
def _load_config(self, filename, replace):
with self._open(filename) as f:
@@ -814,7 +852,7 @@
elif sym.orig_type == STRING:
string_match = _conf_string_re_match(val)
if not string_match:
- self._warn("Malformed string literal in "
+ self._warn("malformed string literal in "
"assignment to {}. Assignment ignored."
.format(_name_and_loc(sym)),
filename, linenr)
@@ -825,6 +863,15 @@
else:
unset_match = unset_re_match(line)
if not unset_match:
+ # Print a warning for lines that match neither
+ # set_re_match() nor unset_re_match() and that are not
+ # blank lines or comments. 'line' has already been
+ # rstrip()'d, so blank lines show up as "" here.
+ if line and not line.lstrip().startswith("#"):
+ self._warn("ignoring malformed line '{}'"
+ .format(line),
+ filename, linenr)
+
continue
name = unset_match.group(1)
@@ -1268,7 +1315,7 @@
Resets the user values of all symbols, as if Kconfig.load_config() or
Symbol.set_value() had never been called.
"""
- self._warn_no_prompt = False
+ self._warn_for_no_prompt = False
try:
# set_value() already rejects undefined symbols, and they don't
# need to be invalidated (because their value never changes), so we
@@ -1279,46 +1326,61 @@
for choice in self._choices:
choice.unset_value()
finally:
- self._warn_no_prompt = True
+ self._warn_for_no_prompt = True
def enable_warnings(self):
"""
See Kconfig.__init__().
"""
- self._print_warnings = True
+ self._warnings_enabled = True
def disable_warnings(self):
"""
See Kconfig.__init__().
"""
- self._print_warnings = False
+ self._warnings_enabled = False
+
+ def enable_stderr_warnings(self):
+ """
+ See Kconfig.__init__().
+ """
+ self._warn_to_stderr = True
+
+ def disable_stderr_warnings(self):
+ """
+ See Kconfig.__init__().
+ """
+ self._warn_to_stderr = False
def enable_undef_warnings(self):
"""
- Enables warnings for assignments to undefined symbols. Printed to
- stderr. Disabled by default since they tend to be spammy for Kernel
- configurations (and mostly suggests cleanups).
+ Enables warnings for assignments to undefined symbols. Disabled by
+ default since they tend to be spammy for Kernel configurations (and
+ mostly suggests cleanups).
"""
- self._print_undef_assign = True
+ self._warn_for_undef_assign = True
def disable_undef_warnings(self):
"""
See enable_undef_assign().
"""
- self._print_undef_assign = False
+ self._warn_for_undef_assign = False
def enable_redun_warnings(self):
"""
- Enables warnings for redundant assignments to symbols. Printed to
- stderr. Enabled by default.
+ Enables warnings for duplicated assignments in .config files that all
+ set the same value.
+
+ These warnings are enabled by default. Disabling them might be helpful
+ in certain cases when merging configurations.
"""
- self._print_redun_assign = True
+ self._warn_for_redun_assign = True
def disable_redun_warnings(self):
"""
See enable_redun_warnings().
"""
- self._print_redun_assign = False
+ self._warn_for_redun_assign = False
def __repr__(self):
"""
@@ -1331,11 +1393,14 @@
"srctree not set" if self.srctree is None else
'srctree "{}"'.format(self.srctree),
'config symbol prefix "{}"'.format(self.config_prefix),
- "warnings " + ("enabled" if self._print_warnings else "disabled"),
+ "warnings " +
+ ("enabled" if self._warnings_enabled else "disabled"),
+ "printing of warnings to stderr " +
+ ("enabled" if self._warn_to_stderr else "disabled"),
"undef. symbol assignment warnings " +
- ("enabled" if self._print_undef_assign else "disabled"),
+ ("enabled" if self._warn_for_undef_assign else "disabled"),
"redundant symbol assignment warnings " +
- ("enabled" if self._print_redun_assign else "disabled")
+ ("enabled" if self._warn_for_redun_assign else "disabled")
)))
#
@@ -2515,14 +2580,20 @@
def _warn(self, msg, filename=None, linenr=None):
# For printing general warnings
- if self._print_warnings:
- _stderr_msg("warning: " + msg, filename, linenr)
+ if self._warnings_enabled:
+ msg = "warning: " + msg
+ if filename is not None:
+ msg = "{}:{}: {}".format(filename, linenr, msg)
+
+ self.warnings.append(msg)
+ if self._warn_to_stderr:
+ sys.stderr.write(msg + "\n")
def _warn_undef_assign(self, msg, filename=None, linenr=None):
# See the class documentation
- if self._print_undef_assign:
- _stderr_msg("warning: " + msg, filename, linenr)
+ if self._warn_for_undef_assign:
+ self._warn(msg, filename, linenr)
def _warn_undef_assign_load(self, name, val, filename, linenr):
# Special version for load_config()
@@ -2534,8 +2605,8 @@
def _warn_redun_assign(self, msg, filename=None, linenr=None):
# See the class documentation
- if self._print_redun_assign:
- _stderr_msg("warning: " + msg, filename, linenr)
+ if self._warn_for_redun_assign:
+ self._warn(msg, filename, linenr)
class Symbol(object):
"""
@@ -3350,7 +3421,7 @@
self._rec_invalidate()
return
- if self.kconfig._warn_no_prompt:
+ if self.kconfig._warn_for_no_prompt:
self.kconfig._warn(_name_and_loc(self) + " has no prompt, meaning "
"user values have no effect on it")
@@ -4320,12 +4391,6 @@
return sym.tri_value if sym.orig_type in (BOOL, TRISTATE) else \
int(sym.str_value, _TYPE_TO_BASE[sym.orig_type])
-def _stderr_msg(msg, filename, linenr):
- if filename is not None:
- msg = "{}:{}: {}".format(filename, linenr, msg)
-
- sys.stderr.write(msg + "\n")
-
def _internal_error(msg):
raise InternalError(
msg +
@@ -4333,6 +4398,22 @@
"email service to tell me about this. Include the message above and "
"the stack trace and describe what you were doing.")
+def _decoding_error(e, filename):
+ # Gives the filename and context for UnicodeDecodeError's, which are a pain
+ # to debug otherwise. 'e' is the UnicodeDecodeError object.
+
+ raise KconfigSyntaxError(
+ "\n"
+ "Malformed {} in {}\n"
+ "Context: {}\n"
+ "Problematic data: {}\n"
+ "Reason: {}".format(
+ e.encoding, filename,
+ e.object[max(e.start - 40, 0):e.end + 40],
+ e.object[e.start:e.end],
+ e.reason))
+
+
# Printing functions
def _sym_choice_str(sc):