mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-17 09:25:57 +00:00
Update Kconfiglib to upstream revision 547fced630611 to get a new Kconfig preprocessor in, documented in https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.txt. The preprocessor allows shell functions to be run directly from Kconfig. Things like 'default "prefix-$(shell,some-cmd)' and 'depends on (success,some-cmd)' are supported. The preprocessor might come in handy for Kconfig/DTS integration. I'm thinking of extending it so that Python functions can be called as well. There's also two new warnings: - Trying to use an int/hex symbol like a bool symbol in an expression (where it will always evaluate to n) - Having a 'default' on an int/hex symbol that lies outside an active 'range'. The parser is more strict now as well (due to dropping some hacks for 3+ year old kernel versions). A related fix for scripts/kconfig.py is also included: The comment above the whitelist lies. I accidentally changed the warning text for the select-with-unsatisfied-dependencies warning while generalizing it (for m-valued dependencies, which you'd never get in Zephyr). Update the whitelist to detect the new warning text. Last-minute piggyback: Include a change that improved the parse time for U-Boot from 4 seconds to about 0.6 seconds, related to symbols defined in multiple locations. It might be helpful for Zephyr as well, as it also uses a lot of symbols defined in multiple locations. Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
223 lines
7.9 KiB
Python
Executable File
223 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Modified from: https://github.com/ulfalizer/Kconfiglib/blob/master/examples/merge_config.py
|
|
import argparse
|
|
import sys
|
|
import textwrap
|
|
|
|
from kconfiglib import Kconfig, Symbol, BOOL, STRING, TRISTATE, TRI_TO_STR
|
|
|
|
# Warnings that won't be turned into errors (but that will still be printed),
|
|
# identified by a substring of the warning. The warning texts from Kconfiglib
|
|
# are guaranteed to not change.
|
|
WARNING_WHITELIST = (
|
|
# Warning generated when a symbol with unsatisfied dependencies is being
|
|
# selected. These should be investigated, but whitelist them for now.
|
|
"y-selected",
|
|
|
|
# This symbol is only defined for ARC, but is set in some "shared" .conf
|
|
# files
|
|
"undefined symbol ARC_INIT", # Issue #7977
|
|
)
|
|
|
|
def fatal(warning):
|
|
# Returns True if 'warning' is not whitelisted and should be turned into an
|
|
# error
|
|
|
|
for wl_warning in WARNING_WHITELIST:
|
|
if wl_warning in warning:
|
|
return False
|
|
|
|
# Only allow enabled (printed) warnings to be fatal
|
|
return enabled(warning)
|
|
|
|
|
|
def enabled(warning):
|
|
# Returns True if 'warning' should be printed
|
|
|
|
# Some prj.conf files seem to deliberately override settings from the board
|
|
# configuration (e.g. samples/bluetooth/hci_usb/prj.conf, with GPIO=y).
|
|
# Disable the warning about a symbol being assigned more than once.
|
|
return "set more than once" not in warning
|
|
|
|
|
|
def main():
|
|
parse_args()
|
|
|
|
print("Parsing Kconfig tree in {}".format(args.kconfig_root))
|
|
kconf = Kconfig(args.kconfig_root, warn_to_stderr=False)
|
|
|
|
# Enable warnings for assignments to undefined symbols
|
|
kconf.enable_undef_warnings()
|
|
|
|
# This script uses alldefconfig as the base. Other starting states could be set
|
|
# up here as well. The approach in examples/allnoconfig_simpler.py could
|
|
# provide an allnoconfig starting state for example.
|
|
|
|
print("Using {} as base".format(args.conf_fragments[0]))
|
|
for config in args.conf_fragments[1:]:
|
|
print("Merging {}".format(config))
|
|
# Create a merged configuration by loading the fragments with replace=False
|
|
for config in args.conf_fragments:
|
|
kconf.load_config(config, replace=False)
|
|
|
|
|
|
# Print warnings for symbols whose actual value doesn't match the assigned
|
|
# value
|
|
for sym in kconf.defined_syms:
|
|
# Was the symbol assigned to? Choice symbols are checked separately.
|
|
if sym.user_value is not None and not sym.choice:
|
|
verify_assigned_sym_value(sym)
|
|
|
|
# Print warnings for choices whose actual selection doesn't match the user
|
|
# selection
|
|
for choice in kconf.choices:
|
|
if choice.user_selection:
|
|
verify_assigned_choice_value(choice)
|
|
|
|
# We could roll this into the loop below, but it's nice to always print all
|
|
# warnings, even if one of them turns out to be fatal
|
|
for warning in kconf.warnings:
|
|
if enabled(warning):
|
|
print(warning, file=sys.stderr)
|
|
|
|
# Turn all warnings except for explicity whitelisted ones into errors. In
|
|
# particular, this will turn assignments to undefined Kconfig variables
|
|
# into errors.
|
|
#
|
|
# A warning is generated by this script whenever a symbol gets a different
|
|
# value than the one it was assigned. Keep that one as just a warning for
|
|
# now as well.
|
|
for warning in kconf.warnings:
|
|
if fatal(warning):
|
|
sys.exit("Error: Aborting due to non-whitelisted Kconfig "
|
|
"warning '{}'.\nNote: If this warning doesn't point "
|
|
"to an actual problem, you can add it to the "
|
|
"whitelist at the top of {}."
|
|
.format(warning, sys.argv[0]))
|
|
|
|
|
|
# Write the merged configuration
|
|
kconf.write_config(args.dotconfig)
|
|
|
|
# Write the C header
|
|
kconf.write_autoconf(args.autoconf)
|
|
|
|
|
|
# Message printed when a promptless symbol is assigned (and doesn't get the
|
|
# assigned value)
|
|
PROMPTLESS_HINT = """
|
|
This symbol has no prompt, meaning assignments in configuration files have no
|
|
effect on it. It can only be set indirectly, via Kconfig defaults (e.g. in a
|
|
Kconfig.defconfig file) or through being 'select'ed or 'imply'd (note: try to
|
|
avoid Kconfig 'select's except for trivial promptless "helper" symbols without
|
|
dependencies, as it ignores dependencies and forces symbols on).
|
|
"""
|
|
|
|
# Message about where to look up symbol information
|
|
SYM_INFO_HINT = """
|
|
You can check symbol information (including dependencies) in the 'menuconfig'
|
|
interface (see the Application Development Primer section of the manual), or in
|
|
the Kconfig reference at
|
|
http://docs.zephyrproject.org/reference/kconfig/CONFIG_{}.html (which is
|
|
updated regularly from the master branch). See the 'Setting configuration
|
|
values' section of the Board Porting Guide as well.
|
|
"""[1:] # Remove initial newline for nicer textwrap output when joining texts
|
|
|
|
PROMPTLESS_HINT_EXTRA = "It covers Kconfig.defconfig files."
|
|
|
|
def verify_assigned_sym_value(sym):
|
|
# Verifies that the value assigned to 'sym' "took" (matches the value the
|
|
# symbol actually got), printing a warning otherwise
|
|
|
|
# Tristate values are represented as 0, 1, 2. Having them as
|
|
# "n", "m", "y" is more convenient here, so convert.
|
|
if sym.type in (BOOL, TRISTATE):
|
|
user_value = TRI_TO_STR[sym.user_value]
|
|
else:
|
|
user_value = sym.user_value
|
|
|
|
if user_value != sym.str_value:
|
|
msg = "warning: {} was assigned the value '{}' but got the " \
|
|
"value '{}'. " \
|
|
.format(name_and_loc(sym), user_value, sym.str_value)
|
|
|
|
if promptless(sym):
|
|
msg += PROMPTLESS_HINT
|
|
|
|
msg += SYM_INFO_HINT.format(sym.name)
|
|
|
|
if promptless(sym):
|
|
msg += PROMPTLESS_HINT_EXTRA
|
|
|
|
# Use a large fill() width to try to avoid linebreaks in the symbol
|
|
# reference link
|
|
print(textwrap.fill(msg, 100), file=sys.stderr)
|
|
|
|
|
|
def verify_assigned_choice_value(choice):
|
|
# Verifies that the choice symbol that was selected (by setting it to y)
|
|
# ended up as the selection, printing a warning otherwise.
|
|
#
|
|
# We check choice symbols separately to avoid warnings when two different
|
|
# choice symbols within the same choice are set to y. This might happen if
|
|
# a choice selection from a board defconfig is overriden in a prj.conf, for
|
|
# example. The last choice symbol set to y becomes the selection (and all
|
|
# other choice symbols get the value n).
|
|
#
|
|
# Without special-casing choices, we'd detect that the first symbol set to
|
|
# y ended up as n, and print a spurious warning.
|
|
|
|
if choice.user_selection is not choice.selection:
|
|
msg = "warning: the choice symbol {} was selected (set =y), but {} " \
|
|
"ended up as the choice selection. " \
|
|
.format(name_and_loc(choice.user_selection),
|
|
name_and_loc(choice.selection) if choice.selection
|
|
else "no symbol")
|
|
|
|
msg += SYM_INFO_HINT.format(choice.user_selection.name)
|
|
|
|
print(textwrap.fill(msg, 100), file=sys.stderr)
|
|
|
|
|
|
def name_and_loc(sym):
|
|
# Helper for printing the name and Kconfig file location(s) for a symbol
|
|
|
|
if not sym.nodes:
|
|
return sym.name + " (undefined)"
|
|
|
|
return "{} (defined at {})".format(
|
|
sym.name,
|
|
", ".join("{}:{}".format(node.filename, node.linenr)
|
|
for node in sym.nodes))
|
|
|
|
|
|
def promptless(sym):
|
|
# Returns True if 'sym' has no prompt. Since the symbol might be defined in
|
|
# multiple locations, we need to check all locations.
|
|
|
|
for node in sym.nodes:
|
|
if node.prompt:
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def parse_args():
|
|
global args
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
)
|
|
|
|
parser.add_argument("kconfig_root")
|
|
parser.add_argument("dotconfig")
|
|
parser.add_argument("autoconf")
|
|
parser.add_argument("conf_fragments", metavar='conf', type=str, nargs='+')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|