summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorUlf Magnusson <ulfalizer@gmail.com>2017-11-09 11:43:13 +0100
committerUlf Magnusson <ulfalizer@gmail.com>2017-11-09 11:43:13 +0100
commit395c2db0e9761def8eb992e3e8068ba2d3ab179c (patch)
tree7b14ac791dbf9d4b9354f1c6149444e090068309 /examples
parent8c978ee0b9c0f7f8406f58d24478a73330512056 (diff)
parent4bffd653148d6fa1c8e626872ae4f445e2b0a24c (diff)
Make Kconfiglib 2 official
Merge in the 'kconfiglib-2-backup' branch.
Diffstat (limited to 'examples')
-rw-r--r--examples/Kmenuconfig102
-rw-r--r--examples/allnoconfig.py96
-rw-r--r--examples/allnoconfig_simpler.py34
-rw-r--r--examples/allyesconfig.py117
-rw-r--r--examples/defconfig.py15
-rw-r--r--examples/defconfig_oldconfig.py28
-rw-r--r--examples/eval_expr.py24
-rw-r--r--examples/find_symbol.py205
-rw-r--r--examples/help_grep.py109
l---------examples/kconfiglib.py1
-rw-r--r--examples/menuconfig.py348
-rw-r--r--examples/print_refs.py13
-rw-r--r--examples/print_sym_info.py61
-rw-r--r--examples/print_tree.py80
-rw-r--r--examples/print_undefined.py15
15 files changed, 1022 insertions, 226 deletions
diff --git a/examples/Kmenuconfig b/examples/Kmenuconfig
new file mode 100644
index 0000000..f1cb67b
--- /dev/null
+++ b/examples/Kmenuconfig
@@ -0,0 +1,102 @@
+mainmenu "Example Kconfig configuration"
+
+config MODULES
+ bool "Enable loadable module support"
+ option modules
+ default y
+
+menu "Bool and tristate symbols"
+
+config BOOL
+ bool "Bool symbol"
+ default y
+
+config BOOL_DEP
+ bool "Dependent bool symbol"
+ depends on BOOL
+
+# Mix it up a bit with an 'if' instead of a 'depends on'
+if BOOL
+
+config TRI_DEP
+ tristate "Dependent tristate symbol"
+ select SELECTED_BY_TRI_DEP
+ imply IMPLIED_BY_TRI_DEP
+
+endif
+
+config TWO_MENU_NODES
+ bool "First prompt"
+ depends on BOOL
+
+config TRI
+ tristate "Tristate symbol"
+
+config TWO_MENU_NODES
+ bool "Second prompt"
+
+comment "These are selected by TRI_DEP"
+
+config SELECTED_BY_TRI_DEP
+ tristate "Tristate selected by TRI_DEP"
+
+config IMPLIED_BY_TRI_DEP
+ tristate "Tristate implied by TRI_DEP"
+
+endmenu
+
+
+menu "String, int, and hex symbols"
+
+config STRING
+ string "String symbol"
+ default "foo"
+
+config INT
+ int "Int symbol"
+ default 747
+
+config HEX
+ hex "Hex symbol"
+ default 0xABC
+
+endmenu
+
+
+menu "Various choices"
+
+choice BOOL_CHOICE
+ bool "Bool choice"
+
+config BOOL_CHOICE_SYM_1
+ bool "Bool choice sym 1"
+
+config BOOL_CHOICE_SYM_2
+ bool "Bool choice sym 2"
+
+endchoice
+
+choice TRI_CHOICE
+ tristate "Tristate choice"
+
+config TRI_CHOICE_SYM_1
+ tristate "Tristate choice sym 1"
+
+config TRI_CHOICE_SYM_2
+ tristate "Tristate choice sym 2"
+
+endchoice
+
+choice OPT_BOOL_CHOICE
+ bool "Optional bool choice"
+ optional
+
+config OPT_BOOL_CHOICE_SYM_1
+ bool "Optional bool choice sym 1"
+
+config OPT_BOOL_CHOICE_SYM_2
+ bool "Optional bool choice sym 2"
+
+endchoice
+
+endmenu
diff --git a/examples/allnoconfig.py b/examples/allnoconfig.py
index 9423352..127c60d 100644
--- a/examples/allnoconfig.py
+++ b/examples/allnoconfig.py
@@ -1,40 +1,62 @@
-# Works like allnoconfig. Automatically verified by the testsuite to generate
-# identical output to 'make allnoconfig' for all ARCHes. The looping is done in
-# case setting one symbol to "n" allows other symbols to be set to "n" (due to
-# dependencies).
+# Works like 'make allnoconfig'. Verified by the test suite to generate
+# identical output to 'make allnoconfig' for all ARCHes.
+#
+# See allnoconfig_simpler.py for a much simpler version. This more roundabout
+# version demonstrates some tree walking and value processing.
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig.py
-import kconfiglib
+from kconfiglib import Kconfig, Symbol, STR_TO_TRI
import sys
-conf = kconfiglib.Config(sys.argv[1])
-
-# Do an initial pass to give allnoconfig_y symbols the user value 'y'. It might
-# be possible to handle this through "successive raising" similarly to the
-# "successive lowering" below too, but keep it simple.
-for sym in conf:
- if sym.get_type() in (kconfiglib.BOOL, kconfiglib.TRISTATE) and \
- sym.is_allnoconfig_y():
- sym.set_user_value('y')
-
-done = False
-while not done:
- done = True
-
- for sym in conf:
- # Choices take care of themselves for allnoconfig, so we only need to
- # worry about non-choice symbols
- if not sym.is_choice_symbol() and not sym.is_allnoconfig_y():
- # If we can assign a value to the symbol (where "n", "m" and "y"
- # are ordered from lowest to highest), then assign the lowest
- # value. lower_bound() returns None for symbols whose values cannot
- # (currently) be changed, as well as for non-bool/tristate symbols.
- lower_bound = sym.get_lower_bound()
- if lower_bound is not None and \
- kconfiglib.tri_less(lower_bound, sym.get_value()):
-
- sym.set_user_value(lower_bound)
- # We just changed the value of some symbol. As this may affect
- # other symbols, keep going.
- done = False
-
-conf.write_config(".config")
+def do_allnoconfig(node):
+ global changed
+
+ # Walk the tree of menu nodes. You can imagine this as going down/into menu
+ # entries in the menuconfig interface, setting each to n (or the lowest
+ # assignable value).
+
+ while node:
+ if isinstance(node.item, Symbol):
+ sym = node.item
+
+ # Is the symbol a non-allnoconfig_y symbol that can be set to a
+ # lower value than its current value?
+ if (not sym.is_allnoconfig_y and
+ sym.assignable and
+ sym.assignable[0] < sym.tri_value):
+
+ # Yup, lower it
+ sym.set_value(sym.assignable[0])
+ changed = True
+
+ # Recursively lower children
+ if node.list:
+ do_allnoconfig(node.list)
+
+ node = node.next
+
+# Parse the Kconfig files
+kconf = Kconfig(sys.argv[1])
+
+# Do an initial pass to set 'option allnoconfig_y' symbols to y
+for sym in kconf.defined_syms:
+ if sym.is_allnoconfig_y:
+ sym.set_value(2)
+
+while 1:
+ # Changing later symbols in the configuration can sometimes allow earlier
+ # symbols to be lowered, e.g. if a later symbol 'select's an earlier
+ # symbol. To handle such situations, we do additional passes over the tree
+ # until we're no longer able to change the value of any symbol in a pass.
+ changed = False
+
+ do_allnoconfig(kconf.top_node)
+
+ # Did the pass change any symbols?
+ if not changed:
+ break
+
+kconf.write_config(".config")
diff --git a/examples/allnoconfig_simpler.py b/examples/allnoconfig_simpler.py
index f3cfe9a..81e701c 100644
--- a/examples/allnoconfig_simpler.py
+++ b/examples/allnoconfig_simpler.py
@@ -1,28 +1,22 @@
# This is a simpler version of allnoconfig.py, corresponding to how the C
-# implementation does it. Setting a user value that's not in the assignable
-# range of the symbol (between get_lower_bound() and get_upper_bound(), or,
-# equivalently, not in get_assignable_values()) is OK; the value will simply
-# get truncated downwards or upwards as determined by the visibility and
-# selects.
+# implementation does it. Verified by the test suite to produce identical
+# output to 'make allnoconfig' for all ARCHes.
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig_simpler.py
-# This version is a bit slower compared allnoconfig.py since Kconfiglib
-# invalidates all dependent symbols for each set_user_value() call. This does not
-# happen for load_config(), which instead invalidates all symbols once after
-# the configuration has been loaded. This is OK for load_config() since nearly
-# all symbols will tend to be affected anyway.
-
-import kconfiglib
+from kconfiglib import Kconfig, BOOL, TRISTATE
import sys
-conf = kconfiglib.Config(sys.argv[1])
+conf = Kconfig(sys.argv[1])
-# Avoid warnings printed by Kconfiglib when assigning a user value with
-# set_user_value() to a symbol that has no prompt (such assignments never have
-# an effect)
-conf.set_print_warnings(False)
+# Avoid warnings printed by Kconfiglib when assigning a value to a symbol that
+# has no prompt. Such assignments never have an effect.
+conf.disable_warnings()
-for sym in conf:
- if sym.get_type() in (kconfiglib.BOOL, kconfiglib.TRISTATE):
- sym.set_user_value("y" if sym.is_allnoconfig_y() else "n")
+for sym in conf.defined_syms:
+ if sym.type in (BOOL, TRISTATE):
+ sym.set_value(2 if sym.is_allnoconfig_y else 0)
conf.write_config(".config")
diff --git a/examples/allyesconfig.py b/examples/allyesconfig.py
index 906343c..1bac713 100644
--- a/examples/allyesconfig.py
+++ b/examples/allyesconfig.py
@@ -1,65 +1,90 @@
-# Works like allyesconfig. This is a bit more involved than allnoconfig as we
-# need to handle choices in two different modes:
+# Works like 'make allyesconfig'. Verified by the test suite to generate output
+# identical to 'make allyesconfig', for all ARCHES.
#
-# "y": One symbol is "y", the rest are "n".
-# "m": Any number of symbols are "m", the rest are "n".
+# This example is implemented a bit differently from allnoconfig.py to
+# demonstrate some other possibilities. A variant similar to
+# allnoconfig_simpler.py could be constructed too.
#
-# Only tristate choices can be in "m" mode. It is safe since the code for two
-# conflicting options will appear as separate modules instead of simultaneously
-# in the kernel.
+# In theory, we need to handle choices in two different modes:
#
-# If a choice can be in "y" mode, it will be. If it can only be in "m" mode
-# (due to dependencies), then all the options will be set to "m".
+# y: One symbol is y, the rest are n
+# m: Any number of symbols are m, the rest are n
#
-# The looping is in case setting one symbol to "y" (or "m") allows the value of
-# other symbols to be raised.
+# Only tristate choices can be in m mode.
+#
+# In practice, no m mode choices appear for allyesconfig as of 4.14, as
+# expected, but we still handle them here for completeness. Here's a convoluted
+# example of how you might get an m-mode choice even during allyesconfig:
+#
+# choice
+# tristate "weird choice"
+# depends on m
+#
+# ...
+#
+# endchoice
+#
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/allyesconfig.py
-import kconfiglib
+from kconfiglib import Kconfig, Choice, STR_TO_TRI
import sys
-conf = kconfiglib.Config(sys.argv[1])
+def all_choices(node):
+ """
+ Returns all choices in the menu tree rooted at 'node'. See the
+ Kconfig.write_config() implementation in kconfiglib.py for an example of
+ how the tree can be walked iteratively instead.
-# Get a list of all symbols that are not in choices
-non_choice_syms = [sym for sym in conf.get_symbols() if
- not sym.is_choice_symbol()]
+ (I was thinking of making a list of choices available directly in the API,
+ but I'm not sure it will always be needed internally, and I'm trying to
+ spam the API with less seldomly-used stuff compared to Kconfiglib 1.)
+ """
+ res = []
-done = False
-while not done:
- done = True
+ while node:
+ if isinstance(node.item, Choice):
+ res.append(node.item)
- # Handle symbols outside of choices
+ if node.list:
+ res.extend(all_choices(node.list))
- for sym in non_choice_syms:
- upper_bound = sym.get_upper_bound()
+ node = node.next
- # See corresponding comment for allnoconfig implementation
- if upper_bound is not None and \
- kconfiglib.tri_less(sym.get_value(), upper_bound):
- sym.set_user_value(upper_bound)
- done = False
+ return res
- # Handle symbols within choices
+kconf = Kconfig(sys.argv[1])
- for choice in conf.get_choices():
+non_choice_syms = [sym for sym in kconf.defined_syms if not sym.choice]
+choices = all_choices(kconf.top_node) # All choices in the configuration
- # Handle choices whose visibility allow them to be in "y" mode
+while True:
+ changed = False
+
+ for sym in non_choice_syms:
+ # Set the symbol to the highest assignable value, unless it already has
+ # that value. sym.assignable[-1] gives the last element in assignable.
+ if sym.assignable and sym.tri_value < sym.assignable[-1]:
+ sym.set_value(sym.assignable[-1])
+ changed = True
- if choice.get_visibility() == "y":
- selection = choice.get_selection_from_defaults()
- if selection is not None and \
- selection is not choice.get_user_selection():
- selection.set_user_value("y")
- done = False
+ for choice in choices:
+ # Same logic as above for choices
+ if choice.assignable and choice.tri_value < choice.assignable[-1]:
+ choice.set_value(choice.assignable[-1])
+ changed = True
- # Handle choices whose visibility only allow them to be in "m" mode.
- # This might happen if a choice depends on a symbol that can only be
- # "m" for example.
+ # For y-mode choices, we just let the choice get its default
+ # selection. For m-mode choices, we set all choice symbols to m.
+ if choice.tri_value == 1:
+ for sym in choice.syms:
+ sym.set_value(1)
- elif choice.get_visibility() == "m":
- for sym in choice.get_symbols():
- if sym.get_value() != "m" and \
- sym.get_upper_bound() != "n":
- sym.set_user_value("m")
- done = False
+ # Do multiple passes until we longer manage to raise any symbols or
+ # choices, like in allnoconfig.py
+ if not changed:
+ break
-conf.write_config(".config")
+kconf.write_config(".config")
diff --git a/examples/defconfig.py b/examples/defconfig.py
index 3e958e2..236db8d 100644
--- a/examples/defconfig.py
+++ b/examples/defconfig.py
@@ -1,17 +1,22 @@
# Works like entering "make menuconfig" and immediately saving and exiting
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/allyesconfig.py
import kconfiglib
import os
import sys
-conf = kconfiglib.Config(sys.argv[1])
+conf = kconfiglib.Kconfig(sys.argv[1])
if os.path.exists(".config"):
+ print("using existing .config")
conf.load_config(".config")
else:
- defconfig = conf.get_defconfig_filename()
- if defconfig is not None:
- print("Using" + defconfig)
- conf.load_config(defconfig)
+ if conf.defconfig_filename is not None:
+ print("using " + conf.defconfig_filename)
+ conf.load_config(conf.defconfig_filename)
conf.write_config(".config")
+print("configuration written to .config")
diff --git a/examples/defconfig_oldconfig.py b/examples/defconfig_oldconfig.py
index 9a85440..84aa134 100644
--- a/examples/defconfig_oldconfig.py
+++ b/examples/defconfig_oldconfig.py
@@ -7,27 +7,31 @@
# yes n | make oldconfig
#
# This came up in https://github.com/ulfalizer/Kconfiglib/issues/15.
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/defconfig_oldconfig.py
import kconfiglib
import sys
-conf = kconfiglib.Config(sys.argv[1])
+kconf = kconfiglib.Kconfig(sys.argv[1])
# Mirrors defconfig
-conf.load_config("arch/x86/configs/x86_64_defconfig")
-conf.write_config(".config")
+kconf.load_config("arch/x86/configs/x86_64_defconfig")
+kconf.write_config(".config")
# Mirrors the first oldconfig
-conf.load_config(".config")
-conf["ETHERNET"].set_user_value('n')
-conf.write_config(".config")
+kconf.load_config(".config")
+kconf.syms["ETHERNET"].set_value(0)
+kconf.write_config(".config")
# Mirrors the second oldconfig
-conf.load_config(".config")
-conf["ETHERNET"].set_user_value('y')
-for s in conf:
- if s.get_user_value() is None and 'n' in s.get_assignable_values():
- s.set_user_value('n')
+kconf.load_config(".config")
+kconf.syms["ETHERNET"].set_value(2)
+for s in kconf.defined_syms:
+ if s.user_value is None and 0 in s.assignable:
+ s.set_value(0)
# Write the final configuration
-conf.write_config(".config")
+kconf.write_config(".config")
diff --git a/examples/eval_expr.py b/examples/eval_expr.py
index edb33e6..36a7e6a 100644
--- a/examples/eval_expr.py
+++ b/examples/eval_expr.py
@@ -1,8 +1,24 @@
-# Evaluates an expression in the context of a configuration. (Here we could
-# load a .config as well.)
+# Evaluates an expression (e.g. "X86_64 || (X86_32 && X86_LOCAL_APIC)") in the
+# context of a configuration. Note that this always yields a tristate value (n,
+# m, or y).
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/eval_expr.py SCRIPT_ARG=<expr>
import kconfiglib
import sys
-conf = kconfiglib.Config(sys.argv[1])
-print(conf.eval("(TRACE_IRQFLAGS_SUPPORT || PPC32) && STACKTRACE_SUPPORT"))
+if len(sys.argv) < 3:
+ print('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=NAME')
+ sys.exit(1)
+
+expr = sys.argv[2]
+
+kconf = kconfiglib.Kconfig(sys.argv[1])
+
+# Enable modules so that m doesn't get demoted to n
+kconf.syms["MODULES"].set_value(2)
+
+print("the expression '{}' evaluates to {}"
+ .format(expr, kconf.eval_string(expr)))
diff --git a/examples/find_symbol.py b/examples/find_symbol.py
new file mode 100644
index 0000000..42677ec
--- /dev/null
+++ b/examples/find_symbol.py
@@ -0,0 +1,205 @@
+# Prints all symbols, choices, menus, and comments that reference a symbol with
+# a particular name in any of their properties or property conditions.
+# Demonstrates expression fetching and walking.
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/find_symbol.py SCRIPT_ARG=<name>
+#
+# Example output for SCRIPT_ARG=X86:
+#
+#
+# Found 452 locations that reference 'X86':
+#
+# ========== Location 1 (init/Kconfig:1122) ==========
+#
+# config SGETMASK_SYSCALL
+# bool
+# prompt "sgetmask/ssetmask syscalls support" if EXPERT
+# default PARISC || MN10300 || BLACKFIN || M68K || PPC || MIPS || X86 || SPARC || CRIS || MICROBLAZE || SUPERH
+# help
+# sys_sgetmask and sys_ssetmask are obsolete system calls
+# no longer supported in libc but still enabled by default in some
+# architectures.
+#
+# If unsure, leave the default option here.
+#
+# ---------- Parent 1 (init/Kconfig:1091) ----------
+#
+# menuconfig EXPERT
+# bool
+# prompt "Configure standard kernel features (expert users)"
+# select DEBUG_KERNEL
+# help
+# This option allows certain base kernel options and settings
+# to be disabled or tweaked. This is for specialized
+# environments which can tolerate a "non-standard" kernel.
+# Only use this if you really know what you are doing.
+#
+# ---------- Parent 2 (init/Kconfig:39) ----------
+#
+# menu "General setup"
+#
+# ========== Location 2 (arch/Kconfig:28) ==========
+#
+# config OPROFILE_EVENT_MULTIPLEX
+# bool
+# prompt "OProfile multiplexing support (EXPERIMENTAL)" if OPROFILE && X86
+# default "n" if OPROFILE && X86
+# help
+# The number of hardware counters is limited. The multiplexing
+# feature enables OProfile to gather more events than counters
+# are provided by the hardware. This is realized by switching
+# between events at a user specified time interval.
+#
+# If unsure, say N.
+#
+# ---------- Parent 1 (arch/Kconfig:15) ----------
+#
+# config OPROFILE
+# ... (tons more lines)
+
+from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT, NOT
+import sys
+
+def expr_contains_sym(expr, sym_name):
+ """
+ Returns True if a symbol (or choice, though that's unlikely) with name
+ 'sym_name' appears in the expression 'expr', and False otherwise.
+
+ Note that "foo" is represented as a constant symbol, like in the C
+ implementation.
+ """
+ # Choice symbols have a Choice instance propagated to the conditions of
+ # their properties, so we need this test rather than
+ # isinstance(expr, Symbol)
+ if not isinstance(expr, tuple):
+ return expr.name == sym_name
+
+ if expr[0] == NOT:
+ return expr_contains_sym(expr[1], sym_name)
+
+ # AND, OR, or relation
+ return expr_contains_sym(expr[1], sym_name) or \
+ expr_contains_sym(expr[2], sym_name)
+
+def sc_references_sym(sc, sym_name):
+ """
+ Returns True if a symbol with name 'sym_name' appears in any of the
+ properties or property conditions of the Symbol or Choice 'sc', and False
+ otherwise.
+ """
+ # Search defaults
+ for default, cond in sc.defaults:
+ if expr_contains_sym(default, sym_name) or \
+ expr_contains_sym(cond, sym_name):
+ return True
+
+ if isinstance(sc, Symbol):
+ # Search selects
+ for select, cond in sc.selects:
+ if select.name == sym_name or \
+ expr_contains_sym(cond, sym_name):
+ return True
+
+ # Search implies
+ for imply, cond in sc.implies:
+ if imply.name == sym_name or \
+ expr_contains_sym(cond, sym_name):
+ return True
+
+ # Search ranges
+ for low, high, cond in sc.ranges:
+ if low.name == sym_name or \
+ high.name == sym_name or \
+ expr_contains_sym(cond, sym_name):
+ return True
+
+ return False
+
+def node_references_sym(node, sym_name):
+ """
+ Returns True if a symbol with name 'sym_name' appears in the prompt
+ condition of the MenuNode 'node' or in any of the properties of a
+ symbol/choice stored in the menu node, and False otherwise.
+
+ For MENU menu nodes, also searches the 'visible if' condition.
+
+ Note that prompts are always stored in menu nodes. This is why a symbol can
+ be defined in multiple locations and have a different prompt in each
+ location. For MENU and COMMENT menu nodes, the prompt holds the menu title
+ or comment text. This organization matches the C implementation.
+ """
+ if node.prompt:
+ # Search the prompt condition
+ if expr_contains_sym(node.prompt[1], sym_name):
+ return True
+
+ if isinstance(node.item, (Symbol, Choice)):
+ # Search symbol or choice
+ return sc_references_sym(node.item, sym_name)
+
+ if node.item == MENU:
+ # Search the 'visible if' condition
+ return expr_contains_sym(node.visibility, sym_name)
+
+ # Comments are already handled by searching the prompt condition, because
+ # 'depends on' gets propagated to its condition. This is why we don't need
+ # to look at the direct dependencies for MENU either.
+
+def nodes_referencing_sym(node, sym_name):
+ """
+ Returns a list of all menu nodes in the menu tree rooted at 'node' that
+ reference a symbol with name 'sym_name' in any of their properties. Also
+ checks the properties of any symbols or choices contained in the menu
+ nodes.
+ """
+ res = []
+
+ while node:
+ if node_references_sym(node, sym_name):
+ res.append(node)
+
+ if node.list:
+ res.extend(nodes_referencing_sym(node.list, sym_name))
+
+ node = node.next
+
+ return res
+
+if len(sys.argv) < 3:
+ print('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=<name>')
+ sys.exit(1)
+
+sym_name = sys.argv[2]
+
+kconf = Kconfig(sys.argv[1])
+nodes = nodes_referencing_sym(kconf.top_node, sym_name)
+
+if not nodes:
+ print("No reference to '{}' found".format(sym_name))
+ sys.exit()
+
+print("Found {} locations that reference '{}':\n".format(len(nodes), sym_name))
+
+for i, node in enumerate(nodes, 1):
+ print("========== Location {} ({}:{}) ==========\n".format(i, node.filename, node.linenr))
+ print(node)
+
+ parent_i = 0
+
+ # Print the parents of the menu node too
+ while True:
+ node = node.parent
+ if node is kconf.top_node:
+ # Don't print the top node. Would say something like the following,
+ # which isn't that interesting:
+ #
+ # menu "Linux/$ARCH $KERNELVERSION Kernel Configuration"
+ break
+
+ parent_i += 1
+
+ print("---------- Parent {} ({}:{}) ----------\n"
+ .format(parent_i, node.filename, node.linenr))
+ print(node)
diff --git a/examples/help_grep.py b/examples/help_grep.py
index 61ac936..01ea5e7 100644
--- a/examples/help_grep.py
+++ b/examples/help_grep.py
@@ -1,49 +1,72 @@
-# Does a case-insensitive search for a string in the help texts for symbols and
-# choices and the titles of menus and comments. Prints the matching items
-# together with their locations and the matching text. Used like
+# Does a case-insensitive search for a regular expression in the help texts of
+# symbols and choices and the prompts of menus and comments. Prints the
+# matching items together with their locations and the matching text.
#
-# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG=<search text>
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG=<regex>
+#
+# Shortened example output for SCRIPT_ARG=general:
+#
+# menu "General setup"
+# location: init/Kconfig:39
+#
+# config SYSVIPC
+# bool
+# prompt "System V IPC"
+# help
+# ...
+# exchange information. It is generally considered to be a good thing,
+# ...
+#
+# location: init/Kconfig:233
+#
+# config BSD_PROCESS_ACCT
+# bool
+# prompt "BSD Process Accounting" if MULTIUSER
+# help
+# ...
+# information. This is generally a good idea, so say Y.
+#
+# location: init/Kconfig:403
+#
+# ...
+
-import kconfiglib
+from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT
+import re
import sys
if len(sys.argv) < 3:
- print('Pass search string with SCRIPT_ARG="search string"')
+ print('Pass the regex with SCRIPT_ARG=regex')
sys.exit(1)
-search_string = sys.argv[2].lower()
-
-conf = kconfiglib.Config(sys.argv[1])
-
-for item in conf.get_symbols() + \
- conf.get_choices() + conf.get_menus() + conf.get_comments():
- if item.is_symbol() or item.is_choice():
- text = item.get_help()
- elif item.is_menu():
- text = item.get_title()
- else:
- # Comment
- text = item.get_text()
-
- # Case-insensitive search
- if text is not None and search_string in text.lower():
- if item.is_symbol() or item.is_choice():
- # Indent lines in help text. (There might be a nicer way. :)
- text = "\n".join([" " + s for s in text.splitlines()])
-
- # Don't worry about symbols/choices defined in multiple locations to
- # keep things simple
- fname, linenr = item.get_def_locations()[0]
- if item.is_symbol():
- print("config {0} at {1}:{2}:\n{3}"
- .format(item.get_name(), fname, linenr, text))
- elif item.is_choice():
- print("choice at {0}:{1}:\n{2}".format(fname, linenr, text))
-
- else:
- # Menu or comment
- fname, linenr = item.get_location()
- if item.is_menu():
- print('menu "{0}" at {1}:{2}'.format(text, fname, linenr))
- else:
- # Comment
- print('comment "{0}" at {1}:{2}'.format(text, fname, linenr))
+
+search = re.compile(sys.argv[2], re.IGNORECASE).search
+
+def search_tree(node):
+ while node:
+ match = False
+
+ if isinstance(node.item, (Symbol, Choice)) and \
+ node.help is not None and search(node.help):
+ print(node.item)
+ match = True
+
+ elif node.item == MENU and search(node.prompt[0]):
+ print('menu "{}"'.format(node.prompt[0]))
+ match = True
+
+ elif node.item == COMMENT and search(node.prompt[0]):
+ print('comment "{}"'.format(node.prompt[0]))
+ match = True
+
+ if match:
+ print("location: {}:{}\n".format(node.filename, node.linenr))
+
+ if node.list:
+ search_tree(node.list)
+
+ node = node.next
+
+kconf = Kconfig(sys.argv[1])
+search_tree(kconf.top_node)
diff --git a/examples/kconfiglib.py b/examples/kconfiglib.py
new file mode 120000
index 0000000..b9dfb64
--- /dev/null
+++ b/examples/kconfiglib.py
@@ -0,0 +1 @@
+../kconfiglib.py \ No newline at end of file
diff --git a/examples/menuconfig.py b/examples/menuconfig.py
new file mode 100644
index 0000000..375b8c8
--- /dev/null
+++ b/examples/menuconfig.py
@@ -0,0 +1,348 @@
+# Implements a simple configuration interface on top of Kconfiglib to
+# demonstrate concepts for building a menuconfig-like. Emulates how the
+# standard menuconfig prints menu entries.
+#
+# Always displays the entire Kconfig tree to keep things as simple as possible
+# (all symbols, choices, menus, and comments).
+#
+# Usage:
+#
+# $ python(3) Kconfiglib/examples/menuconfig.py <Kconfig file>
+#
+# A sample Kconfig is available in Kconfiglib/examples/Kmenuconfig.
+#
+# Here's a notation guide. The notation matches the one used by menuconfig
+# (scripts/kconfig/mconf):
+#
+# [ ] prompt - Bool
+# < > prompt - Tristate
+# {M} prompt - Tristate selected to m. Can only be set to m or y.
+# -*- prompt - Bool/tristate selected to y, pinning it
+# -M- prompt - Tristate selected to m that also has m visibility,
+# pinning it to m
+# (foo) prompt - String/int/hex symbol with value "foo"
+# --> prompt - The selected symbol in a choice in y mode. This
+# syntax is unique to this example.
+#
+# When modules are disabled, the .type attribute of TRISTATE symbols and
+# choices automatically changes to BOOL. This trick is used by the C
+# implementation as well, and gives the expected behavior without having to do
+# anything extra here. The original type is available in .orig_type if needed.
+#
+# The Kconfiglib/examples/Kmenuconfig example uses named choices to be able to
+# refer to choices by name. Named choices are supported in the C tools too, but
+# I don't think I've ever seen them used in the wild.
+#
+# Sample session:
+#
+# $ python Kconfiglib/examples/menuconfig.py Kconfiglib/examples/Kmenuconfig
+#
+# ======== Example Kconfig configuration ========
+#
+# [*] Enable loadable module support (MODULES)
+# Bool and tristate symbols
+# [*] Bool symbol (BOOL)
+# [ ] Dependent bool symbol (BOOL_DEP)
+# < > Dependent tristate symbol (TRI_DEP)
+# [ ] First prompt (TWO_MENU_NODES)
+# < > Tristate symbol (TRI)
+# [ ] Second prompt (TWO_MENU_NODES)
+# *** These are selected by TRI_DEP ***
+# < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP)
+# < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP)
+# String, int, and hex symbols
+# (foo) String symbol (STRING)
+# (747) Int symbol (INT)
+# (0xABC) Hex symbol (HEX)
+# Various choices
+# -*- Bool choice (BOOL_CHOICE)
+# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1)
+# Bool choice sym 2 (BOOL_CHOICE_SYM_2)
+# {M} Tristate choice (TRI_CHOICE)
+# < > Tristate choice sym 1 (TRI_CHOICE_SYM_1)
+# < > Tristate choice sym 2 (TRI_CHOICE_SYM_2)
+# [ ] Optional bool choice (OPT_BOOL_CHOICE)
+#
+# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): BOOL
+# Value for BOOL (available: n, y): n
+#
+# ======== Example Kconfig configuration ========
+#
+# [*] Enable loadable module support (MODULES)
+# Bool and tristate symbols
+# [ ] Bool symbol (BOOL)
+# < > Tristate symbol (TRI)
+# [ ] Second prompt (TWO_MENU_NODES)
+# *** These are selected by TRI_DEP ***
+# < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP)
+# < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP)
+# String, int, and hex symbols
+# (foo) String symbol (STRING)
+# (747) Int symbol (INT)
+# (0xABC) Hex symbol (HEX)
+# Various choices
+# -*- Bool choice (BOOL_CHOICE)
+# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1)
+# Bool choice sym 2 (BOOL_CHOICE_SYM_2)
+# {M} Tristate choice (TRI_CHOICE)
+# < > Tristate choice sym 1 (TRI_CHOICE_SYM_1)
+# < > Tristate choice sym 2 (TRI_CHOICE_SYM_2)
+# [ ] Optional bool choice (OPT_BOOL_CHOICE)
+#
+# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): MODULES
+# Value for MODULES (available: n, y): n
+#
+# ======== Example Kconfig configuration ========
+#
+# [ ] Enable loadable module support (MODULES)
+# Bool and tristate symbols
+# [ ] Bool symbol (BOOL)
+# [ ] Tristate symbol (TRI)
+# [ ] Second prompt (TWO_MENU_NODES)
+# *** These are selected by TRI_DEP ***
+# [ ] Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP)
+# [ ] Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP)
+# String, int, and hex symbols
+# (foo) String symbol (STRING)
+# (747) Int symbol (INT)
+# (0xABC) Hex symbol (HEX)
+# Various choices
+# -*- Bool choice (BOOL_CHOICE)
+# --> Bool choice sym 1 (BOOL_CHOICE_SYM_1)
+# Bool choice sym 2 (BOOL_CHOICE_SYM_2)
+# -*- Tristate choice (TRI_CHOICE)
+# --> Tristate choice sym 1 (TRI_CHOICE_SYM_1)
+# Tristate choice sym 2 (TRI_CHOICE_SYM_2)
+# [ ] Optional bool choice (OPT_BOOL_CHOICE)
+#
+# Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): ^D
+
+from kconfiglib import Kconfig, \
+ Symbol, Choice, MENU, COMMENT, \
+ BOOL, TRISTATE, STRING, INT, HEX, UNKNOWN, \
+ expr_value, \
+ TRI_TO_STR, STR_TO_TRI
+import readline
+import sys
+
+# Python 2/3 compatibility hack
+if sys.version_info[0] < 3:
+ input = raw_input
+
+def indent_print(s, indent):
+ print((" " * indent) + s)
+
+def value_str(sc):
+ """
+ Returns the value part ("[*]", "<M>", "(foo)" etc.) of a menu entry.
+
+ sc: Symbol or Choice.
+ """
+ if sc.type in (STRING, INT, HEX):
+ return "({})".format(sc.str_value)
+
+ # BOOL or TRISTATE
+
+ # The choice mode acts as an upper bound on the visibility of choice
+ # symbols, so we can check the choice symbols' own visibility to see if the
+ # choice is in y mode
+ if isinstance(sc, Symbol) and sc.choice and sc.visibility == 2:
+ # For choices in y mode, print '-->' next to the selected symbol
+ if sc.choice.selection is sc:
+ return "-->"
+ return " "
+
+ tri_val_str = {0: " ", 1: "M", 2: "*"}[sc.tri_value]
+
+ if len(sc.assignable) == 1:
+ # Pinned to a single value
+ return "-{}-".format(tri_val_str)
+
+ if sc.type == BOOL:
+ return "[{}]".format(tri_val_str)
+
+ if sc.type == TRISTATE:
+ if sc.assignable == (1, 2):
+ # m and y available
+ return "{" + tri_val_str + "}" # Gets a bit confusing with .format()
+ return "<{}>".format(tri_val_str)
+
+def node_str(node):
+ """
+ Returns the complete menu entry text for a menu node, or "" for invisible
+ menu nodes. Invisible menu nodes are those that lack a prompt or don't have
+ a satisfied prompt condition.
+
+ Example return value: "[*] Bool symbol (BOOL)"
+
+ The symbol name is printed in parentheses to the right of the prompt. This
+ is so that symbols can easily be referred to in the configuration
+ interface.
+ """
+ if not node.prompt:
+ return ""
+
+ # Even for menu nodes for symbols and choices, it's wrong to check
+ # Symbol.visibility / Choice.visibility here. The reason is that a symbol
+ # (and a choice, in theory) can be defined in multiple locations, giving it
+ # multiple menu nodes, which do not necessarily all have the same prompt
+ # visibility. Symbol.visibility / Choice.visibility is calculated as the OR
+ # of the visibility of all the prompts.
+ prompt, prompt_cond = node.prompt
+ if not expr_value(prompt_cond):
+ return ""
+
+ if node.item == MENU:
+ return " " + prompt
+
+ if node.item == COMMENT:
+ return " *** {} ***".format(prompt)
+
+ # Symbol or Choice
+
+ sc = node.item
+
+ if sc.type == UNKNOWN:
+ # Skip symbols defined without a type
+ return ""
+
+ # {:3} sets the field width to three. Gives nice alignment for empty string
+ # values.
+ res = "{:3} {}".format(value_str(sc), prompt)
+
+ # Don't print the name for unnamed choices (the normal kind)
+ if sc.name is not None:
+ res += " ({})".format(sc.name)
+
+ return res
+
+def print_menuconfig_nodes(node, indent):
+ """
+ Prints a tree with all the menu entries rooted at node. Child menu entries
+ are indented.
+ """
+ while node:
+ string = node_str(node)
+ if string:
+ indent_print(string, indent)
+
+ if node.list:
+ print_menuconfig_nodes(node.list, indent + 8)
+
+ node = node.next
+
+def print_menuconfig(kconf):
+ """
+ Prints all menu entries for the configuration.
+ """
+ # Print the expanded mainmenu text at the top. This is the same as
+ # kconf.top_node.prompt[0], but with variable references expanded.
+ print("\n======== {} ========\n".format(kconf.mainmenu_text))
+
+ print_menuconfig_nodes(kconf.top_node.list, 0)
+ print("")
+
+def get_value_from_user(sc):
+ """
+ Prompts the user for a value for the symbol or choice 'sc'. For
+ bool/tristate symbols and choices, provides a list of all the assignable
+ values.
+ """
+ if not sc.visibility:
+ print(sc.name + " is not currently visible")
+ return False
+
+ prompt = "Value for {}".format(sc.name)
+ if sc.type in (BOOL, TRISTATE):
+ prompt += " (available: {})" \
+ .format(", ".join([TRI_TO_STR[val] for val in sc.assignable]))
+ prompt += ": "
+
+ val_str = input(prompt).strip()
+ if sc.type in (BOOL, TRISTATE):
+ if val_str not in STR_TO_TRI:
+ print("'{}' is not a valid tristate value".format(val_str))
+ return False
+
+ # I was thinking of having set_value() accept "n", "m", "y" as well as
+ # a convenience for BOOL / TRISTATE symbols. Consistently using 0, 1, 2
+ # makes the format clearer though. That's the best format in all ways
+ # except for readability (where it isn't horrible either).
+ val = STR_TO_TRI[val_str]
+ else:
+ val = val_str
+
+ # Automatically add a "0x" prefix for hex symbols, like the menuconfig
+ # interface does. This isn't done when loading .config files, hence why
+ # set_value() doesn't do it automatically.
+ if sc.type == HEX and not val.startswith(("0x", "0X")):
+ val = "0x" + val
+
+ # Let Kconfiglib itself print a warning here if the value is invalid. We
+ # could also disable warnings temporarily with
+ # kconf.disable_warnings() / kconf.enable_warnings() and print our own
+ # warning.
+ return sc.set_value(val)
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ sys.exit("usage: menuconfig.py <Kconfig file>")
+
+ # Load Kconfig configuration files
+ kconf = Kconfig(sys.argv[1])
+
+ # Print the initial configuration tree
+ print_menuconfig(kconf)
+
+ while True:
+ try:
+ cmd = input('Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): ') \
+ .strip()
+ except EOFError:
+ print("")
+ break
+
+ if cmd == "load_config":
+ config_filename = input(".config file to load: ")
+
+ try:
+ kconf.load_config(config_filename)
+ except IOError as e:
+ # Print the (spammy) error from Kconfiglib itself
+ print(e.message + "\n")
+ else:
+ print("Configuration loaded from " + config_filename)
+
+ print_menuconfig(kconf)
+ continue
+
+ if cmd == "write_config":
+ config_filename = input("To this file: ")
+
+ try:
+ kconf.write_config(config_filename)
+ except IOError as e:
+ print(e.message)
+ else:
+ print("Configuration written to " + config_filename)
+
+ continue
+
+ # Assume 'cmd' is the name of a symbol or choice if it isn't one of the
+ # commands above, prompt the user for a value for it, and print the new
+ # configuration tree
+
+ if cmd in kconf.syms:
+ if get_value_from_user(kconf.syms[cmd]):
+ print_menuconfig(kconf)
+
+ continue
+
+ if cmd in kconf.named_choices:
+ if get_value_from_user(kconf.named_choices[cmd]):
+ print_menuconfig(kconf)
+
+ continue
+
+ print("No symbol/choice named '{}' in the configuration"
+ .format(cmd))
diff --git a/examples/print_refs.py b/examples/print_refs.py
deleted file mode 100644
index ea62223..0000000
--- a/examples/print_refs.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# Prints the names of all symbols that reference a particular symbol. (There's
-# also a method get_selected_symbols() for determining just selection
-# relations.)
-
-import kconfiglib
-import sys
-
-conf = kconfiglib.Config(sys.argv[1])
-
-x86 = conf["X86"]
-for sym in conf:
- if x86 in sym.get_referenced_symbols():
- print(sym.get_name())
diff --git a/examples/print_sym_info.py b/examples/print_sym_info.py
index c913358..3ee3c97 100644
--- a/examples/print_sym_info.py
+++ b/examples/print_sym_info.py
@@ -1,18 +1,53 @@
-# Loads a Kconfig and a .config and prints information about a symbol.
+# Loads a Kconfig and a .config and prints a symbol.
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/print_sym_info.py SCRIPT_ARG=<name>
+#
+# Example output for SCRIPT_ARG=MODULES:
+#
+# menuconfig MODULES
+# bool
+# prompt "Enable loadable module support"
+# option modules
+# help
+# Kernel modules are small pieces of compiled code which can
+# be inserted in the running kernel, rather than being
+# permanently built into the kernel. You use the "modprobe"
+# tool to add (and sometimes remove) them. If you say Y here,
+# many parts of the kernel can be built as modules (by
+# answering M instead of Y where indicated): this is most
+# useful for infrequently used options which are not required
+# for booting. For more information, see the man pages for
+# modprobe, lsmod, modinfo, insmod and rmmod.
+#
+# If you say Y here, you will need to run "make
+# modules_install" to put the modules under /lib/modules/
+# where modprobe can find them (you may need to be root to do
+# this).
+#
+# If unsure, say Y.
+#
+# value = n
+# visibility = y
+# currently assignable values: n, y
+# defined at init/Kconfig:1674
-import kconfiglib
+from kconfiglib import Kconfig, TRI_TO_STR
import sys
-# Create a Config object representing a Kconfig configuration. (Any number of
-# these can be created -- the library has no global state.)
-conf = kconfiglib.Config(sys.argv[1])
+if len(sys.argv) < 3:
+ print('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=<name>')
+ sys.exit(1)
-# Load values from a .config file. 'srctree' is an environment variable set by
-# the Linux makefiles to the top-level directory of the kernel tree. It needs
-# to be used here for the script to work with alternative build directories
-# (specified e.g. with O=).
-conf.load_config("$srctree/arch/x86/configs/i386_defconfig")
+kconf = Kconfig(sys.argv[1])
+sym = kconf.syms[sys.argv[2]]
-# Print some information about a symbol. (The Config class implements
-# __getitem__() to provide a handy syntax for getting symbols.)
-print(conf["SERIAL_UARTLITE_CONSOLE"])
+print(sym)
+print("value = " + sym.str_value)
+print("visibility = " + TRI_TO_STR[sym.visibility])
+print("currently assignable values: " +
+ ", ".join([TRI_TO_STR[v] for v in sym.assignable]))
+
+for node in sym.nodes:
+ print("defined at {}:{}".format(node.filename, node.linenr))
diff --git a/examples/print_tree.py b/examples/print_tree.py
index 1405ed5..1a53a3a 100644
--- a/examples/print_tree.py
+++ b/examples/print_tree.py
@@ -1,23 +1,67 @@
-# Prints a tree of all items in the configuration
+# Prints the menu tree of the configuration. Dependencies between symbols can
+# sometimes implicitly alter the menu structure (see kconfig-language.txt), and
+# that's implemented too.
+#
+# Usage:
+#
+# $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py
+#
+# Example output:
+#
+# ...
+# config HAVE_KERNEL_LZO
+# config HAVE_KERNEL_LZ4
+# choice
+# config KERNEL_GZIP
+# config KERNEL_BZIP2
+# config KERNEL_LZMA
+# config KERNEL_XZ
+# config KERNEL_LZO
+# config KERNEL_LZ4
+# config DEFAULT_HOSTNAME
+# config SWAP
+# config SYSVIPC
+# config SYSVIPC_SYSCTL
+# config POSIX_MQUEUE
+# config POSIX_MQUEUE_SYSCTL
+# config CROSS_MEMORY_ATTACH
+# config FHANDLE
+# config USELIB
+# config AUDIT
+# config HAVE_ARCH_AUDITSYSCALL
+# config AUDITSYSCALL
+# config AUDIT_WATCH
+# config AUDIT_TREE
+# menu "IRQ subsystem"
+# config MAY_HAVE_SPARSE_IRQ
+# config GENERIC_IRQ_LEGACY
+# config GENERIC_IRQ_PROBE
+# ...
-import kconfiglib
+from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT
import sys
-def print_with_indent(s, indent):
+def indent_print(s, indent):
print((" " * indent) + s)
-def print_items(items, indent):
- for item in items:
- if item.is_symbol():
- print_with_indent("config {0}".format(item.get_name()), indent)
- elif item.is_menu():
- print_with_indent('menu "{0}"'.format(item.get_title()), indent)
- print_items(item.get_items(), indent + 2)
- elif item.is_choice():
- print_with_indent('choice', indent)
- print_items(item.get_items(), indent + 2)
- elif item.is_comment():
- print_with_indent('comment "{0}"'.format(item.get_text()), indent)
-
-conf = kconfiglib.Config(sys.argv[1])
-print_items(conf.get_top_level_items(), 0)
+def print_items(node, indent):
+ while node:
+ if isinstance(node.item, Symbol):
+ indent_print("config " + node.item.name, indent)
+
+ elif isinstance(node.item, Choice):
+ indent_print("choice", indent)
+
+ elif node.item == MENU:
+ indent_print('menu "{0}"'.format(node.prompt[0]), indent)
+
+ elif node.item == COMMENT:
+ indent_print('comment "{0}"'.format(node.prompt[0]), indent)
+
+ if node.list:
+ print_items(node.list, indent + 2)
+
+ node = node.next
+
+kconf = Kconfig(sys.argv[1])
+print_items(kconf.top_node, 0)
diff --git a/examples/print_undefined.py b/examples/print_undefined.py
deleted file mode 100644
index fb8120b..0000000
--- a/examples/print_undefined.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Prints the names of all symbols that are referenced but never defined in the
-# current configuration together with the locations where they are referenced.
-# Integers being included in the list is not a bug, as these need to be treated
-# as symbols per the design of Kconfig.
-
-import kconfiglib
-import sys
-
-conf = kconfiglib.Config(sys.argv[1])
-
-for sym in conf.get_symbols():
- if not sym.is_defined():
- print(sym.get_name())
- for (filename, linenr) in sym.get_ref_locations():
- print(" {0}:{1}".format(filename, linenr))