89 lines
2.4 KiB
Python
Executable File
89 lines
2.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Prints a message giving the locations of all references to undefined symbols
|
|
# within the Kconfig files. Prints nothing if there are no undefined
|
|
# references.
|
|
#
|
|
# The top-level Kconfig file is assumed to be called 'Kconfig'.
|
|
|
|
import sys
|
|
|
|
import kconfiglib
|
|
|
|
|
|
def report():
|
|
# Returns a message (string) giving the locations of all references to
|
|
# undefined Kconfig symbols within the Kconfig files, or the empty string
|
|
# if there are no references to undefined symbols.
|
|
#
|
|
# Note: This function is called directly during CI.
|
|
|
|
kconf = kconfiglib.Kconfig()
|
|
|
|
undef_msg = ""
|
|
|
|
for name, sym in kconf.syms.items():
|
|
# - sym.nodes empty means the symbol is undefined (has no definition
|
|
# locations)
|
|
#
|
|
# - Due to Kconfig internals, numbers show up as undefined Kconfig
|
|
# symbols, but shouldn't be flagged
|
|
#
|
|
# - The MODULES symbol always exists but is unused in Zephyr
|
|
if not sym.nodes and not is_num(name) and name != "MODULES":
|
|
undef_msg += ref_locations_str(sym)
|
|
|
|
if undef_msg:
|
|
return "Error: Found references to undefined Kconfig symbols:\n" \
|
|
+ undef_msg
|
|
|
|
return ""
|
|
|
|
|
|
def is_num(name):
|
|
# Heuristic to see if a symbol name looks like a number. Internally,
|
|
# everything is a symbol, only undefined symbols (which numbers usually
|
|
# are) get their name as their value.
|
|
|
|
try:
|
|
int(name)
|
|
except ValueError:
|
|
# Require hex constants to be prefixed with 0x in Kconfig files, so
|
|
# that we can tell that e.g. F00 is an undefined symbol reference.
|
|
if not name.startswith(("0x", "0X")):
|
|
return False
|
|
|
|
try:
|
|
int(name, 16)
|
|
except ValueError:
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def ref_locations_str(sym):
|
|
# Prints all locations where sym is referenced, along with the Kconfig
|
|
# definitions of the referencing items
|
|
|
|
msg = "\n{}\n{}".format(sym.name, len(sym.name)*"=")
|
|
|
|
def search(node):
|
|
nonlocal msg
|
|
|
|
while node:
|
|
if sym in node.referenced:
|
|
msg += "\n\n- Referenced at {}:{}:\n\n{}" \
|
|
.format(node.filename, node.linenr, node)
|
|
|
|
if node.list:
|
|
search(node.list)
|
|
|
|
node = node.next
|
|
|
|
search(sym.kconfig.top_node)
|
|
return msg
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.stdout.write(report())
|