summaryrefslogtreecommitdiff
path: root/README.rst
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 /README.rst
parent8c978ee0b9c0f7f8406f58d24478a73330512056 (diff)
parent4bffd653148d6fa1c8e626872ae4f445e2b0a24c (diff)
Make Kconfiglib 2 official
Merge in the 'kconfiglib-2-backup' branch.
Diffstat (limited to 'README.rst')
-rw-r--r--README.rst400
1 files changed, 280 insertions, 120 deletions
diff --git a/README.rst b/README.rst
index 181c5c3..410c949 100644
--- a/README.rst
+++ b/README.rst
@@ -1,22 +1,126 @@
-Kconfiglib
-==========
+.. contents:: Table of contents
+ :backlinks: none
-A Python library for doing stuff with `Kconfig <https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt>`_-based
-configuration systems. Can extract information, query and set symbol values,
-and read and write ``.config`` files. Highly compatible with the
-``scripts/kconfig/*conf`` utilities in the kernel, usually invoked via make
-targets such as ``menuconfig`` and ``defconfig``.
+Overview
+--------
-Supports both Python 2 and Python 3 without modification, and should also run
-on non-\*nix platforms.
+*This is version 2 of Kconfiglib, which is not backwards-compatible with
+Kconfiglib 1. For a summary of changes between Kconfiglib 1 and Kconfiglib 2,
+see* |changes|_.
-*NOTE: A non-backwards-compatible 2.0 version will be coming soon, with a much cleaner and more general API (property-based,
-less redundant, more logical). That one will also expose the menu structure (including implicit menus) and all the
-expressions directly. The major version will be bumped to 2 in accordance with
-semantic versioning. See the kconfiglib-2-backup branch for a sneak peek (or if you feel like beta testing).*
+.. _changes: kconfiglib-2-changes.txt
+.. |changes| replace:: *kconfiglib-2-changes.txt*
-.. contents:: Table of contents
- :backlinks: none
+Kconfiglib is a Python 2/3 library for scripting and extracting information
+from `Kconfig
+<https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt>`_
+configuration systems. It can do the following, among other things:
+
+- **Programmatically get and set symbol values**
+
+ `allnoconfig.py <examples/allnoconfig.py>`_ and `allyesconfig.py
+ <examples/allyesconfig.py>`_ examples are provided, automatically verified to
+ produce identical output to the standard ``make allnoconfig`` and ``make
+ allyesconfig``.
+
+- **Read and write .config files**
+
+ The generated ``.config`` 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.
+
+- **Inspect symbols**
+
+ Printing a symbol gives output which could be fed back into a Kconfig parser
+ to redefine it***. The printing function (``__str__()``) is implemented with
+ public APIs, meaning you can fetch just whatever information you need as
+ well.
+
+ A helpful ``__repr__()`` is implemented on all objects too, also implemented
+ with public APIs.
+
+ \***Choice symbols get their parent choice as a dependency, which shows up as
+ e.g. ``prompt "choice symbol" if <choice>`` when printing the symbol. This
+ could easily be worked around if 100% reparsable output is needed.
+
+- **Inspect expressions**
+
+ Expressions 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 tree**
+
+ The 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.
+
+ See the `menuconfig.py <examples/menuconfig.py>`_ example.
+
+
+Here are some other features:
+
+- **Single-file implementation**
+
+ The entire library is contained in `kconfiglib.py <kconfiglib.py>`_.
+
+- **Runs unmodified under both Python 2 and Python 3**
+
+ The code mostly uses basic Python features and has no third-party
+ dependencies. The most advanced things used are probably ``@property`` and
+ ``__slots__``.
+
+- **Robust and highly compatible with the standard Kconfig C tools**
+
+ The test suite automatically compares output from Kconfiglib and the C tools
+ by diffing the generated ``.config`` files 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 implementation**
+
+ The `allyesconfig.py <examples/allyesconfig.py>`_ example currently runs in
+ about 1.6 seconds on a Core i7 2600K (with a warm file cache), where half a
+ second is overhead from ``make scriptconfig`` (see below).
+
+ For long-running jobs, `PyPy <https://pypy.org/>`_ gives a big performance
+ boost. CPython is faster for short-running jobs as PyPy needs some time to
+ warm up.
+
+- **Internals that (mostly) mirror the C implementation**
+
+ While being simpler to understand.
+
+Documentation
+-------------
+
+Kconfiglib comes with extensive documentation in the form of docstrings. To view it, run e.g.
+the following command:
+
+.. code:: sh
+
+ $ pydoc kconfiglib
+
+For HTML output, add ``-w``:
+
+.. code:: sh
+
+ $ pydoc -w kconfiglib
+
+A good starting point is to read the module docstring (which you could also just read directly
+at the beginning of `kconfiglib.py <kconfiglib.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 the ``Kconfig`` class
+documentation, and then the documentation for the ``Symbol``, ``Choice``, and ``MenuNode``
+classes.
+
+Please tell me if something is unclear to you or can be explained better.
Installation
------------
@@ -37,77 +141,174 @@ All releases have a corresponding tag in the git repository, e.g. ``v1.0.6``.
Installation for the Linux kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-After installing with ``pip(3)``, apply ``makefile.patch``
-by running e.g. the following commands in the kernel root:
+See the module docstring at the top of `kconfiglib.py <kconfiglib.py>`_.
-.. code:: sh
+Manual installation
+~~~~~~~~~~~~~~~~~~~
-   $ wget https://raw.githubusercontent.com/ulfalizer/Kconfiglib/master/makefile.patch
- $ git am makefile.patch
+The entire library is contained in
+`kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
+Just drop it somewhere.
-If you do not wish to install anything, the following manual approach will work as well:
+Examples
+--------
-.. code:: sh
+Example scripts
+~~~~~~~~~~~~~~~
- $ git clone git://github.com/ulfalizer/Kconfiglib.git
- $ git am Kconfiglib/makefile.patch
+The ``examples/`` subdirectory contains some simple example scripts. Among these are the following ones:
-(Warning: The directory name ``Kconfiglib/`` is significant in this case, because it's added to ``PYTHONPATH`` by the new targets in ``makefile.patch``.)
+- `allnoconfig.py <examples/allnoconfig.py>`_, `allnoconfig_simpler.py <examples/allnoconfig_simpler.py>`_, and `allyesconfig.py <examples/allyesconfig.py>`_ implement ``make allnoconfig`` and ``make allyesconfig`` in various ways. Demonstrates menu tree walking and value setting.
-In addition to creating a handy interface, the make targets created by the
-patch (``scriptconfig`` and ``iscriptconfig``) are needed to pick up environment
-variables set in the kernel makefiles and later referenced in the Kconfig files
-(``ARCH``, ``SRCARCH``, and ``KERNELVERSION`` as of Linux v4.14.0-rc1).
-The documentation explains how the make targets are used. The compatibility
-tests in the test suite also needs them.
+- `defconfig.py <examples/defconfig.py>`_ has the same effect as going into ``make menuconfig`` and immediately saving and exiting.
-Please tell me if the patch does not apply. It should be trivial to apply
-manually, as it's just a block of text that needs to be inserted near the other
-``*conf:`` targets.
+- `eval_expr.py <examples/eval_expr.py>`_ evaluates an expression in the context of a configuration.
-Manual installation
-~~~~~~~~~~~~~~~~~~~
+- `find_symbol.py <examples/find_symbol.py>`_ searches through expressions to find references to a symbol, also printing a "backtrace" with parents for each reference found.
-The entire library is contained in
-`kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
-Just drop it somewhere.
+- `help_grep.py <examples/help_grep.py>`_ searches for a string in all help texts.
-Documentation
--------------
+- `print_tree.py <examples/print_tree.py>`_ prints a tree of all configuration items.
-The (extensive) documentation is generated by running the following command in the same
-directory as `kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_:
+- `menuconfig.py <examples/menuconfig.py>`_ implements a configuration interface that uses notation similar to ``make menuconfig``. It's deliberately kept as simple as possible to demonstrate just the core concepts, and isn't something you'd actually want to use. Here's a screenshot:
-.. code:: sh
+.. code-block::
- $ pydoc kconfiglib
+ ======== Example Kconfig configuration ========
-For HTML output, use
-
-.. code:: sh
+ [*] 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)
- $ pydoc -w kconfiglib
+ Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): BOOL
+ Value for BOOL (available: n, y): n
+ ...
-You could also browse the docstrings directly in
-`kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
+I'm not currently interested in implementing a (more usable) menuconfig myself, but all the infrastructure
+for a great one should be there if you want to give it a go. I'll help you out with any questions you might
+have.
-Please tell me if something is unclear to you or can be explained better. The Kconfig
-language has some dark corners.
+Real-world examples
+~~~~~~~~~~~~~~~~~~~
-Examples
---------
+These 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.py <http://git.denx.de/?p=u-boot.git;a=blob;f=tools/genboardscfg.py;hb=HEAD>`_ from `Das U-Boot <http://www.denx.de/wiki/U-Boot>`_ generates 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.py <https://git.busybox.net/buildroot/tree/support/scripts/gen-manual-lists.py?id=5676a2deea896f38123b99781da0a612865adeb0>`_ generated listings for an appendix in the `Buildroot <https://buildroot.org>`_ manual. (The listing has since been removed.)
+
+- `gen_kconfig_doc.py <https://github.com/espressif/esp-idf/blob/master/docs/gen-kconfig-doc.py>`_ from the `esp-idf <https://github.com/espressif/esp-idf>`_ project generates documentation from Kconfig files.
+
+- `SConf <https://github.com/CoryXie/SConf>`_ builds an interactive configuration interface (like ``menuconfig``) on top of Kconfiglib, for use e.g. with `SCons <scons.org>`_.
-* The `examples/ <https://github.com/ulfalizer/Kconfiglib/tree/master/examples>`_ directory contains simple example scripts. See the documentation for how to run them.
+- `kconfig-diff.py <https://gist.github.com/dubiousjim/5638961>`_ -- a script by `dubiousjim <https://github.com/dubiousjim>`_ that compares kernel configurations.
-* `genboardscfg.py <http://git.denx.de/?p=u-boot.git;a=blob;f=tools/genboardscfg.py;hb=HEAD>`_ from `Das U-Boot <http://www.denx.de/wiki/U-Boot>`_ generates some sort of legacy board database by pulling information from a newly added Kconfig-based configuration system (as far as I understand it :).
+- Originally, Kconfiglib was used in chapter 4 of my `master's thesis <http://liu.diva-portal.org/smash/get/diva2:473038/FULLTEXT01.pdf>`_ to 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.
-* `gen-manual-lists.py <https://git.busybox.net/buildroot/tree/support/scripts/gen-manual-lists.py?id=5676a2deea896f38123b99781da0a612865adeb0>`_ generated listings for an appendix in the `Buildroot <https://buildroot.org>`_ manual. (The listing has since been removed.)
+Sample ``make iscriptconfig`` session
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* `SConf <https://github.com/CoryXie/SConf>`_ builds an interactive configuration interface (like ``menuconfig``) on top of Kconfiglib, for use e.g. with `SCons <scons.org>`_.
+The following log should give some idea of the functionality available in the API:
-* `kconfig-diff.py <https://gist.github.com/dubiousjim/5638961>`_ -- a script by `dubiousjim <https://github.com/dubiousjim>`_ that compares kernel configurations.
+.. code-block::
-* Originally, Kconfiglib was used in chapter 4 of my `master's thesis <http://liu.diva-portal.org/smash/get/diva2:473038/FULLTEXT01.pdf>`_ to 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.
+ $ 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/$ARCH $KERNELVERSION 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
+ prompt "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
+ prompt "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) # Print it. Dependencies are propagated to properties, like in the C implementation.
+ config X86_LOCAL_APIC
+ bool
+ default "y" if X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
+ select IRQ_DOMAIN_HIERARCHY if X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
+ select PCI_MSI_IRQ_DOMAIN if PCI_MSI && (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 suite
----------
@@ -118,18 +319,20 @@ The test suite is run with
$ python(3) Kconfiglib/testsuite.py
-(`pypy <http://pypy.org>`_ works too, and is much speedier.)
+`pypy <http://pypy.org>`_ works too, and is much speedier for everything except ``allnoconfig.py``/``allnoconfig_simpler.py``/``allyesconfig.py``, where it doesn't have time to warm up since
+the scripts are run via ``make scriptconfig``.
-The test suite must be run from the top-level kernel directory. It requires that the git
-repository has been cloned into it and that ``makefile.patch`` has been applied.
+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.
-**NOTE: Some tests currently overwrite .config in the kernel root, so make sure to back it up.**
+**NOTE: 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 (character for character) configurations generated by Kconfiglib with
-configurations generated by ``scripts/kconfig/conf`` for a number of cases. You
-might want to use the "speedy" option; see
-`testsuite.py <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_.
+compare configurations generated by Kconfiglib with
+configurations generated by the C tools, for a number of cases. See
+`testsuite.py <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_
+for the available options. You might want to use the "speedy" option to speed things
+up a bit.
The test suite might fail for a few configurations for kernels older than April 2016,
when a fix was added to Kconfig that's also mirrored in Kconfiglib
@@ -137,61 +340,18 @@ when a fix was added to Kconfig that's also mirrored in Kconfiglib
This is harmless, and only counts as a fail since the test suite compares literal
output from the kconfig version that's bundled with the kernel.
-Kconfiglib is much faster than the test suite would indicate. Most of the time
-is spent waiting around for ``make`` or the C utilities. Adding some multiprocessing
-to the test suite would make sense.
+A lot of time is spent waiting around for ``make`` and 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.
Notes
-----
-* **Useful information can be extracted from internal data structures.** The
- expression format is pretty simple for example: ``A && B && (!C || D == 3)`` is
- represented as the tuple structure
- ``(_AND, A, (_AND, B, (_OR, (_NOT, C), (_EQUAL, D, 3))))``; see the
- ``Config._parse_expr()`` docstring.
-
- It's hard to come up with good APIs for dealing with expressions given how
- general they are, so feel free to look at them directly if none of the
- exposed APIs will suffice (modifying them is dangerous though, because it
- breaks dependency tracking). Maybe I'll officially document the expression
- format and add a bunch of accessors later. The internal format is unlikely
- to change in either case, and would probably be returned directly.
-
- If you come up with some good generally-usable APIs involving
- expressions, please tell me. Make sure they also make sense for expressions
- involving ``||`` (or) and ``!`` (not).
-
-* Kconfiglib works well with `PyPy <http://pypy.org>`_. It gives a nice speedup
- over CPython when batch processing a large number of configurations (like
- the test suite does).
-
-* Kconfiglib assumes the modules symbol is ``MODULES`` and will warn if
- ``option modules`` is set on some other symbol. Let me know if this is a
- problem for you. Adding proper ``option modules`` support should be pretty
- easy.
-
-* At least two things make it awkward to replicate a ``menuconfig``-like
- interface in Kconfiglib at the moment (but see
- `SConf <https://github.com/CoryXie/SConf>`_, as mentioned above).
-
- * There are no good APIs for figuring out what other symbols change in value
- when the value of some symbol is changed, to allow for "live" updates
- in the configuration interface. The simplest workaround is to refetch the
- value of each currently visible symbol every time a symbol value is
- changed.
-
- * ``menuconfig`` sometimes creates cosmetic menus implicitly by looking at
- dependencies. For example, a list of symbols where all symbols depend on
- the first symbol creates a cosmetic menu rooted at the first symbol.
- Recreating such menus is awkward.
-
- There is already basic support internally though, because it's needed to
-   get obscure ``choice`` behavior right. See ``_determine_actual_symbols()`` and
- its helper ``_has_auto_menu_dep_on()``.
-
-* Using `__slots__ <https://docs.python.org/3.1/reference/datamodel.html#slots>`_
- on classes would speed things up a bit and save memory. It'd remove some
- flexibility though.
+* Kconfiglib assumes the modules symbol is ``MODULES``, which is backwards-compatible.
+ A warning is printed by default if ``option modules`` is set on some other symbol.
+
+ Let me know if you need proper ``option modules`` support. It wouldn't be that
+ hard to add.
* `fpemud <https://github.com/fpemud>`_ has put together
`Python bindings <https://github.com/fpemud/pylkc>`_ to internal functions in the C