Package: kconfiglib
Table of contentsNewsDependency loop with recent linux-next kernelswindows-cursesis no longer automatically installed on WindowsOverviewInstallationInstallation with pipManual installationInstallation for the Linux kernelPython version compatibility (2.7/3.2+)Getting startedUsing.configfiles as Make inputUseful helper macrosIncremental buildingLibrary documentationLibrary featuresKconfig extensionsOther featuresMenuconfig interfacesExamplesExample scriptsReal-world examplesSamplemake iscriptconfigsessionTest suiteNotesThanksLicenseNewsDependency loop with recent linux-next kernelsTo fix issues with dependency loops on recent linux-next kernels, applythis
patch. Hopefully,
it will be inlinux-nextsoon.windows-cursesis no longer automatically installed on WindowsStarting with Kconfiglib 13.0.0, thewindows-cursespackage is no longer
automatically installed on Windows, and needs to be installed manually for the
terminalmenuconfigto work.This fixes installation of Kconfiglib on MSYS2, which is not compatible withwindows-curses. Seethis issue.Themenuconfignow shows a hint re. installingwindows-curseswhen thecursesmodule can’t be imported on Windows.Sorry if this change caused problems!OverviewKconfiglib is aKconfigimplementation in Python 2/3. It started out as a helper library, but now has a
enough functionality to also work well as a standalone Kconfig implementation
(includingterminal and GUI menuconfig interfacesandKconfig extensions).The entire library is contained inkconfiglib.py. The
bundled scripts are implemented on top of it. Implementing your own scripts
should be relatively easy, if needed.Kconfiglib is used exclusively by e.g. theZephyr,esp-idf, andACRNprojects. It is also used for many small helper
scripts in various projects.Since Kconfiglib is based around a library, it can be used e.g. to generate aKconfig cross-reference, using
the same robust Kconfig parser used for other Kconfig tools, instead of brittle
ad-hoc parsing. The documentation generation script can be foundhere.Kconfiglib implements the recently addedKconfig preprocessor.
For backwards compatibility, environment variables can be referenced both as$(FOO)(the new syntax) and as$FOO(the old syntax). The old syntax is
deprecated, but will probably be supported for a long time, as it’s needed to
stay compatible with older Linux kernels. The major version will be increased
if support is ever dropped. Using the old syntax with an undefined environment
variable keeps the string as is.Note: Seethis issueif
you run into a “macro expanded to blank string” error with kernel 4.18+.Seethis pagefor some
Kconfig tips and best practices.InstallationInstallation with pipKconfiglib is available onPyPIand can be
installed with e.g.$ pip(3) install kconfiglibMicrosoft Windows is supported.Thepipinstallation will give you both the base library and the following
executables. All but two (genconfigandsetconfig) mirror functionality
available in the C tools.menuconfigguiconfigoldconfigolddefconfigsavedefconfigdefconfigalldefconfigallnoconfigallmodconfigallyesconfiglistnewconfiggenconfigsetconfiggenconfigis intended to be run at build time. It generates a C header from
the configuration and (optionally) information that can be used to rebuild only
files that reference Kconfig symbols that have changed value.Starting with Kconfiglib version 12.2.0, all utilities are compatible with both
Python 2 and Python 3. Previously,menuconfig.pyonly ran under Python 3
(i.e., it’s now more backwards compatible than before).Note:If you install Kconfiglib withpip’s--userflag, make sure
that yourPATHincludes the directory where the executables end up. You can
list the installed files withpip(3) show-fkconfiglib.All releases have a corresponding tag in the git repository, e.g.v14.1.0(the latest version).Semantic versioningis used. There’s been ten small
changes to the behavior of the API, a Windows packaging change, and a hashbang
change to usepython3(1,2,3,4,5,6,7,8,9,10,Windows packaging change,Python 3 hashbang change),
which is why the major version is at 14 rather than 2. I do major version bumps
for all behavior changes, even tiny ones, and most of these were fixes for baby
issues in the early days of the Kconfiglib 2 API.Manual installationJust dropkconfiglib.pyand the scripts you want somewhere. There are no
third-party dependencies, but the terminalmenuconfigwon’t work on Windows
unless a package likewindows-cursesis installed.Installation for the Linux kernelSee the module docstring at the top ofkconfiglib.py.Python version compatibility (2.7/3.2+)Kconfiglib and all utilities run under both Python 2.7 and Python 3.2 and
later. The code mostly uses basic Python features and has no third-party
dependencies, so keeping it backwards-compatible is pretty low effort.The 3.2 requirement comes fromargparse.format()with unnumbered{}is used as well.A recent Python 3 version is recommended if you have a choice, as it’ll give
you better Unicode handling.Getting startedInstallthe library and the utilities.WriteKconfigfiles that describe the available configuration options. Seethis pagefor some
general Kconfig advice.Generate an initial configuration with e.g.menuconfig/guiconfigoralldefconfig. The configuration is saved as.configby default.For more advanced projects, thedefconfigutility can be used to
generate the initial configuration from an existing configuration file.
Usually, this existing configuration file would be a minimal configuration
file, as generated by e.g.savedefconfig.Rungenconfigto generate a header file. By default, it is saved asconfig.h.Normally,genconfigwould be run automatically as part of the build.Before writing a header file or other configuration output, Kconfiglib
compares the old contents of the file against the new contents. If there’s
no change, the write is skipped. This avoids updating file metadata like the
modification time, and might save work depending on your build setup.Adding new configuration output formats should be relatively straightforward.
See the implementation ofwrite_config()inkconfiglib.py.
The documentation for theSymbol.config_stringproperty has some tips as
well.To update an old.configfile after the Kconfig files have changed (e.g.
to add new options), runoldconfig(prompts for values for new options)
orolddefconfig(gives new options their default value). Entering themenuconfigorguiconfiginterface and saving the configuration will
also update it (the configuration interfaces always prompt for saving
on exit if it would modify the contents of the.configfile).Due to Kconfig semantics, simply loading an old.configfile performs an
implicitolddefconfig, so building will normally not be affected by
having an outdated configuration.Whenever.configis overwritten, the previous version of the file is saved
to.config.old(or, more generally, to$KCONFIG_CONFIG.old).Using.configfiles as Make input.configfiles use Make syntax and can be included directly in Makefiles to
read configuration values from there. This is whyn-valuedbool/tristatevalues are written out as# CONFIG_FOO is not set(a
Make comment) in.config, allowing them to be tested withifdefin
Make.If you make use of this, you might want to pass--config-out<filename>togenconfigand include the configuration file it generates instead of
including.configdirectly. This has the advantage that the generated
configuration file will always be a “full” configuration file, even if.configis outdated. Otherwise, it might be necessary to runold(def)configormenuconfig/guiconfigbefore rebuilding with an
outdated.config.If you use--sync-depsto generate incremental build information, you can
includedeps/auto.confinstead, which is also a full configuration file.Useful helper macrosTheinclude/linux/kconfig.hheader in the Linux kernel defines some useful helper macros for testing
Kconfig configuration values.IS_ENABLED()is generally useful, allowing configuration values to be
tested inifstatements with no runtime overhead.Incremental buildingSee the docstring forKconfig.sync_deps()inkconfiglib.pyfor hints
on implementing incremental builds (rebuilding just source files that reference
changed configuration values).Running thescripts/basic/fixdep.ctool from the kernel on the output ofgcc-MD<source file>might give you an idea of how it all fits together.Library documentationKconfiglib comes with extensive documentation in the form of docstrings. To view it, run e.g.
the following command:$pydoc(3)kconfiglibFor HTML output, add-w:$pydoc(3)-wkconfiglibThis will also work after installing Kconfiglib withpip(3).Documentation for other modules can be viewed in the same way (though a plain--helpwill work when they’re run as executables):$pydoc(3)menuconfig/guiconfig/...A good starting point for learning the library is to read the module docstring
(which you could also just read directly at the beginning ofkconfiglib.py). It
gives an introduction to symbol values, the menu tree, and expressions.After reading the module docstring, a good next step is to read theKconfigclass documentation, and then the documentation for theSymbol,Choice,
andMenuNodeclasses.Please tell me if something is unclear or can be explained better.Library featuresKconfiglib can do the following, among other things:Programmatically get and set symbol valuesSeeallnoconfig.pyandallyesconfig.py,
which are automatically verified to produce identical output to the standardmake allnoconfigandmake allyesconfig.Read and write .config and defconfig filesThe generated.configanddefconfig(minimal configuration) files are
character-for-character identical to what the C implementation would generate
(except for the header comment). The test suite relies on this, as it
compares the generated files.Write C headersThe generated headers use the same format asinclude/generated/autoconf.hfrom the Linux kernel. Output for symbols appears in the order that they’re
defined, unlike in the C tools (where the order depends on the hash table
implementation).Implement incremental buildsThis uses the same scheme as theinclude/configdirectory in the kernel:
Symbols are translated into files that are touched when the symbol’s value
changes between builds, which can be used to avoid having to do a full
rebuild whenever the configuration is changed.See thesync_deps()function for more information.Inspect symbolsPrinting a symbol or other item (which calls__str__()) returns its
definition in Kconfig format. This also works for symbols defined in multiple
locations.A helpful__repr__()is  on all objects too.All__str__()and__repr__()methods are deliberately implemented
with just public APIs, so all symbol information can be fetched separately as
well.Inspect expressionsExpressions use a simple tuple-based format that can be processed manually
if needed. Expression printing and evaluation functions are provided,
implemented with public APIs.Inspect the menu treeThe underlying menu tree is exposed, including submenus created implicitly
from symbols depending on preceding symbols. This can be used e.g. to
implement menuconfig-like functionality.Seemenuconfig.py/guiconfig.pyand the
minimalisticmenuconfig_example.pyexample.Kconfig extensionsThe following Kconfig extensions are available:sourcesupports glob patterns and includes each matching file. A pattern
is required to match at least one file.A separateosourcestatement is available for cases where it’s okay for
the pattern to match no files (in which caseosourceturns into a no-op).A relativesourcestatement (rsource) is available, where file paths
are specified relative to the directory of the current Kconfig file. Anorsourcestatement is available as well, analogous toosource.Preprocessor user functions can be defined in Python, which makes it simple
to integrate information from existing Python tools into Kconfig (e.g. to
have Kconfig symbols depend on hardware information stored in some other
format).See theKconfig extensionssection in thekconfiglib.pymodule docstring for more information.def_int,def_hex, anddef_stringare available in addition todef_boolanddef_tristate, allowingint,hex, andstringsymbols to be given a type and a default at the same time.These can be useful in projects that make use of symbols defined in multiple
locations, and remove some Kconfig inconsistency.Environment variables are expanded directly in e.g.sourceandmainmenustatements, meaningoption envsymbols are redundant.This is the standard behavior with the newKconfig preprocessor,
which Kconfiglib implements.option envsymbols are accepted but ignored, which leads the caveat that
they must have the same name as the environment variables they reference
(Kconfiglib warns if the names differ). This keeps Kconfiglib compatible with
older Linux kernels, where the name of theoption envsymbol always
matched the environment variable. Compatibility with older Linux kernels is
the main reasonoption envis still supported.The C tools have dropped support foroption env.Two extra optional warnings can be enabled by setting environment variables,
covering cases that are easily missed when making changes to Kconfig files:KCONFIG_WARN_UNDEF: If set toy, warnings will be generated for all
references to undefined symbols within Kconfig files. The only gotcha is
that all hex literals must be prefixed with0xor0X, to make it
possible to distinguish them from symbol references.Some projects (e.g. the Linux kernel) use multiple Kconfig trees with many
shared Kconfig files, leading to some safe undefined symbol references.KCONFIG_WARN_UNDEFis useful in projects that only have a single
Kconfig tree though.KCONFIG_STRICTis an older alias for this environment variable,
supported for backwards compatibility.KCONFIG_WARN_UNDEF_ASSIGN: If set toy, warnings will be generated
for all assignments to undefined symbols within.configfiles. By
default, no such warnings are generated.This warning can also be enabled/disabled by settingKconfig.warn_assign_undeftoTrue/False.Other featuresSingle-file implementationThe entire library is contained inkconfiglib.py.The tools implemented on top of it are one file each.Robust and highly compatible with the C Kconfig toolsThetest suiteautomatically compares output from Kconfiglib and the C tools
by diffing the generated.configfiles for the real kernel Kconfig and
defconfig files, for all ARCHes.This currently involves comparing the output for 36 ARCHes and 498 defconfig
files (or over 18000 ARCH/defconfig combinations in “obsessive” test suite
mode). All tests are expected to pass.A comprehensive suite of selftests is included as well.Not horribly slow despite being a pure Python implementationTheallyesconfig.pyscript currently runs in about 1.3 seconds on the Linux kernel on a Core i7
2600K (with a warm file cache), including themakeoverhead frommake scriptconfig. Note that the Linux kernel Kconfigs are absolutely massive
(over 14k symbols for x86) compared to most projects, and also have overhead
from running shell commands via the Kconfig preprocessor.Kconfiglib is especially speedy in cases where multiple.configfiles
need to be processed, because theKconfigfiles will only need to be parsed
once.For long-running jobs,PyPygives a big performance
boost. CPython is faster for short-running jobs as PyPy needs some time to
warm up.Kconfiglib also works well with themultiprocessingmodule. No global state is kept.Generates more warnings than the C implementationGenerates the same warnings as the C implementation, plus additional ones.
Also detects dependency andsourceloops.All warnings point out the location(s) in theKconfigfiles where a
symbol is defined, where applicable.Unicode supportUnicode characters in string literals inKconfigand.configfiles are
correctly handled. This support mostly comes for free from Python.Windows supportNothing Linux-specific is used. Universal newlines mode is used for both
Python 2 and Python 3.TheZephyrproject uses Kconfiglib to
generate.configfiles and C headers on Linux as well as Windows.Internals that (mostly) mirror the C implementationWhile being simpler to understand and tweak.Menuconfig interfacesThree configuration interfaces are currently available:menuconfig.pyis a terminal-based configuration interface implemented using the standard
Pythoncursesmodule.xconfigfeatures like showing invisible symbols and
showing symbol names are included, and it’s possible to jump directly to a symbol
in the menu tree (even if it’s currently invisible).There is now also a show-help mode that shows the help text of the currently
selected symbol in the help window at the bottom.Starting with Kconfiglib 12.2.0,menuconfig.pyruns under both Python 2
and Python 3 (previously, it only ran under Python 3, so this was a
backport). Running it under Python 3 provides better support for Unicode text
entry (get_wch()is not available in thecursesmodule on Python 2).There are no third-party dependencies on *nix. On Windows,
thecursesmodules is not available by default, but support
can be added by installing thewindows-cursespackage:$pipinstallwindows-cursesThis uses wheels built fromthis repository, which is in turn
based on Christoph Gohlke’sPython Extension Packages for Windows.See the docstring at the top ofmenuconfig.pyfor
more information about the terminal menuconfig implementation.guiconfig.pyis a
graphical configuration interface written inTkinter. Likemenuconfig.py,
it supports showing all symbols (with invisible symbols in red) and jumping
directly to symbols. Symbol values can also be changed directly from the
jump-to dialog.When single-menu mode is enabled, a single menu is shown at a time, like in
the terminal menuconfig. Only this mode distinguishes between symbols defined
withconfigand symbols defined withmenuconfig.guiconfig.pyhas been tested on X11, Windows, and macOS, and is
compatible with both Python 2 and Python 3.Despite being part of the Python standard library,tkinteroften isn’t
included by default in Python installations on Linux. These commands will
install it on a few different distributions:Ubuntu:sudo apt installpython-tk/sudo apt installpython3-tkFedora:dnf installpython2-tkinter/dnf installpython3-tkinterArch:sudo pacman-StkClear Linux:sudo swupdbundle-addpython3-tclScreenshot below, with show-all mode enabled and the jump-to dialog open:To avoid having to carry around a bunch of GIFs, the image data is embedded
inguiconfig.py. To use separate GIF files instead, change_USE_EMBEDDED_IMAGEStoFalseinguiconfig.py. The image files
can be found in thescreenshotsbranch.I did my best with the images, but some are definitely only art adjacent.
Touch-ups are welcome. :)pymenuconfig, built byRomaVis, is an older portable Python 2/3 TkInter
menuconfig implementation.Screenshot below:While working on the terminal menuconfig implementation, I added a few APIs
to Kconfiglib that turned out to be handy.pymenuconfigpredatesmenuconfig.pyandguiconfig.py, and so didn’t have them available.
Blame me for any workarounds.ExamplesExample scriptsTheexamples/directory contains some simple example scripts. Among these are the following ones. Make sure you run them with the latest version of Kconfiglib, as they might make use of newly added features.eval_expr.pyevaluates an expression in the context of a configuration.find_symbol.pysearches through expressions to find references to a symbol, also printing a “backtrace” with parents for each reference found.help_grep.pysearches for a string in all help texts.print_tree.pyprints a tree of all configuration items.print_config_tree.pyis similar toprint_tree.py, but dumps the tree as it would appear inmenuconfig, including values. This can be handy for visually diffing between.configfiles and different versions ofKconfigfiles.list_undefined.pyfinds references to symbols that are not defined by any architecture in the Linux kernel.merge_config.pymerges configuration fragments to produce a complete .config, similarly toscripts/kconfig/merge_config.shfrom the kernel.menuconfig_example.pyimplements a configuration interface that uses notation similar tomake menuconfig. It’s deliberately kept as simple as possible to demonstrate just the core concepts.Real-world exampleskconfig.pyfrom theZephyrproject handles.configand header file generation, also doing configuration fragment
merginggenrest.pygenerates a Kconfig symbol cross-reference, which can be viewedhereCMake and IDE integrationfrom
the ESP-IDF project, via a configuration server program.A script for turning on USB-related options,
from thesyzkallerproject.Various automated checks,
including a check for references to undefined Kconfig symbols in source code.
See theKconfigCheckclass.Various utilitiesfrom theACRNprojectThese use the older Kconfiglib 1 API, which was clunkier and not as general
(functions instead of properties, no direct access to the menu structure or
properties, uglier__str__()output):genboardscfg.pyfromDas U-Bootgenerates some sort of legacy board database by pulling information from a newly added Kconfig-based configuration system (as far as I understand it :).gen-manual-lists.pygenerated listings for an appendix in theBuildrootmanual. (The listing has since been removed.)gen_kconfig_doc.pyfrom theesp-idfproject generates documentation from Kconfig files.SConfbuilds an interactive configuration interface (likemenuconfig) on top of Kconfiglib, for use e.g. withSCons.kconfig-diff.py– a script bydubiousjimthat compares kernel configurations.Originally, Kconfiglib was used in chapter 4 of mymaster’s thesisto automatically generate a “minimal” kernel for a given system. Parts of it bother me a bit now, but that’s how it goes with old work.Samplemake iscriptconfigsessionThe following log should give some idea of the functionality available in the API:$ make iscriptconfig
A Kconfig instance 'kconf' for the architecture x86 has been created.
>>> kconf  # Calls Kconfig.__repr__()
<configuration with 13711 symbols, main menu prompt "Linux/x86 4.14.0-rc7 Kernel Configuration", srctree ".", config symbol prefix "CONFIG_", warnings enabled, undef. symbol assignment warnings disabled>
>>> kconf.mainmenu_text  # Expanded main menu text
'Linux/x86 4.14.0-rc7 Kernel Configuration'
>>> kconf.top_node  # The implicit top-level menu
<menu node for menu, prompt "Linux/x86 4.14.0-rc7 Kernel Configuration" (visibility y), deps y, 'visible if' deps y, has child, Kconfig:5>
>>> kconf.top_node.list  # First child menu node
<menu node for symbol SRCARCH, deps y, has next, Kconfig:7>
>>> print(kconf.top_node.list)  # Calls MenuNode.__str__()
config SRCARCH
    string
    option env="SRCARCH"
    default "x86"
>>> sym = kconf.top_node.list.next.item  # Item contained in next menu node
>>> print(sym)  # Calls Symbol.__str__()
config 64BIT
    bool "64-bit kernel" if ARCH = "x86"
    default ARCH != "i386"
    help
      Say yes to build a 64-bit kernel - formerly known as x86_64
      Say no to build a 32-bit kernel - formerly known as i386
>>> sym  # Calls Symbol.__repr__()
<symbol 64BIT, bool, "64-bit kernel", value y, visibility y, direct deps y, arch/x86/Kconfig:2>
>>> sym.assignable  # Currently assignable values (0, 1, 2 = n, m, y)
(0, 2)
>>> sym.set_value(0)  # Set it to n
True
>>> sym.tri_value  # Check the new value
0
>>> sym = kconf.syms["X86_MPPARSE"]  # Look up symbol by name
>>> print(sym)
config X86_MPPARSE
    bool "Enable MPS table" if (ACPI || SFI) && X86_LOCAL_APIC
    default y if X86_LOCAL_APIC
    help
      For old smp systems that do not have proper acpi support. Newer systems
      (esp with 64bit cpus) with acpi support, MADT and DSDT will override it
>>> default = sym.defaults[0]  # Fetch its first default
>>> sym = default[1]  # Fetch the default's condition (just a Symbol here)
>>> print(sym)
config X86_LOCAL_APIC
    bool
    default y
    select IRQ_DOMAIN_HIERARCHY
    select PCI_MSI_IRQ_DOMAIN if PCI_MSI
    depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
>>> sym.nodes  # Show the MenuNode(s) associated with it
[<menu node for symbol X86_LOCAL_APIC, deps n, has next, arch/x86/Kconfig:1015>]
>>> kconfiglib.expr_str(sym.defaults[0][1])  # Print the default's condition
'X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI'
>>> kconfiglib.expr_value(sym.defaults[0][1])  # Evaluate it (0 = n)
0
>>> kconf.syms["64BIT"].set_value(2)
True
>>> kconfiglib.expr_value(sym.defaults[0][1])  # Evaluate it again (2 = y)
2
>>> kconf.write_config("myconfig")  # Save a .config
>>> ^D
$ cat myconfig
# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)
CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
...Test suiteThe test suite is run with$ python(3) Kconfiglib/testsuite.pypypyworks too, and is much speedier for everything exceptallnoconfig.py/allnoconfig_simpler.py/allyesconfig.py, where it doesn’t have time to warm up since
the scripts are run viamake scriptconfig.The test suite must be run from the top-level kernel directory. It requires that the
Kconfiglib git repository has been cloned into it and that the makefile patch has been applied.To get rid of warnings generated for the kernelKconfigfiles, add2>/dev/nullto the command to
discardstderr.NOTE: Forgetting to apply the Makefile patch will cause some tests that compare generated configurations to failNOTE: The test suite overwrites .config in the kernel root, so make sure to back it up.The test suite consists of a set of selftests and a set of compatibility tests that
compare configurations generated by Kconfiglib with
configurations generated by the C tools, for a number of cases. Seetestsuite.pyfor the available options.Thetests/reltestscript runs the test suite
and all the example scripts for both Python 2 and Python 3, verifying that everything works.Rarely, the output from the C tools is changed slightly (most recently due to achangeI added).
If you get test suite failures, try running the test suite again against thelinux-next tree,
which has all the latest changes. I will make it clear if any
non-backwards-compatible changes appear.A lot of time is spent waiting around formakeand the C utilities (which need to reparse all the
Kconfig files for each defconfig test). Adding some multiprocessing to the test suite would make sense
too.NotesThis is version 2 of Kconfiglib, which is not backwards-compatible with
Kconfiglib 1. A summary of changes between Kconfiglib 1 and Kconfiglib
2 can be foundhere.I sometimes see people add custom output formats, which is pretty
straightforward to do (see the implementations ofwrite_autoconf()andwrite_config()for a template, and also the documentation of theSymbol.config_stringproperty). If you come up with something you think
might be useful to other people, I’m happy to take it in upstream. Batteries
included and all that.Kconfiglib assumes the modules symbol isMODULES, which is backwards-compatible.
A warning is printed by default ifoption modulesis set on some other symbol.Let me know if you need properoption modulessupport. It wouldn’t be that
hard to add.ThanksToRomaVis, for makingpymenuconfigand suggesting
thersourcekeyword.ToMitja Horvat, for adding support
for user-defined styles to the terminal menuconfig.ToPhilip Craigfor adding
support for theallnoconfig_yoption and fixing an obscure issue
withcomments insidechoices (that didn’t affect correctness but
made outputs differ).allnoconfig_yis used to force certain symbols
toyduringmake allnoconfigto improve coverage.LicenseSeeLICENSE.txt. SPDX license identifiers are used in the
source code.