diff options
| -rw-r--r-- | examples/allnoconfig.py | 36 | ||||
| -rw-r--r-- | examples/allyesconfig.py | 66 | ||||
| -rw-r--r-- | examples/defconfig.py | 17 | ||||
| -rw-r--r-- | examples/eval_expr.py | 8 | ||||
| -rw-r--r-- | examples/print_refs.py | 13 | ||||
| -rw-r--r-- | examples/print_sym_info.py | 18 | ||||
| -rw-r--r-- | examples/print_tree.py | 23 | ||||
| -rw-r--r-- | examples/print_undefined.py | 15 | ||||
| -rw-r--r-- | kconfiglib.py | 377 |
9 files changed, 221 insertions, 352 deletions
diff --git a/examples/allnoconfig.py b/examples/allnoconfig.py new file mode 100644 index 0000000..2fe151d --- /dev/null +++ b/examples/allnoconfig.py @@ -0,0 +1,36 @@ +# Works like allnoconfig. Verified to produce 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). + +import kconfiglib +import sys + +conf = kconfiglib.Config(sys.argv[1]) + +while True: + 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_item(): + lower_bound = sym.get_lower_bound() + + # If we can assign a lower value to the symbol (where "n", "m" and + # "y" are ordered from lowest to highest), then do so. + # lower_bound() returns None for symbols whose values cannot + # (currently) be changed, as well as for non-bool, non-tristate + # symbols. + if lower_bound is not None and \ + kconfiglib.tri_less(lower_bound, sym.calc_value()): + + sym.set_value(lower_bound) + + # We just changed the value of some symbol. As this may affect + # other symbols, keep going. + done = False + + if done: + break + +conf.write_config(".config") diff --git a/examples/allyesconfig.py b/examples/allyesconfig.py new file mode 100644 index 0000000..12dc19e --- /dev/null +++ b/examples/allyesconfig.py @@ -0,0 +1,66 @@ +# Works like allyesconfig. This is a bit more involved than allnoconfig as we +# need to handle choices in two different modes: +# +# "y": One symbol is "y", the rest are "n". +# "m": Any number of symbols are "m", the rest are "n". +# +# 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. +# +# 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". +# +# The looping is in case setting one symbol to "y" (or "m") allows the value of +# other symbols to be raised. + +import kconfiglib +import sys + +conf = kconfiglib.Config(sys.argv[1]) + +# 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_item()] + +while True: + done = True + + # Handle symbols outside of choices + + for sym in non_choice_syms: + upper_bound = sym.get_upper_bound() + + # See corresponding comment for allnoconfig implementation + if upper_bound is not None and \ + kconfiglib.tri_less(sym.calc_value(), upper_bound): + sym.set_value(upper_bound) + done = False + + # Handle symbols within choices + + for choice in conf.get_choices(): + + # Handle choices whose visibility allow them to be in "y" mode + + 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_value("y") + done = False + + # Handle choices whose visibility only allow them to be in "m" mode + + elif choice.get_visibility() == "m": + for sym in choice.get_items(): + if sym.calc_value() != "m" and \ + sym.get_upper_bound() != "n": + sym.set_value("m") + done = False + + + if done: + break + +conf.write_config(".config") diff --git a/examples/defconfig.py b/examples/defconfig.py new file mode 100644 index 0000000..3ed09fa --- /dev/null +++ b/examples/defconfig.py @@ -0,0 +1,17 @@ +# Works like entering "make menuconfig" and immediately saving and exiting + +import kconfiglib +import os +import sys + +conf = kconfiglib.Config(sys.argv[1]) + +if os.path.exists(".config"): + conf.load_config(".config") +else: + defconfig = conf.get_defconfig_filename() + if defconfig is not None: + print "Using " + defconfig + conf.load_config(defconfig) + +conf.write_config(".config") diff --git a/examples/eval_expr.py b/examples/eval_expr.py new file mode 100644 index 0000000..f8e0f65 --- /dev/null +++ b/examples/eval_expr.py @@ -0,0 +1,8 @@ +# Evaluates an expression in the context of a configuration. (Here we could +# load a .config as well.) + +import kconfiglib +import sys + +conf = kconfiglib.Config(sys.argv[1]) +print conf.eval("(TRACE_IRQFLAGS_SUPPORT || PPC32) && STACKTRACE_SUPPORT") diff --git a/examples/print_refs.py b/examples/print_refs.py new file mode 100644 index 0000000..b2d9f5f --- /dev/null +++ b/examples/print_refs.py @@ -0,0 +1,13 @@ +# 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 new file mode 100644 index 0000000..8c69cac --- /dev/null +++ b/examples/print_sym_info.py @@ -0,0 +1,18 @@ +# Loads a Kconfig and a .config and prints information about a symbol. + +import kconfiglib +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]) + +# 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") + +# Print some information about a symbol. (The Config class implements +# __getitem__() to provide a handy syntax for getting symbols.) +print conf["SERIAL_UARTLITE_CONSOLE"] diff --git a/examples/print_tree.py b/examples/print_tree.py new file mode 100644 index 0000000..35ad23e --- /dev/null +++ b/examples/print_tree.py @@ -0,0 +1,23 @@ +# Prints a tree of all items in the configuration + +import kconfiglib +import sys + +def print_with_indent(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) diff --git a/examples/print_undefined.py b/examples/print_undefined.py new file mode 100644 index 0000000..82a29d3 --- /dev/null +++ b/examples/print_undefined.py @@ -0,0 +1,15 @@ +# 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) diff --git a/kconfiglib.py b/kconfiglib.py index 9300021..8cdb543 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -2,18 +2,21 @@ # information from Kconfig-based configuration systems. To view the # documentation, run # -# $ pydoc kconfiglib +# $ pydoc kconfiglib # # or, if you prefer HTML, # -# $ pydoc -w kconfiglib +# $ pydoc -w kconfiglib # -# By Ulf "Ulfalizer" Magnusson. +# The examples/ subdirectory contains examples, to be run with e.g. +# +# $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py +# +# Look in kconfigtest.py for the test suite. """ -Kconfiglib is a Python library for scripting, debugging, and extracting -information from Kconfig-based configuration systems. Features include the -following: +Kconfiglib is a Python library for scripting and extracting information from +Kconfig-based configuration systems. Features include the following: - Symbol values and properties can be looked up and values assigned programmatically. @@ -31,368 +34,38 @@ following: Linux 2.6.38-rc3. * Also generates a .config that is character-for-character identical to the one generated by mconf for all architectures when no .config is supplied. - * The 'make allyesconfig' and 'make allnoconfig' implementations below + * The 'make allyesconfig' and 'make allnoconfig' implementations in the generate output character-for-character identical to the C implementation for all architectures. - See scripts/kconfig/kconfigtest.py for the Kconfiglib test suite. +For the Linux kernel, scripts are run using -For the Linux kernel, scripts should be run with + $ make scriptconfig SCRIPT=<path to script> -$ make scriptconfig SCRIPT=<path to script> +This ensures that needed environment variables (SRCARCH, ARCH, srctree, +KERNELVERSION, etc.) are set up correctly. Alternative architectures can be +specified like for other 'make *config' targets: -to ensure that the environment (SRCARCH, ARCH, and KERNELVERSION) is set up -correctly. Alternative architectures can be specified like for other 'make -*config' targets: + $ make scriptconfig ARCH=mips SCRIPT=<path to script> -$ make scriptconfig ARCH=mips SCRIPT=<path to script> - -The script will receive the name of the Kconfig file to load in sys.argv[1]. (As +The script will receive the name of the Kconfig file to load in sys.argv[1]. As of Linux 2.6.38-rc3 this is always "Kconfig" from the kernel top-level -directory.) +directory. -To get an interactive Python prompt with Kconfiglib preloaded, use +To get an interactive Python prompt with Kconfiglib preloaded and a Config +object 'c' created, use -$ make iscriptconfig [ARCH=<architecture>] + $ make iscriptconfig [ARCH=<architecture>] Kconfiglib requires Python 2. For (i)scriptconfig the command to run the Python interpreter can be passed in the environment variable PYTHONCMD (defaults to -'python'). - -Learning to use the library is probably easiest by looking at a few examples, -reading the documentation, and experimenting. The API is designed to be -intuitive and easy to use. - -=============================================================================== -Example 1: Load a configuration and a .config and print information about a - symbol. - -import kconfiglib -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]) - -# 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") - -# Print some information about a symbol. (The Config class implements -# __getitem__() to provide a handy syntax for getting symbols.) -print conf["SERIAL_UARTLITE_CONSOLE"] - -Output for ARCH=i386: -Symbol SERIAL_UARTLITE_CONSOLE -Type : bool -Value : "n" -User value : (no user value) -Visibility : "n" -Is choice item : false -Is defined : true -Is from env. : false -Is special : false -Prompts: - "Support for console on Xilinx uartlite serial port" if SERIAL_UARTLITE = y (value: "n") -Default values: - (no default values) -Selects: - SERIAL_CORE_CONSOLE if SERIAL_UARTLITE = y (value: "n") -Reverse dependencies: - (no reverse dependencies) -Additional dependencies from enclosing menus and if's: - HAS_IOMEM (value: "y") -Locations: drivers/serial/Kconfig:913 - -=============================================================================== -Example 2: Evaluate an expression in the context of a configuration. (Here we - could load a .config as well.) - -import kconfiglib -import sys - -conf = kconfiglib.Config(sys.argv[1]) -print conf.eval("(TRACE_IRQFLAGS_SUPPORT || PPC32) && STACKTRACE_SUPPORT") - -Output for ARCH=mips: -y - -=============================================================================== -Example 3: Print 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) - -Output for ARCH=i386: -MACH_NET2BIG_V2 - drivers/leds/Kconfig:365 -MACH_OMAP3517EVM - sound/soc/omap/Kconfig:84 -ARCH_OMAP16XX - drivers/pcmcia/Kconfig:271 - drivers/char/hw_random/Kconfig:117 - drivers/watchdog/Kconfig:210 - drivers/rtc/Kconfig:694 -SOC_JZ4740 - sound/soc/codecs/Kconfig:30 -MACH_AT91SAM9261EK - drivers/video/Kconfig:1055 -PPC_83xx - drivers/mtd/nand/Kconfig:463 - drivers/watchdog/Kconfig:951 - drivers/usb/Kconfig:58 - drivers/edac/Kconfig:221 -PPC_PSERIES - init/Kconfig:999 - drivers/pci/hotplug/Kconfig:146 - drivers/scsi/Kconfig:964 - drivers/scsi/Kconfig:975 - drivers/scsi/Kconfig:989 - drivers/net/Kconfig:1353 - drivers/serial/Kconfig:1261 - drivers/char/Kconfig:628 - drivers/char/Kconfig:712 - drivers/char/Kconfig:729 -... (lots more) - -=============================================================================== -Example 4: Print 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() - -Output for ARCH=i386: -AUDITSYSCALL -PCSPKR_PLATFORM -OPROFILE_EVENT_MULTIPLEX -GCOV_PROFILE_ALL -SCHED_OMIT_FRAME_POINTER -MEMORY_HOTPLUG -PM_TRACE_RTC -ACPI -ACPI_AC -ACPI_BATTERY -ACPI_VIDEO -ACPI_PROCESSOR_AGGREGATOR -ACPI_NUMA -X86_PM_TIMER -ACPI_SBS -ACPI_APEI -ACPI_APEI_GHES -INTEL_IDLE -XEN_PCIDEV_FRONTEND -EISA_VLB_PRIMING -EISA_VIRTUAL_ROOT -HOTPLUG_PCI_COMPAQ -HOTPLUG_PCI_IBM -HOTPLUG_PCI_CPCI_ZT5550 -HOTPLUG_PCI_CPCI_GENERIC -MTD_SC520CDP -... (lots more) - -=============================================================================== -Example 5: Print a tree of all items in the configuration. - -import kconfiglib -import sys - -def print_with_indent(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) - -Output for ARCH=i386: -... -config ARCH -config KERNELVERSION -config CONSTRUCTORS -config HAVE_IRQ_WORK -config IRQ_WORK -menu "General setup" - config EXPERIMENTAL - config BROKEN - config BROKEN_ON_SMP - config LOCK_KERNEL - config INIT_ENV_ARG_LIMIT - config CROSS_COMPILE - config LOCALVERSION - config LOCALVERSION_AUTO - config HAVE_KERNEL_GZIP - config HAVE_KERNEL_BZIP2 - config HAVE_KERNEL_LZMA - config HAVE_KERNEL_XZ - config HAVE_KERNEL_LZO - choice - config KERNEL_GZIP - config KERNEL_BZIP2 - config KERNEL_LZMA - config KERNEL_XZ - config KERNEL_LZO - config SWAP - config SYSVIPC - config SYSVIPC_SYSCTL - config POSIX_MQUEUE - config POSIX_MQUEUE_SYSCTL - config BSD_PROCESS_ACCT - config BSD_PROCESS_ACCT_V3 -... - -=============================================================================== -Example 6: This does the same thing as entering "make menuconfig" and - immediately saving and exiting. - -import kconfiglib -import os -import sys - -conf = kconfiglib.Config(sys.argv[1]) - -if os.path.exists(".config"): - conf.load_config(".config") -else: - defconfig = conf.get_defconfig_filename() - if defconfig is not None: - print "Using " + defconfig - conf.load_config(defconfig) - -conf.write_config(".config") - -=============================================================================== -Example 7: As a more complex example, this is a reimplementation of allnoconfig - (verified to produce 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). - -import kconfiglib -import sys - -conf = kconfiglib.Config(sys.argv[1]) - -while True: - 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_item(): - lower_bound = sym.get_lower_bound() - - # If we can assign a lower value to the symbol (where "n", "m" and - # "y" are ordered from lowest to highest), then do so. - # lower_bound() returns None for symbols whose values cannot - # (currently) be changed, as well as for non-bool, non-tristate - # symbols. - if lower_bound is not None and \\ - kconfiglib.tri_less(lower_bound, sym.calc_value()): - - sym.set_value(lower_bound) - - # We just changed the value of some symbol. As this may affect - # other symbols, keep going. - done = False - - if done: - break - -conf.write_config(".config") - -=============================================================================== -Example 8: here's allyesconfig (also verified), which is a bit more involved - as we need to handle choices in two different modes ("y", i.e. - one-is-y-rest-is-n, and "m", i.e. - any-number-of-symbols-are-m-rest-are-n). The looping is in case - setting one symbol to "y" (or "m") allows the value of other symbols - to be raised. - -import kconfiglib -import sys - -conf = kconfiglib.Config(sys.argv[1]) - -# 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_item()] - -while True: - done = True - - # Handle symbols outside of choices - - for sym in non_choice_syms: - upper_bound = sym.get_upper_bound() - - # See corresponding comment for allnoconfig implementation - if upper_bound is not None and \\ - kconfiglib.tri_less(sym.calc_value(), upper_bound): - sym.set_value(upper_bound) - done = False - - # Handle symbols within choices - - for choice in conf.get_choices(): - - # Handle choices whose visibility allow them to be in "y" mode - - 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_value("y") - done = False - - # Handle choices whose visibility only allow them to be in "m" mode - - elif choice.get_visibility() == "m": - for sym in choice.get_items(): - if sym.calc_value() != "m" and \\ - sym.get_upper_bound() != "n": - sym.set_value("m") - done = False - - - if done: - break +'python'; PyPy works too and is a bit faster). -conf.write_config(".config") +Look in the examples/ subdirectory for examples. +Look in kconfigtest.py for the test suite. -Credits: written by Ulf "Ulfalizer" Magnusson +Credits: Written by Ulf "Ulfalizer" Magnusson Send bug reports, suggestions (any missing APIs that would make your life easier?) and other feedback to kconfiglib@gmail.com .""" |
