将scons --menuconfig/--pyconfig/--pyconfig-silent统一调用kconfiglib

This commit is contained in:
LaterComer 2024-04-19 08:48:32 +08:00 committed by GitHub
parent 202bacb44d
commit 6311bcaf24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 8840 additions and 382 deletions

View File

@ -354,7 +354,7 @@ jobs:
chmod 777 install_ubuntu.sh
./install_ubuntu.sh
git config --global http.postBuffer 524288000
python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
python -c "import tools.menukconfig; tools.menukconfig.touch_env()"
echo "RTT_ROOT=${{ github.workspace }}" >> $GITHUB_ENV
echo "RTT_CC=gcc" >> $GITHUB_ENV

View File

@ -52,7 +52,7 @@ jobs:
git config --global http.postBuffer 524288000
git remote -v
git fetch origin
python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
python -c "import tools.menukconfig; tools.menukconfig.touch_env()"
- name: Install Arm ToolChains
if: ${{ success() }}

View File

@ -66,7 +66,7 @@ jobs:
chmod 777 install_ubuntu.sh
./install_ubuntu.sh
git config --global http.postBuffer 524288000
python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
python -c "import tools.menukconfig; tools.menukconfig.touch_env()"
echo "RTT_ROOT=${{ github.workspace }}" >> $GITHUB_ENV
echo "RTT_CC=gcc" >> $GITHUB_ENV

View File

@ -141,7 +141,7 @@ jobs:
chmod 777 install_ubuntu.sh
./install_ubuntu.sh
git config --global http.postBuffer 524288000
python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
python -c "import tools.menukconfig; tools.menukconfig.touch_env()"
echo "RTT_ROOT=${{ github.workspace }}" >> $GITHUB_ENV
echo "RTT_CC=gcc" >> $GITHUB_ENV

View File

@ -286,7 +286,7 @@ jobs:
chmod 777 install_ubuntu.sh
./install_ubuntu.sh
git config --global http.postBuffer 524288000
python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
python -c "import tools.menukconfig; tools.menukconfig.touch_env()"
echo "RTT_ROOT=${{ github.workspace }}" >> $GITHUB_ENV
echo "RTT_CC=gcc" >> $GITHUB_ENV

View File

@ -116,7 +116,7 @@ jobs:
chmod 777 install_ubuntu.sh
./install_ubuntu.sh
git config --global http.postBuffer 524288000
python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
python -c "import tools.menukconfig; tools.menukconfig.touch_env()"
echo "RTT_ROOT=${{ github.workspace }}" >> $GITHUB_ENV
echo "RTT_CC=gcc" >> $GITHUB_ENV

View File

@ -139,10 +139,20 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [
# set RTT_ROOT in ENV
Env['RTT_ROOT'] = Rtt_Root
os.environ["RTT_DIR"] = Rtt_Root
# set BSP_ROOT in ENV
Env['BSP_ROOT'] = Dir('#').abspath
os.environ["BSP_DIR"] = Dir('#').abspath
# set PKGS_ROOT in ENV
if not "PKGS_DIR" in os.environ:
if "ENV_ROOT" in os.environ:
os.environ["PKGS_DIR"] = os.path.join(os.environ["ENV_ROOT"], "packages")
elif sys.platform == "win32":
os.environ["PKGS_DIR"] = os.path.join(os.environ["USERPROFILE"], ".env/packages")
else:
os.environ["PKGS_DIR"] = os.path.join(os.environ["HOME"], ".env/packages")
sys.path = sys.path + [os.path.join(Rtt_Root, 'tools')]
sys.path = sys.path + [os.path.join(Rtt_Root, 'tools'), os.path.join(Rtt_Root, 'tools/kconfiglib')]
# {target_name:(CROSS_TOOL, PLATFORM)}
tgt_dict = {'mdk':('keil', 'armcc'),
@ -303,7 +313,7 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [
print('--global-macros arguments are illegal!')
if GetOption('genconfig'):
from genconf import genconfig
from menukconfig import genconfig
genconfig()
exit(0)
@ -311,25 +321,25 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [
from WCS import ThreadStackStaticAnalysis
ThreadStackStaticAnalysis(Env)
exit(0)
if platform.system() != 'Windows':
if GetOption('menuconfig'):
from menuconfig import menuconfig
menuconfig(Rtt_Root)
exit(0)
if GetOption('menuconfig'):
from menukconfig import menuconfig
menuconfig(Rtt_Root)
exit(0)
if GetOption('pyconfig-silent'):
from menuconfig import guiconfig_silent
from menukconfig import guiconfig_silent
guiconfig_silent(Rtt_Root)
exit(0)
elif GetOption('pyconfig'):
from menuconfig import guiconfig
from menukconfig import guiconfig
guiconfig(Rtt_Root)
exit(0)
configfn = GetOption('useconfig')
if configfn:
from menuconfig import mk_rtconfig
from menukconfig import mk_rtconfig
mk_rtconfig(configfn)
exit(0)

View File

@ -1,32 +0,0 @@
import os
def genconfig() :
from SCons.Script import SCons
PreProcessor = SCons.cpp.PreProcessor()
try:
f = open('rtconfig.h', 'r')
contents = f.read()
f.close()
except :
print("Open rtconfig.h file failed.")
PreProcessor.process_contents(contents)
options = PreProcessor.cpp_namespace
try:
f = open('.config', 'w')
for (opt, value) in options.items():
if type(value) == type(1):
f.write("CONFIG_%s=%d\n" % (opt, value))
if type(value) == type('') and value == '':
f.write("CONFIG_%s=y\n" % opt)
elif type(value) == type('str'):
f.write("CONFIG_%s=%s\n" % (opt, value))
print("Generate .config done!")
f.close()
except:
print("Generate .config file failed.")

4
tools/kconfiglib/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.py[co]
build/
*.egg-info/
dist/

View File

@ -0,0 +1,5 @@
Copyright (c) 2011-2019, Ulf Magnusson <ulfalizer@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,2 @@
# Include the license file in source distributions
include LICENSE.txt

841
tools/kconfiglib/README.rst Normal file
View File

@ -0,0 +1,841 @@
.. contents:: Table of contents
:backlinks: none
News
----
Dependency loop with recent linux-next kernels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To fix issues with dependency loops on recent linux-next kernels, apply `this
patch <https://www.spinics.net/lists/linux-kbuild/msg23455.html>`_. Hopefully,
it will be in ``linux-next`` soon.
``windows-curses`` is no longer automatically installed on Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starting with Kconfiglib 13.0.0, the `windows-curses
<https://github.com/zephyrproject-rtos/windows-curses>`__ package is no longer
automatically installed on Windows, and needs to be installed manually for the
terminal ``menuconfig`` to work.
This fixes installation of Kconfiglib on MSYS2, which is not compatible with
``windows-curses``. See `this issue
<https://github.com/ulfalizer/Kconfiglib/issues/77>`__.
The ``menuconfig`` now shows a hint re. installing ``windows-curses`` when the
``curses`` module can't be imported on Windows.
Sorry if this change caused problems!
Overview
--------
Kconfiglib is a `Kconfig
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-language.rst>`__
implementation 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
(including `terminal and GUI menuconfig interfaces <Menuconfig interfaces_>`_
and `Kconfig extensions`_).
The entire library is contained in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.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. the `Zephyr
<https://www.zephyrproject.org/>`__, `esp-idf
<https://github.com/espressif/esp-idf>`__, and `ACRN
<https://projectacrn.org/>`__ projects. 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 a
`Kconfig cross-reference
<https://docs.zephyrproject.org/latest/reference/kconfig/index.html>`_, using
the same robust Kconfig parser used for other Kconfig tools, instead of brittle
ad-hoc parsing. The documentation generation script can be found `here
<https://github.com/zephyrproject-rtos/zephyr/blob/master/doc/scripts/genrest.py>`__.
Kconfiglib implements the recently added `Kconfig preprocessor
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.rst>`__.
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: See `this issue <https://github.com/ulfalizer/Kconfiglib/issues/47>`__ if
you run into a "macro expanded to blank string" error with kernel 4.18+.
See `this page
<https://docs.zephyrproject.org/latest/guides/kconfig/tips.html>`__ for some
Kconfig tips and best practices.
Installation
------------
Installation with pip
~~~~~~~~~~~~~~~~~~~~~
Kconfiglib is available on `PyPI <https://pypi.python.org/pypi/kconfiglib/>`_ and can be
installed with e.g.
.. code::
$ pip(3) install kconfiglib
Microsoft Windows is supported.
The ``pip`` installation will give you both the base library and the following
executables. All but two (``genconfig`` and ``setconfig``) mirror functionality
available in the C tools.
- `menuconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_
- `guiconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_
- `oldconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/oldconfig.py>`_
- `olddefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/olddefconfig.py>`_
- `savedefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/savedefconfig.py>`_
- `defconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/defconfig.py>`_
- `alldefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/alldefconfig.py>`_
- `allnoconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allnoconfig.py>`_
- `allmodconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allmodconfig.py>`_
- `allyesconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_
- `listnewconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/listnewconfig.py>`_
- `genconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/genconfig.py>`_
- `setconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/setconfig.py>`_
``genconfig`` is 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.py`` only ran under Python 3
(i.e., it's now more backwards compatible than before).
**Note:** If you install Kconfiglib with ``pip``'s ``--user`` flag, make sure
that your ``PATH`` includes the directory where the executables end up. You can
list the installed files with ``pip(3) show -f kconfiglib``.
All releases have a corresponding tag in the git repository, e.g. ``v14.1.0``
(the latest version).
`Semantic versioning <http://semver.org/>`_ is used. There's been ten small
changes to the behavior of the API, a Windows packaging change, and a hashbang
change to use ``python3``
(`1 <https://github.com/ulfalizer/Kconfiglib/commit/e8b4ecb6ff6ccc1c7be0818314fbccda2ef2b2ee>`_,
`2 <https://github.com/ulfalizer/Kconfiglib/commit/db633015a4d7b0ba1e882f665e191f350932b2af>`_,
`3 <https://github.com/ulfalizer/Kconfiglib/commit/8983f7eb297dd614faf0beee3129559bc8ba338e>`_,
`4 <https://github.com/ulfalizer/Kconfiglib/commit/cbf32e29a130d22bc734b7778e6304ac9df2a3e8>`_,
`5 <https://github.com/ulfalizer/Kconfiglib/commit/eb6c21a9b33a2d6e2bed9882d4f930d0cab2f03b>`_,
`6 <https://github.com/ulfalizer/Kconfiglib/commit/c19fc11355b13d75d97286402c7a933fb23d3b70>`_,
`7 <https://github.com/ulfalizer/Kconfiglib/commit/7a428aa415606820a44291f475248b08e3952c4b>`_,
`8 <https://github.com/ulfalizer/Kconfiglib/commit/f247ddf618ad29718e5efd3e69f8baf75d4d347b>`_,
`9 <https://github.com/ulfalizer/Kconfiglib/commit/4fed39d9271ceb68be4157ab3f96a45b94f77dc0>`_,
`10 <https://github.com/ulfalizer/Kconfiglib/commit/55bc8c380869ea663092212e8fe388ad7abae596>`_,
`Windows packaging change <https://github.com/ulfalizer/Kconfiglib/commit/21b4c1e3b6e2867b9a0788d21a358f6b1f581d86>`_,
`Python 3 hashbang change <https://github.com/ulfalizer/Kconfiglib/commit/9e0a8d29fa76adcb3f27bb2e20f16fefc2a8591e>`_),
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 installation
~~~~~~~~~~~~~~~~~~~
Just drop ``kconfiglib.py`` and the scripts you want somewhere. There are no
third-party dependencies, but the terminal ``menuconfig`` won't work on Windows
unless a package like `windows-curses
<https://github.com/zephyrproject-rtos/windows-curses>`__ is installed.
Installation for the Linux kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See the module docstring at the top of `kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.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 from ``argparse``. ``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 started
---------------
1. `Install <Installation_>`_ the library and the utilities.
2. Write `Kconfig
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-language.rst>`__
files that describe the available configuration options. See `this page
<https://docs.zephyrproject.org/latest/guides/kconfig/tips.html>`__ for some
general Kconfig advice.
3. Generate an initial configuration with e.g. ``menuconfig``/``guiconfig`` or
``alldefconfig``. The configuration is saved as ``.config`` by default.
For more advanced projects, the ``defconfig`` utility 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``.
4. Run ``genconfig`` to generate a header file. By default, it is saved as
``config.h``.
Normally, ``genconfig`` would 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 of ``write_config()`` in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
The documentation for the ``Symbol.config_string`` property has some tips as
well.
5. To update an old ``.config`` file after the Kconfig files have changed (e.g.
to add new options), run ``oldconfig`` (prompts for values for new options)
or ``olddefconfig`` (gives new options their default value). Entering the
``menuconfig`` or ``guiconfig`` interface 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 ``.config`` file).
Due to Kconfig semantics, simply loading an old ``.config`` file performs an
implicit ``olddefconfig``, so building will normally not be affected by
having an outdated configuration.
Whenever ``.config`` is overwritten, the previous version of the file is saved
to ``.config.old`` (or, more generally, to ``$KCONFIG_CONFIG.old``).
Using ``.config`` files as Make input
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``.config`` files use Make syntax and can be included directly in Makefiles to
read configuration values from there. This is why ``n``-valued
``bool``/``tristate`` values are written out as ``# CONFIG_FOO is not set`` (a
Make comment) in ``.config``, allowing them to be tested with ``ifdef`` in
Make.
If you make use of this, you might want to pass ``--config-out <filename>`` to
``genconfig`` and include the configuration file it generates instead of
including ``.config`` directly. This has the advantage that the generated
configuration file will always be a "full" configuration file, even if
``.config`` is outdated. Otherwise, it might be necessary to run
``old(def)config`` or ``menuconfig``/``guiconfig`` before rebuilding with an
outdated ``.config``.
If you use ``--sync-deps`` to generate incremental build information, you can
include ``deps/auto.conf`` instead, which is also a full configuration file.
Useful helper macros
~~~~~~~~~~~~~~~~~~~~
The `include/linux/kconfig.h
<https://github.com/torvalds/linux/blob/master/include/linux/kconfig.h>`_
header 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 in ``if`` statements with no runtime overhead.
Incremental building
~~~~~~~~~~~~~~~~~~~~
See the docstring for ``Kconfig.sync_deps()`` in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_ for hints
on implementing incremental builds (rebuilding just source files that reference
changed configuration values).
Running the ``scripts/basic/fixdep.c`` tool from the kernel on the output of
``gcc -MD <source file>`` might give you an idea of how it all fits together.
Library documentation
---------------------
Kconfiglib comes with extensive documentation in the form of docstrings. To view it, run e.g.
the following command:
.. code:: sh
$ pydoc(3) kconfiglib
For HTML output, add ``-w``:
.. code:: sh
$ pydoc(3) -w kconfiglib
This will also work after installing Kconfiglib with ``pip(3)``.
Documentation for other modules can be viewed in the same way (though a plain
``--help`` will work when they're run as executables):
.. code:: sh
$ 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 of `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/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 or can be explained better.
Library features
----------------
Kconfiglib can do the following, among other things:
- **Programmatically get and set symbol values**
See `allnoconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allnoconfig.py>`_ and
`allyesconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_,
which are automatically verified to produce identical output to the standard
``make allnoconfig`` and ``make allyesconfig``.
- **Read and write .config and defconfig files**
The generated ``.config`` and ``defconfig`` (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 headers**
The generated headers use the same format as ``include/generated/autoconf.h``
from 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 builds**
This uses the same scheme as the ``include/config`` directory 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 the ``sync_deps()`` function for more information.
- **Inspect symbols**
Printing 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 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 `menuconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_/`guiconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_ and the
minimalistic `menuconfig_example.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/examples/menuconfig_example.py>`_
example.
Kconfig extensions
~~~~~~~~~~~~~~~~~~
The following Kconfig extensions are available:
- ``source`` supports glob patterns and includes each matching file. A pattern
is required to match at least one file.
A separate ``osource`` statement is available for cases where it's okay for
the pattern to match no files (in which case ``osource`` turns into a no-op).
- A relative ``source`` statement (``rsource``) is available, where file paths
are specified relative to the directory of the current Kconfig file. An
``orsource`` statement is available as well, analogous to ``osource``.
- 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 the *Kconfig extensions* section in the
`kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_
module docstring for more information.
- ``def_int``, ``def_hex``, and ``def_string`` are available in addition to
``def_bool`` and ``def_tristate``, allowing ``int``, ``hex``, and ``string``
symbols 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. ``source`` and
``mainmenu`` statements, meaning ``option env`` symbols are redundant.
This is the standard behavior with the new `Kconfig preprocessor
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.rst>`__,
which Kconfiglib implements.
``option env`` symbols 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 the ``option env`` symbol always
matched the environment variable. Compatibility with older Linux kernels is
the main reason ``option env`` is still supported.
The C tools have dropped support for ``option 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 to ``y``, warnings will be generated for all
references to undefined symbols within Kconfig files. The only gotcha is
that all hex literals must be prefixed with ``0x`` or ``0X``, 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_UNDEF`` is useful in projects that only have a single
Kconfig tree though.
``KCONFIG_STRICT`` is an older alias for this environment variable,
supported for backwards compatibility.
* ``KCONFIG_WARN_UNDEF_ASSIGN``: If set to ``y``, warnings will be generated
for all assignments to undefined symbols within ``.config`` files. By
default, no such warnings are generated.
This warning can also be enabled/disabled by setting
``Kconfig.warn_assign_undef`` to ``True``/``False``.
Other features
--------------
- **Single-file implementation**
The entire library is contained in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
The tools implemented on top of it are one file each.
- **Robust and highly compatible with the C Kconfig tools**
 The `test suite <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_
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
<https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_
script currently runs in about 1.3 seconds on the Linux kernel on a Core i7
2600K (with a warm file cache), including the ``make`` overhead from ``make
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 ``.config`` files
need to be processed, because the ``Kconfig`` files will only need to be parsed
once.
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.
Kconfiglib also works well with the
`multiprocessing <https://docs.python.org/3/library/multiprocessing.html>`_
module. No global state is kept.
- **Generates more warnings than the C implementation**
Generates the same warnings as the C implementation, plus additional ones.
Also detects dependency and ``source`` loops.
All warnings point out the location(s) in the ``Kconfig`` files where a
symbol is defined, where applicable.
- **Unicode support**
Unicode characters in string literals in ``Kconfig`` and ``.config`` files are
correctly handled. This support mostly comes for free from Python.
- **Windows support**
Nothing Linux-specific is used. Universal newlines mode is used for both
Python 2 and Python 3.
The `Zephyr <https://www.zephyrproject.org/>`_ project uses Kconfiglib to
generate ``.config`` files and C headers on Linux as well as Windows.
- **Internals that (mostly) mirror the C implementation**
While being simpler to understand and tweak.
Menuconfig interfaces
---------------------
Three configuration interfaces are currently available:
- `menuconfig.py <https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_
is a terminal-based configuration interface implemented using the standard
Python ``curses`` module. ``xconfig`` features 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).
.. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/menuconfig.gif
*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.py`` runs 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 the ``curses`` module on Python 2).
There are no third-party dependencies on \*nix. On Windows,
the ``curses`` modules is not available by default, but support
can be added by installing the ``windows-curses`` package:
.. code-block:: shell
$ pip install windows-curses
This uses wheels built from `this repository
<https://github.com/zephyrproject-rtos/windows-curses>`_, which is in turn
based on Christoph Gohlke's `Python Extension Packages for Windows
<https://www.lfd.uci.edu/~gohlke/pythonlibs/#curses>`_.
See the docstring at the top of `menuconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_ for
more information about the terminal menuconfig implementation.
- `guiconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_ is a
graphical configuration interface written in `Tkinter
<https://docs.python.org/3/library/tkinter.html>`_. Like ``menuconfig.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
with ``config`` and symbols defined with ``menuconfig``.
``guiconfig.py`` has 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, ``tkinter`` often isn't
included by default in Python installations on Linux. These commands will
install it on a few different distributions:
- Ubuntu: ``sudo apt install python-tk``/``sudo apt install python3-tk``
- Fedora: ``dnf install python2-tkinter``/``dnf install python3-tkinter``
- Arch: ``sudo pacman -S tk``
- Clear Linux: ``sudo swupd bundle-add python3-tcl``
Screenshot below, with show-all mode enabled and the jump-to dialog open:
.. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/guiconfig.png
To avoid having to carry around a bunch of GIFs, the image data is embedded
in ``guiconfig.py``. To use separate GIF files instead, change
``_USE_EMBEDDED_IMAGES`` to ``False`` in ``guiconfig.py``. The image files
can be found in the `screenshots
<https://github.com/ulfalizer/Kconfiglib/tree/screenshots/guiconfig>`_
branch.
I did my best with the images, but some are definitely only art adjacent.
Touch-ups are welcome. :)
- `pymenuconfig <https://github.com/RomaVis/pymenuconfig>`_, built by `RomaVis
<https://github.com/RomaVis>`_, is an older portable Python 2/3 TkInter
menuconfig implementation.
Screenshot below:
.. image:: https://raw.githubusercontent.com/RomaVis/pymenuconfig/master/screenshot.PNG
While working on the terminal menuconfig implementation, I added a few APIs
to Kconfiglib that turned out to be handy. ``pymenuconfig`` predates
``menuconfig.py`` and ``guiconfig.py``, and so didn't have them available.
Blame me for any workarounds.
Examples
--------
Example scripts
~~~~~~~~~~~~~~~
The `examples/ <https://github.com/ulfalizer/Kconfiglib/blob/master/examples>`_ 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.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/eval_expr.py>`_ evaluates an expression in the context of a configuration.
- `find_symbol.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/find_symbol.py>`_ searches through expressions to find references to a symbol, also printing a "backtrace" with parents for each reference found.
- `help_grep.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/help_grep.py>`_ searches for a string in all help texts.
- `print_tree.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/print_tree.py>`_ prints a tree of all configuration items.
- `print_config_tree.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/print_config_tree.py>`_ is similar to ``print_tree.py``, but dumps the tree as it would appear in ``menuconfig``, including values. This can be handy for visually diffing between ``.config`` files and different versions of ``Kconfig`` files.
- `list_undefined.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py>`_ finds references to symbols that are not defined by any architecture in the Linux kernel.
- `merge_config.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/merge_config.py>`_ merges configuration fragments to produce a complete .config, similarly to ``scripts/kconfig/merge_config.sh`` from the kernel.
- `menuconfig_example.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/menuconfig_example.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.
Real-world examples
~~~~~~~~~~~~~~~~~~~
- `kconfig.py
<https://github.com/zephyrproject-rtos/zephyr/blob/master/scripts/kconfig/kconfig.py>`_
from the `Zephyr <https://www.zephyrproject.org/>`_ project handles
``.config`` and header file generation, also doing configuration fragment
merging
- `genrest.py
<https://github.com/zephyrproject-rtos/zephyr/blob/master/doc/scripts/genrest.py>`_
generates a Kconfig symbol cross-reference, which can be viewed `here
<http://docs.zephyrproject.org/reference/kconfig/index.html>`__
- `CMake and IDE integration
<https://github.com/espressif/esp-idf/tree/master/tools/kconfig_new>`_ from
the ESP-IDF project, via a configuration server program.
- `A script for turning on USB-related options
<https://github.com/google/syzkaller/blob/master/dashboard/config/kconfiglib-merge-usb-configs.py>`_,
from the `syzkaller <https://github.com/google/syzkaller>`_ project.
- `Various automated checks
<https://github.com/zephyrproject-rtos/ci-tools/blob/master/scripts/check_compliance.py>`_,
including a check for references to undefined Kconfig symbols in source code.
See the ``KconfigCheck`` class.
- `Various utilities
<https://github.com/projectacrn/acrn-hypervisor/tree/master/scripts/kconfig>`_
from the `ACRN <https://projectacrn.org/>`_ project
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>`_.
- `kconfig-diff.py <https://gist.github.com/dubiousjim/5638961>`_ -- a script by `dubiousjim <https://github.com/dubiousjim>`_ that compares kernel configurations.
- 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.
Sample ``make iscriptconfig`` session
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following log should give some idea of the functionality available in the API:
.. code-block::
$ 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 suite
----------
The test suite is run with
.. code::
$ python(3) Kconfiglib/testsuite.py
`pypy <https://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
Kconfiglib git repository has been cloned into it and that the makefile patch has been applied.
To get rid of warnings generated for the kernel ``Kconfig`` files, add ``2>/dev/null`` to the command to
discard ``stderr``.
**NOTE: Forgetting to apply the Makefile patch will cause some tests that compare generated configurations to fail**
**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 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.
The `tests/reltest <https://github.com/ulfalizer/Kconfiglib/blob/master/tests/reltest>`_ script 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 a
`change <https://www.spinics.net/lists/linux-kbuild/msg17074.html>`_ I added).
If you get test suite failures, try running the test suite again against the
`linux-next tree <https://www.kernel.org/doc/man-pages/linux-next.html>`_,
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 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
-----
* This 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 found `here
<https://github.com/ulfalizer/Kconfiglib/blob/screenshots/kconfiglib-2-changes.txt>`__.
* I sometimes see people add custom output formats, which is pretty
straightforward to do (see the implementations of ``write_autoconf()`` and
``write_config()`` for a template, and also the documentation of the
``Symbol.config_string`` property). 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 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.
Thanks
------
- To `RomaVis <https://github.com/RomaVis>`_, for making
`pymenuconfig <https://github.com/RomaVis/pymenuconfig>`_ and suggesting
the ``rsource`` keyword.
- To `Mitja Horvat <https://github.com/pinkfluid>`_, for adding support
for user-defined styles to the terminal menuconfig.
- To `Philip Craig <https://github.com/philipc>`_ for adding
support for the ``allnoconfig_y`` option and fixing an obscure issue
with ``comment``\s inside ``choice``\s (that didn't affect correctness but
made outputs differ). ``allnoconfig_y`` is used to force certain symbols
to ``y`` during ``make allnoconfig`` to improve coverage.
License
-------
See `LICENSE.txt <https://github.com/ulfalizer/Kconfiglib/blob/master/LICENSE.txt>`_. SPDX license identifiers are used in the
source code.

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where all symbols are set to their their default
values.
The default output filename is '.config'. A different filename can be passed in
the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/alldefconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
kconf.load_allconfig("alldef.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'm'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allmodconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# See allnoconfig.py
kconf.warn = False
for sym in kconf.unique_defined_syms:
if sym.orig_type == kconfiglib.BOOL:
# 'bool' choice symbols get their default value, as determined by
# e.g. 'default's on the choice
if not sym.choice:
# All other bool symbols get set to 'y', like for allyesconfig
sym.set_value(2)
elif sym.orig_type == kconfiglib.TRISTATE:
sym.set_value(1)
for choice in kconf.unique_choices:
choice.set_value(2 if choice.orig_type == kconfiglib.BOOL else 1)
kconf.warn = True
kconf.load_allconfig("allmod.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'n'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allnoconfig.py
"""
# See examples/allnoconfig_walk.py for another way to implement this script
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# Avoid warnings that would otherwise get printed by Kconfiglib for the
# following:
#
# 1. Assigning a value to a symbol without a prompt, which never has any
# effect
#
# 2. Assigning values invalid for the type (only bool/tristate symbols
# accept 0/1/2, for n/m/y). The assignments will be ignored for other
# symbol types, which is what we want.
kconf.warn = False
for sym in kconf.unique_defined_syms:
sym.set_value(2 if sym.is_allnoconfig_y else 0)
kconf.warn = True
kconf.load_allconfig("allno.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'y'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allyesconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# See allnoconfig.py
kconf.warn = False
# Try to set all symbols to 'y'. Dependencies might truncate the value down
# later, but this will at least give the highest possible value.
#
# Assigning 0/1/2 to non-bool/tristate symbols has no effect (int/hex
# symbols still take a string, because they preserve formatting).
for sym in kconf.unique_defined_syms:
# Set choice symbols to 'm'. This value will be ignored for choices in
# 'y' mode (the "normal" mode), which will instead just get their
# default selection, but will set all symbols in m-mode choices to 'm',
# which is as high as they can go.
#
# Here's a convoluted example of how you might get an m-mode choice
# even during allyesconfig:
#
# choice
# tristate "weird choice"
# depends on m
sym.set_value(1 if sym.choice else 2)
# Set all choices to the highest possible mode
for choice in kconf.unique_choices:
choice.set_value(2)
kconf.warn = True
kconf.load_allconfig("allyes.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
@ -25,7 +25,7 @@ def main():
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Base Kconfig file (default: Kconfig)")
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"config",
@ -34,7 +34,7 @@ def main():
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig)
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config(args.config))
print(kconf.write_config())

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Generates a header file with #defines from the configuration, matching the
format of include/generated/autoconf.h in the Linux kernel.
Optionally, also writes the configuration output as a .config file. See
--config-out.
The --sync-deps, --file-list, and --env-list options generate information that
can be used to avoid needless rebuilds/reconfigurations.
Before writing a header or configuration file, 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.
By default, the configuration is generated from '.config'. A different
configuration file can be passed in the KCONFIG_CONFIG environment variable.
A custom header string can be inserted at the beginning of generated
configuration and header files by setting the KCONFIG_CONFIG_HEADER and
KCONFIG_AUTOHEADER_HEADER environment variables, respectively (this also works
for other scripts). The string is not automatically made a comment (this is by
design, to allow anything to be added), and no trailing newline is added, so
add '/* */', '#', and newlines as appropriate.
See https://www.gnu.org/software/make/manual/make.html#Multi_002dLine for a
handy way to define multi-line variables in makefiles, for use with custom
headers. Remember to export the variable to the environment.
"""
import argparse
import os
import sys
import kconfiglib
DEFAULT_SYNC_DEPS_PATH = "deps/"
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--header-path",
metavar="HEADER_FILE",
help="""
Path to write the generated header file to. If not specified, the path in the
environment variable KCONFIG_AUTOHEADER is used if it is set, and 'config.h'
otherwise.
""")
parser.add_argument(
"--config-out",
metavar="CONFIG_FILE",
help="""
Write the configuration to CONFIG_FILE. This is useful if you include .config
files in Makefiles, as the generated configuration file will be a full .config
file even if .config is outdated. The generated configuration matches what
olddefconfig would produce. If you use sync-deps, you can include
deps/auto.conf instead. --config-out is meant for cases where incremental build
information isn't needed.
""")
parser.add_argument(
"--sync-deps",
metavar="OUTPUT_DIR",
nargs="?",
const=DEFAULT_SYNC_DEPS_PATH,
help="""
Enable generation of symbol dependency information for incremental builds,
optionally specifying the output directory (default: {}). See the docstring of
Kconfig.sync_deps() in Kconfiglib for more information.
""".format(DEFAULT_SYNC_DEPS_PATH))
parser.add_argument(
"--file-list",
metavar="OUTPUT_FILE",
help="""
Write a list of all Kconfig files to OUTPUT_FILE, with one file per line. The
paths are relative to $srctree (or to the current directory if $srctree is
unset). Files appear in the order they're 'source'd.
""")
parser.add_argument(
"--env-list",
metavar="OUTPUT_FILE",
help="""
Write a list of all environment variables referenced in Kconfig files to
OUTPUT_FILE, with one variable per line. Each line has the format NAME=VALUE.
Only environment variables referenced with the preprocessor $(VAR) syntax are
included, and not variables referenced with the older $VAR syntax (which is
only supported for backwards compatibility).
""")
parser.add_argument(
"kconfig",
metavar="KCONFIG",
nargs="?",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
kconf.load_config()
if args.header_path is None:
if "KCONFIG_AUTOHEADER" in os.environ:
kconf.write_autoconf()
else:
# Kconfiglib defaults to include/generated/autoconf.h to be
# compatible with the C tools. 'config.h' is used here instead for
# backwards compatibility. It's probably a saner default for tools
# as well.
kconf.write_autoconf("config.h")
else:
kconf.write_autoconf(args.header_path)
if args.config_out is not None:
kconf.write_config(args.config_out, save_old=False)
if args.sync_deps is not None:
kconf.sync_deps(args.sync_deps)
if args.file_list is not None:
with _open_write(args.file_list) as f:
for path in kconf.kconfig_filenames:
f.write(path + "\n")
if args.env_list is not None:
with _open_write(args.env_list) as f:
for env_var in kconf.env_vars:
f.write("{}={}\n".format(env_var, os.environ[env_var]))
def _open_write(path):
# Python 2/3 compatibility. io.open() is available on both, but makes
# write() expect 'unicode' strings on Python 2.
if sys.version_info[0] < 3:
return open(path, "w")
return open(path, "w", encoding="utf-8")
if __name__ == "__main__":
main()

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
@ -95,7 +95,7 @@ an item will jump to it. Item values can be toggled directly within the dialog.\
def _main():
menuconfig(standard_kconfig())
menuconfig(standard_kconfig(__doc__))
# Global variables used below:
@ -345,9 +345,9 @@ def _load_images():
# Note: Base64 data can be put on the clipboard with
# $ base64 -w0 foo.gif | xclip
load_image("icon", "R0lGODlhIwAjAPcAAAAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAABVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/wCqAACqMwCqZgCqmQCqzACq/wDVAADVMwDVZgDVmQDVzADV/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMrADMrMzMrZjMrmTMrzDMr/zNVADNVMzNVZjNVmTNVzDNV/zOAADOAMzOAZjOAmTOAzDOA/zOqADOqMzOqZjOqmTOqzDOq/zPVADPVMzPVZjPVmTPVzDPV/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YrAGYrM2YrZmYrmWYrzGYr/2ZVAGZVM2ZVZmZVmWZVzGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmWaqzGaq/2bVAGbVM2bVZmbVmWbVzGbV/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5krAJkrM5krZpkrmZkrzJkr/5lVAJlVM5lVZplVmZlVzJlV/5mAAJmAM5mAZpmAmZmAzJmA/5mqAJmqM5mqZpmqmZmqzJmq/5nVAJnVM5nVZpnVmZnVzJnV/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wrAMwrM8wrZswrmcwrzMwr/8xVAMxVM8xVZsxVmcxVzMxV/8yAAMyAM8yAZsyAmcyAzMyA/8yqAMyqM8yqZsyqmcyqzMyq/8zVAMzVM8zVZszVmczVzMzV/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8rAP8rM/8rZv8rmf8rzP8r//9VAP9VM/9VZv9Vmf9VzP9V//+AAP+AM/+AZv+Amf+AzP+A//+qAP+qM/+qZv+qmf+qzP+q///VAP/VM//VZv/Vmf/VzP/V////AP//M///Zv//mf//zP///wAAAAAAAAAAAAAAACH5BAEAAPwALAAAAAAjACMAAAj/AKPtE0hwoMGCAiUF28VwoaJIyg4a3LeMIkVly5QR00gsk8eNvBZGYrhr4SJhmixWJFgPkyReIyVFisTrEi9eu2aOXBhsZE5dkYYtK1gR00lhydoha5dMGFOkwhr6bEhSUTKLApVFEjZsHtdkw56CjRoJ0iJIOYHlJLlL0kqKmXZ1RdoO6bCkw+QJ86nrLK2duy7tAhpx6D5Jwujenat02DBhZx/2LSu54UmB+zTtsrt06eKkyKKSjNT34UO0gyOt1DpvGLvFSF/Lc7yXIVqdihYpyo120bCEXJHNbQ1WeF5JqW2fXbQITBjTkH5H45W4ujCFMGHOXOSTZ8iQwRRu/80ZLdr4tSPTo2e7ViT7YNfpHW4nmKQuhvfZily4NjDD+nsNtRlDPtXXU0mkTVXSew0Jw0tEkgxj4GgL6rfgTpHwN1JikigTzYAILqghTz4BRlJ9JTkI4TD88Uegi1S1WCFPm3X4oWgH9iSjYC4eWOGCie1SEWKiKRIGGLql11xzRx7JnHNQhsGQMJh4SJ1IYGzhnBY2LBLMllmCgSSUWjoZDHxCHuZgMLxoAUaGi2g5mps0XQiGFlNRZ6NcPMEgZU5+btZTGFsAyVAYWkR1JppDsriZFnguYiaBbtpEI6IZfkelh3zmFAYMYMTwJptoImqoJFl6x2hLwwiqRRiSauRx0oWvjifMQp+GFNU613Ea5C43gFESpqTy4pyIIYkZ0mZBDkXdrcK8ulkkhKYYiZY4QbsLorqmaCMvLIYkLa5IihZGGGgqemRUt7IT1TItuQufrVFhB5+Bwqzz3ZT6wmdjUAvdKuiit5KamMHwJfwsOxAd5q4w5eQbFTu8sLOZOcFYrDGbFq/JzpnvTsfVw4mRTLJ1JadcncWYDDVMJMiwk9TMeTHmlDDuPvxwxkEGtQ9cvLjUFiZtIScJ0S5dd13QNL0kU9CZYEYQRtFQTU80y0CzzDL6ZFR11ltrLfbW+9QTTUAAOw==")
load_image("n_bool", "R0lGODlhDgAOAHAAACH5BAEAAPwALAAAAAAOAA4AhwAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAABVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/wCqAACqMwCqZgCqmQCqzACq/wDVAADVMwDVZgDVmQDVzADV/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMrADMrMzMrZjMrmTMrzDMr/zNVADNVMzNVZjNVmTNVzDNV/zOAADOAMzOAZjOAmTOAzDOA/zOqADOqMzOqZjOqmTOqzDOq/zPVADPVMzPVZjPVmTPVzDPV/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YrAGYrM2YrZmYrmWYrzGYr/2ZVAGZVM2ZVZmZVmWZVzGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmWaqzGaq/2bVAGbVM2bVZmbVmWbVzGbV/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5krAJkrM5krZpkrmZkrzJkr/5lVAJlVM5lVZplVmZlVzJlV/5mAAJmAM5mAZpmAmZmAzJmA/5mqAJmqM5mqZpmqmZmqzJmq/5nVAJnVM5nVZpnVmZnVzJnV/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wrAMwrM8wrZswrmcwrzMwr/8xVAMxVM8xVZsxVmcxVzMxV/8yAAMyAM8yAZsyAmcyAzMyA/8yqAMyqM8yqZsyqmcyqzMyq/8zVAMzVM8zVZszVmczVzMzV/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8rAP8rM/8rZv8rmf8rzP8r//9VAP9VM/9VZv9Vmf9VzP9V//+AAP+AM/+AZv+Amf+AzP+A//+qAP+qM/+qZv+qmf+qzP+q///VAP/VM//VZv/Vmf/VzP/V////AP//M///Zv//mf//zP///wAAAAAAAAAAAAAAAAgxAAEIHEiw4L6DCBMeFKiw4T6GDhNCjLgQAEWEEylmjLjRYceGHxWGlGjx4sOCKAcGBAA7")
load_image("y_bool", "R0lGODlhDwAPAHAAACH5BAEAAPwALAAAAAAPAA8AhwAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAABVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/wCqAACqMwCqZgCqmQCqzACq/wDVAADVMwDVZgDVmQDVzADV/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMrADMrMzMrZjMrmTMrzDMr/zNVADNVMzNVZjNVmTNVzDNV/zOAADOAMzOAZjOAmTOAzDOA/zOqADOqMzOqZjOqmTOqzDOq/zPVADPVMzPVZjPVmTPVzDPV/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YrAGYrM2YrZmYrmWYrzGYr/2ZVAGZVM2ZVZmZVmWZVzGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmWaqzGaq/2bVAGbVM2bVZmbVmWbVzGbV/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5krAJkrM5krZpkrmZkrzJkr/5lVAJlVM5lVZplVmZlVzJlV/5mAAJmAM5mAZpmAmZmAzJmA/5mqAJmqM5mqZpmqmZmqzJmq/5nVAJnVM5nVZpnVmZnVzJnV/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wrAMwrM8wrZswrmcwrzMwr/8xVAMxVM8xVZsxVmcxVzMxV/8yAAMyAM8yAZsyAmcyAzMyA/8yqAMyqM8yqZsyqmcyqzMyq/8zVAMzVM8zVZszVmczVzMzV/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8rAP8rM/8rZv8rmf8rzP8r//9VAP9VM/9VZv9Vmf9VzP9V//+AAP+AM/+AZv+Amf+AzP+A//+qAP+qM/+qZv+qmf+qzP+q///VAP/VM//VZv/Vmf/VzP/V////AP//M///Zv//mf//zP///wAAAAAAAAAAAAAAAAhLAAEIHEiwIIB9CBMqTChwoUOEDR8iJHZjX0SJDS86HGjx4MGFBiJm/IhwxcWRB5WFJNkRosAYGlvuq0dwI0llMV1KXJjzocGfAwMCADs=")
load_image("icon", "R0lGODlhMAAwAPEDAAAAAADQAO7u7v///yH5BAUKAAMALAAAAAAwADAAAAL/nI+gy+2Pokyv2jazuZxryQjiSJZmyXxHeLbumH6sEATvW8OLNtf5bfLZRLFITzgEipDJ4mYxYv6A0ubuqYhWk66tVTE4enHer7jcKvt0LLUw6P45lvEprT6c0+v7OBuqhYdHohcoqIbSAHc4ljhDwrh1UlgSydRCWWlp5wiYZvmSuSh4IzrqV6p4cwhkCsmY+nhK6uJ6t1mrOhuJqfu6+WYiCiwl7HtLjNSZZZis/MeM7NY3TaRKS40ooDeoiVqIultsrav92bi9c3a5KkkOsOJZpSS99m4k/0zPng4Gks9JSbB+8DIcoQfnjwpZCHv5W+ip4aQrKrB0uOikYhiMCBw1/uPoQUMBADs=")
load_image("n_bool", "R0lGODdhEAAQAPAAAAgICP///ywAAAAAEAAQAAACIISPacHtvp5kcb5qG85hZ2+BkyiRF8BBaEqtrKkqslEAADs=")
load_image("y_bool", "R0lGODdhEAAQAPEAAAgICADQAP///wAAACwAAAAAEAAQAAACMoSPacLtvlh4YrIYsst2cV19AvaVF9CUXBNJJoum7ymrsKuCnhiupIWjSSjAFuWhSCIKADs=")
load_image("n_tri", "R0lGODlhEAAQAPD/AAEBAf///yH5BAUKAAIALAAAAAAQABAAAAInlI+pBrAKQnCPSUlXvFhznlkfeGwjKZhnJ65h6nrfi6h0st2QXikFADs=")
load_image("m_tri", "R0lGODlhEAAQAPEDAAEBAeQMuv///wAAACH5BAUKAAMALAAAAAAQABAAAAI5nI+pBrAWAhPCjYhiAJQCnWmdoElHGVBoiK5M21ofXFpXRIrgiecqxkuNciZIhNOZFRNI24PhfEoLADs=")
load_image("y_tri", "R0lGODlhEAAQAPEDAAICAgDQAP///wAAACH5BAUKAAMALAAAAAAQABAAAAI0nI+pBrAYBhDCRRUypfmergmgZ4xjMpmaw2zmxk7cCB+pWiVqp4MzDwn9FhGZ5WFjIZeGAgA7")
@ -355,7 +355,7 @@ def _load_images():
load_image("y_my", "R0lGODlhEAAQAPH/AAAAAADQAAPRA////yH5BAUKAAQALAAAAAAQABAAAAM+SArcrhCMSSuIM9Q8rxxBWIXawIBkmWonupLd565Um9G1PIs59fKmzw8WnAlusBYR2SEIN6DmAmqBLBxYSAIAOw==")
load_image("n_locked", "R0lGODlhEAAQAPABAAAAAP///yH5BAUKAAEALAAAAAAQABAAAAIgjB8AyKwN04pu0vMutpqqz4Hih4ydlnUpyl2r23pxUAAAOw==")
load_image("m_locked", "R0lGODlhEAAQAPD/AAAAAOQMuiH5BAUKAAIALAAAAAAQABAAAAIylC8AyKwN04ohnGcqqlZmfXDWI26iInZoyiore05walolV39ftxsYHgL9QBBMBGFEFAAAOw==")
load_image("y_locked", "R0lGODlhDwAPAHAAACH5BAEAAPwALAAAAAAPAA8AhwAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAABVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/wCqAACqMwCqZgCqmQCqzACq/wDVAADVMwDVZgDVmQDVzADV/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMrADMrMzMrZjMrmTMrzDMr/zNVADNVMzNVZjNVmTNVzDNV/zOAADOAMzOAZjOAmTOAzDOA/zOqADOqMzOqZjOqmTOqzDOq/zPVADPVMzPVZjPVmTPVzDPV/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YrAGYrM2YrZmYrmWYrzGYr/2ZVAGZVM2ZVZmZVmWZVzGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmWaqzGaq/2bVAGbVM2bVZmbVmWbVzGbV/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5krAJkrM5krZpkrmZkrzJkr/5lVAJlVM5lVZplVmZlVzJlV/5mAAJmAM5mAZpmAmZmAzJmA/5mqAJmqM5mqZpmqmZmqzJmq/5nVAJnVM5nVZpnVmZnVzJnV/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wrAMwrM8wrZswrmcwrzMwr/8xVAMxVM8xVZsxVmcxVzMxV/8yAAMyAM8yAZsyAmcyAzMyA/8yqAMyqM8yqZsyqmcyqzMyq/8zVAMzVM8zVZszVmczVzMzV/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8rAP8rM/8rZv8rmf8rzP8r//9VAP9VM/9VZv9Vmf9VzP9V//+AAP+AM/+AZv+Amf+AzP+A//+qAP+qM/+qZv+qmf+qzP+q///VAP/VM//VZv/Vmf/VzP/V////AP//M///Zv//mf//zP///wAAAAAAAAAAAAAAAAg1AAEIHEiwIIB9CBMqTChwoUOEDR8ujCiR4cGKFjFmNFhwX0OOBD1e1EgRY8mKJyWmfAgSZEAAOw==")
load_image("y_locked", "R0lGODlhEAAQAPD/AAAAAADQACH5BAUKAAIALAAAAAAQABAAAAIylC8AyKzNgnlCtoDTwvZwrHydIYpQmR3KWq4uK74IOnp0HQPmnD3cOVlUIAgKsShkFAAAOw==")
load_image("not_selected", "R0lGODlhEAAQAPD/AAAAAP///yH5BAUKAAIALAAAAAAQABAAAAIrlA2px6IBw2IpWglOvTYhzmUbGD3kNZ5QqrKn2YrqigCxZoMelU6No9gdCgA7")
load_image("selected", "R0lGODlhEAAQAPD/AAAAAP///yH5BAUKAAIALAAAAAAQABAAAAIzlA2px6IBw2IpWglOvTah/kTZhimASJomiqonlLov1qptHTsgKSEzh9H8QI0QzNPwmRoFADs=")
load_image("edit", "R0lGODlhEAAQAPIFAAAAAKOLAMuuEPvXCvrxvgAAAAAAAAAAACH5BAUKAAUALAAAAAAQABAAAANCWLqw/gqMBp8cszJxcwVC2FEOEIAi5kVBi3IqWZhuCGMyfdpj2e4pnK+WAshmvxeAcETWlsxPkkBtsqBMa8TIBSQAADs=")
@ -403,9 +403,8 @@ def _init_misc_ui():
# Use the 'clam' theme on *nix if it's available. It looks nicer than the
# 'default' theme.
style = ttk.Style()
style.theme_use("default")
if _root.tk.call("tk", "windowingsystem") == "x11":
style = ttk.Style()
if "clam" in style.theme_names():
style.theme_use("clam")
@ -556,7 +555,7 @@ def _create_kconfig_tree(parent):
tree.tag_configure("y-locked", image=_y_locked_img)
tree.tag_configure("not-selected", image=_not_selected_img)
tree.tag_configure("selected", image=_selected_img)
# tree.tag_configure("edit", image=_edit_img)
tree.tag_configure("edit", image=_edit_img)
tree.tag_configure("invisible", foreground="red")
tree.grid(column=0, row=0, sticky="nsew")
@ -1476,9 +1475,8 @@ def _toggle_showall(_):
def _do_showall():
# Updates the UI for the current show-all setting
# Don't allow turning off show-all if we're in single-menu mode and the
# current menu would become empty
if _single_menu and not _shown_menu_nodes(_cur_menu):
# Don't allow turning off show-all if we'd end up with no visible nodes
if _nothing_shown():
_show_all_var.set(True)
return
@ -1513,6 +1511,17 @@ def _do_showall():
_tree.focus_set()
def _nothing_shown():
# _do_showall() helper. Returns True if no nodes would get
# shown with the current show-all setting. Also handles the
# (obscure) case when there are no visible nodes in the entire
# tree, meaning guiconfig was automatically started in
# show-all mode, which mustn't be turned off.
return not _shown_menu_nodes(
_cur_menu if _single_menu else _kconf.top_node)
def _toggle_tree_mode(_):
# Toggles single-menu mode on/off
@ -1952,9 +1961,7 @@ def _sorted_sc_nodes(cached_nodes=[]):
key=lambda choice: choice.name or "")
cached_nodes += sorted(
[node
for choice in choices
for node in choice.nodes],
[node for choice in choices for node in choice.nodes],
key=lambda node: node.prompt[0] if node.prompt else "")
return cached_nodes
@ -2120,7 +2127,10 @@ def _defaults_info(sc):
if not sc.defaults:
return ""
s = "Defaults:\n"
s = "Default"
if len(sc.defaults) > 1:
s += "s"
s += ":\n"
for val, cond in sc.orig_defaults:
s += " - "

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Lists all user-modifiable symbols that are not given a value in the
configuration file. Usually, these are new symbols that have been added to the
Kconfig files.
The default configuration filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
"""
from __future__ import print_function
import argparse
import sys
from kconfiglib import Kconfig, BOOL, TRISTATE, INT, HEX, STRING, TRI_TO_STR
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--show-help", "-l",
action="store_true",
help="Show any help texts as well")
parser.add_argument(
"kconfig",
metavar="KCONFIG",
nargs="?",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
args = parser.parse_args()
kconf = Kconfig(args.kconfig, suppress_traceback=True)
# Make it possible to filter this message out
print(kconf.load_config(), file=sys.stderr)
for sym in kconf.unique_defined_syms:
# Only show symbols that can be toggled. Choice symbols are a special
# case in that sym.assignable will be (2,) (length 1) for visible
# symbols in choices in y mode, but they can still be toggled by
# selecting some other symbol.
if sym.user_value is None and \
(len(sym.assignable) > 1 or
(sym.visibility and (sym.orig_type in (INT, HEX, STRING) or
sym.choice))):
# Don't reuse the 'config_string' format for bool/tristate symbols,
# to show n-valued symbols as 'CONFIG_FOO=n' instead of
# '# CONFIG_FOO is not set'. This matches the C tools.
if sym.orig_type in (BOOL, TRISTATE):
s = "{}{}={}\n".format(kconf.config_prefix, sym.name,
TRI_TO_STR[sym.tri_value])
else:
s = sym.config_string
print(s, end="")
if args.show_help:
for node in sym.nodes:
if node.help is not None:
# Indent by two spaces. textwrap.indent() is not
# available in Python 2 (it's 3.3+).
print("\n".join(" " + line
for line in node.help.split("\n")))
break
if __name__ == "__main__":
main()

View File

@ -0,0 +1,48 @@
From 93daf46f309b0c8f86149ef58c4906387d054c22 Mon Sep 17 00:00:00 2001
From: Ulf Magnusson <ulfalizer@gmail.com>
Date: Tue, 9 Jun 2015 13:01:34 +0200
Subject: [PATCH] Kconfiglib scripts/kconfig/Makefile patch
---
scripts/kconfig/Makefile | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 3f327e21f60e..8b7dd1292005 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -27,2 +27,31 @@ gconfig: $(obj)/gconf
+PHONY += scriptconfig iscriptconfig kmenuconfig guiconfig dumpvarsconfig
+
+PYTHONCMD ?= python
+kpython := PYTHONPATH=$(srctree)/Kconfiglib:$$PYTHONPATH $(PYTHONCMD)
+
+ifneq ($(filter scriptconfig,$(MAKECMDGOALS)),)
+ifndef SCRIPT
+$(error Use "make scriptconfig SCRIPT=<path to script> [SCRIPT_ARG=<argument>]")
+endif
+endif
+
+scriptconfig:
+ $(Q)$(kpython) $(SCRIPT) $(Kconfig) $(if $(SCRIPT_ARG),"$(SCRIPT_ARG)")
+
+iscriptconfig:
+ $(Q)$(kpython) -i -c \
+ "import kconfiglib; \
+ kconf = kconfiglib.Kconfig('$(Kconfig)'); \
+ print('A Kconfig instance \'kconf\' for the architecture $(ARCH) has been created.')"
+
+kmenuconfig:
+ $(Q)$(kpython) $(srctree)/Kconfiglib/menuconfig.py $(Kconfig)
+
+guiconfig:
+ $(Q)$(kpython) $(srctree)/Kconfiglib/guiconfig.py $(Kconfig)
+
+dumpvarsconfig:
+ $(Q)$(kpython) $(srctree)/Kconfiglib/examples/dumpvars.py $(Kconfig)
+
menuconfig: $(obj)/mconf
--
2.20.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,246 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Implements oldconfig functionality.
1. Loads existing .config
2. Prompts for the value of all modifiable symbols/choices that
aren't already set in the .config
3. Writes an updated .config
The default input/output filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
Entering '?' displays the help text of the symbol/choice, if any.
Unlike 'make oldconfig', this script doesn't print menu titles and comments,
but gives Kconfig definition locations. Printing menus and comments would be
pretty easy to add: Look at the parents of each item, and print all menu
prompts and comments unless they have already been printed (assuming you want
to skip "irrelevant" menus).
"""
from __future__ import print_function
import sys
from kconfiglib import Symbol, Choice, BOOL, TRISTATE, HEX, standard_kconfig
# Python 2/3 compatibility hack
if sys.version_info[0] < 3:
input = raw_input
def _main():
# Earlier symbols in Kconfig files might depend on later symbols and become
# visible if their values change. This flag is set to True if the value of
# any symbol changes, in which case we rerun the oldconfig to check for new
# visible symbols.
global conf_changed
kconf = standard_kconfig(__doc__)
print(kconf.load_config())
while True:
conf_changed = False
for node in kconf.node_iter():
oldconfig(node)
if not conf_changed:
break
print(kconf.write_config())
def oldconfig(node):
"""
Prompts the user for a value if node.item is a visible symbol/choice with
no user value.
"""
# See main()
global conf_changed
# Only symbols and choices can be configured
if not isinstance(node.item, (Symbol, Choice)):
return
# Skip symbols and choices that aren't visible
if not node.item.visibility:
return
# Skip symbols and choices that don't have a prompt (at this location)
if not node.prompt:
return
if isinstance(node.item, Symbol):
sym = node.item
# Skip symbols that already have a user value
if sym.user_value is not None:
return
# Skip symbols that can only have a single value, due to selects
if len(sym.assignable) == 1:
return
# Skip symbols in choices in y mode. We ask once for the entire choice
# instead.
if sym.choice and sym.choice.tri_value == 2:
return
# Loop until the user enters a valid value or enters a blank string
# (for the default value)
while True:
val = input("{} ({}) [{}] ".format(
node.prompt[0], _name_and_loc_str(sym),
_default_value_str(sym)))
if val == "?":
_print_help(node)
continue
# Substitute a blank string with the default value the symbol
# would get
if not val:
val = sym.str_value
# 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 sym.type == HEX and not val.startswith(("0x", "0X")):
val = "0x" + val
old_str_val = sym.str_value
# Kconfiglib itself will print a warning here if the value
# is invalid, so we don't need to bother
if sym.set_value(val):
# Valid value input. We're done with this node.
if sym.str_value != old_str_val:
conf_changed = True
return
else:
choice = node.item
# Skip choices that already have a visible user selection...
if choice.user_selection and choice.user_selection.visibility == 2:
# ...unless there are new visible symbols in the choice. (We know
# they have y (2) visibility in that case, because m-visible
# symbols get demoted to n-visibility in y-mode choices, and the
# user-selected symbol had visibility y.)
for sym in choice.syms:
if sym is not choice.user_selection and sym.visibility and \
sym.user_value is None:
# New visible symbols in the choice
break
else:
# No new visible symbols in the choice
return
# Get a list of available selections. The mode of the choice limits
# the visibility of the choice value symbols, so this will indirectly
# skip choices in n and m mode.
options = [sym for sym in choice.syms if sym.visibility == 2]
if not options:
# No y-visible choice value symbols
return
# Loop until the user enters a valid selection or a blank string (for
# the default selection)
while True:
print("{} ({})".format(node.prompt[0], _name_and_loc_str(choice)))
for i, sym in enumerate(options, 1):
print("{} {}. {} ({})".format(
">" if sym is choice.selection else " ",
i,
# Assume people don't define choice symbols with multiple
# prompts. That generates a warning anyway.
sym.nodes[0].prompt[0],
sym.name))
sel_index = input("choice[1-{}]: ".format(len(options)))
if sel_index == "?":
_print_help(node)
continue
# Pick the default selection if the string is blank
if not sel_index:
choice.selection.set_value(2)
break
try:
sel_index = int(sel_index)
except ValueError:
print("Bad index", file=sys.stderr)
continue
if not 1 <= sel_index <= len(options):
print("Bad index", file=sys.stderr)
continue
# Valid selection
if options[sel_index - 1].tri_value != 2:
conf_changed = True
options[sel_index - 1].set_value(2)
break
# Give all of the non-selected visible choice symbols the user value n.
# This makes it so that the choice is no longer considered new once we
# do additional passes, if the reason that it was considered new was
# that it had new visible choice symbols.
#
# Only giving visible choice symbols the user value n means we will
# prompt for the choice again if later user selections make more new
# choice symbols visible, which is correct.
for sym in choice.syms:
if sym is not choice.user_selection and sym.visibility:
sym.set_value(0)
def _name_and_loc_str(sc):
# Helper for printing the name of the symbol/choice 'sc' along with the
# location(s) in the Kconfig files where it is defined. Unnamed choices
# return "choice" instead of the name.
return "{}, defined at {}".format(
sc.name or "choice",
", ".join("{}:{}".format(node.filename, node.linenr)
for node in sc.nodes))
def _print_help(node):
print("\n" + (node.help or "No help text\n"))
def _default_value_str(sym):
# Returns the "m/M/y" string in e.g.
#
# TRISTATE_SYM prompt (TRISTATE_SYM, defined at Kconfig:9) [n/M/y]:
#
# For string/int/hex, returns the default value as-is.
if sym.type in (BOOL, TRISTATE):
return "/".join(("NMY" if sym.tri_value == tri else "nmy")[tri]
for tri in sym.assignable)
# string/int/hex
return sym.str_value
if __name__ == "__main__":
_main()

View File

@ -0,0 +1,28 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Updates an old .config file or creates a new one, by filling in default values
for all new symbols. This is the same as picking the default selection for all
symbols in oldconfig, or entering the menuconfig interface and immediately
saving.
The default input/output filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
print(kconf.load_config())
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,49 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Saves a minimal configuration file that only lists symbols that differ in value
from their defaults. Loading such a configuration file is equivalent to loading
the "full" configuration file.
Minimal configuration files are handy to start from when editing configuration
files by hand.
The default input configuration file is '.config'. A different input filename
can be passed in the KCONFIG_CONFIG environment variable.
Note: Minimal configurations can also be generated from within the menuconfig
interface.
"""
import argparse
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"--out",
metavar="MINIMAL_CONFIGURATION",
default="defconfig",
help="Output filename for minimal configuration (default: defconfig)")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config())
print(kconf.write_min_config(args.out))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,92 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Simple utility for setting configuration values from the command line.
Sample usage:
$ setconfig FOO_SUPPORT=y BAR_BITS=8
Note: Symbol names should not be prefixed with 'CONFIG_'.
The exit status on errors is 1.
The default input/output configuration file is '.config'. A different filename
can be passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
"""
import argparse
import sys
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"--no-check-exists",
dest="check_exists",
action="store_false",
help="Ignore assignments to non-existent symbols instead of erroring "
"out")
parser.add_argument(
"--no-check-value",
dest="check_value",
action="store_false",
help="Ignore assignments that didn't \"take\" (where the symbol got a "
"different value, e.g. due to unsatisfied dependencies) instead "
"of erroring out")
parser.add_argument(
"assignments",
metavar="ASSIGNMENT",
nargs="*",
help="A 'NAME=value' assignment")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config())
for arg in args.assignments:
if "=" not in arg:
sys.exit("error: no '=' in assignment: '{}'".format(arg))
name, value = arg.split("=", 1)
if name not in kconf.syms:
if not args.check_exists:
continue
sys.exit("error: no symbol '{}' in configuration".format(name))
sym = kconf.syms[name]
if not sym.set_value(value):
sys.exit("error: '{}' is an invalid value for the {} symbol {}"
.format(value, kconfiglib.TYPE_TO_STR[sym.orig_type],
name))
if args.check_value and sym.str_value != value:
sys.exit("error: {} was assigned the value '{}', but got the "
"value '{}'. Check the symbol's dependencies, and make "
"sure that it has a prompt."
.format(name, value, sym.str_value))
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,7 @@
[bdist_wheel]
# We support both Python 2 and Python 3
universal = 1
[metadata]
# Include the license file in wheels
license_file = LICENSE.txt

96
tools/kconfiglib/setup.py Normal file
View File

@ -0,0 +1,96 @@
import io
import os
import setuptools
setuptools.setup(
name="kconfiglib",
# MAJOR.MINOR.PATCH, per http://semver.org
version="14.1.0",
description="A flexible Python Kconfig implementation",
# Make sure that README.rst decodes on Python 3 in environments that use
# the C locale (which implies ASCII), by explicitly giving the encoding.
#
# io.open() has the 'encoding' parameter on both Python 2 and 3. open()
# doesn't have it on Python 2. This lets us use the same code for both.
long_description=io.open(
os.path.join(os.path.dirname(__file__), "README.rst"),
encoding="utf-8"
).read(),
url="https://github.com/ulfalizer/Kconfiglib",
author='Ulf "Ulfalizer" Magnusson',
author_email="ulfalizer@gmail.com",
keywords="kconfig, kbuild, menuconfig, configuration-management",
license="ISC",
py_modules=(
"kconfiglib",
"menuconfig",
"guiconfig",
"genconfig",
"oldconfig",
"olddefconfig",
"savedefconfig",
"defconfig",
"alldefconfig",
"allnoconfig",
"allmodconfig",
"allyesconfig",
"listnewconfig",
"setconfig",
),
entry_points={
"console_scripts": (
"menuconfig = menuconfig:_main",
"guiconfig = guiconfig:_main",
"genconfig = genconfig:main",
"oldconfig = oldconfig:_main",
"olddefconfig = olddefconfig:main",
"savedefconfig = savedefconfig:main",
"defconfig = defconfig:main",
"alldefconfig = alldefconfig:main",
"allnoconfig = allnoconfig:main",
"allmodconfig = allmodconfig:main",
"allyesconfig = allyesconfig:main",
"listnewconfig = listnewconfig:main",
"setconfig = setconfig:main",
)
},
# Note: windows-curses is not automatically installed on Windows anymore,
# because it made Kconfiglib impossible to install on MSYS2 with pip
# Needs support for unnumbered {} in format() and argparse
python_requires=">=2.7,!=3.0.*,!=3.1.*",
project_urls={
"GitHub repository": "https://github.com/ulfalizer/Kconfiglib",
"Examples": "https://github.com/ulfalizer/Kconfiglib/tree/master/examples",
},
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Topic :: System :: Operating System Kernels :: Linux",
"License :: OSI Approved :: ISC License (ISCL)",
"Operating System :: POSIX",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
)

File diff suppressed because it is too large Load Diff

View File

@ -243,16 +243,16 @@ def exclude_utestcases(RTT_ROOT):
if line.find('examples/utest/testcases/Kconfig') == -1:
f.write(line)
# menuconfig for Linux
# menuconfig for Linux and Windows
def menuconfig(RTT_ROOT):
import menuconfig
# Exclude utestcases
exclude_utestcases(RTT_ROOT)
kconfig_dir = os.path.join(RTT_ROOT, 'tools', 'kconfig-frontends')
os.system('scons -C ' + kconfig_dir)
if sys.platform != 'win32':
touch_env()
touch_env()
env_dir = get_env_dir()
if isinstance(env_dir, str):
os.environ['PKGS_ROOT'] = os.path.join(env_dir, 'packages')
@ -260,8 +260,8 @@ def menuconfig(RTT_ROOT):
fn = '.config'
fn_old = '.config.old'
kconfig_cmd = os.path.join(RTT_ROOT, 'tools', 'kconfig-frontends', 'kconfig-mconf')
os.system(kconfig_cmd + ' Kconfig')
sys.argv = ['menuconfig', 'Kconfig']
menuconfig._main()
if os.path.isfile(fn):
if os.path.isfile(fn_old):
@ -278,7 +278,7 @@ def menuconfig(RTT_ROOT):
# guiconfig for windows and linux
def guiconfig(RTT_ROOT):
import pyguiconfig
import guiconfig
# Exclude utestcases
exclude_utestcases(RTT_ROOT)
@ -294,7 +294,7 @@ def guiconfig(RTT_ROOT):
fn_old = '.config.old'
sys.argv = ['guiconfig', 'Kconfig']
pyguiconfig._main()
guiconfig._main()
if os.path.isfile(fn):
if os.path.isfile(fn_old):
@ -331,3 +331,35 @@ def guiconfig_silent(RTT_ROOT):
# silent mode, force to make rtconfig.h
mk_rtconfig(fn)
def genconfig() :
from SCons.Script import SCons
PreProcessor = SCons.cpp.PreProcessor()
try:
f = open('rtconfig.h', 'r')
contents = f.read()
f.close()
except :
print("Open rtconfig.h file failed.")
PreProcessor.process_contents(contents)
options = PreProcessor.cpp_namespace
try:
f = open('.config', 'w')
for (opt, value) in options.items():
if type(value) == type(1):
f.write("CONFIG_%s=%d\n" % (opt, value))
if type(value) == type('') and value == '':
f.write("CONFIG_%s=y\n" % opt)
elif type(value) == type('str'):
f.write("CONFIG_%s=%s\n" % (opt, value))
print("Generate .config done!")
f.close()
except:
print("Generate .config file failed.")

View File

@ -121,19 +121,18 @@ def AddOptions():
action = 'store_true',
default = False,
help = 'reset the project configurations to default')
AddOption('--pyconfig',
AddOption('--pyconfig', '--guiconfig',
dest = 'pyconfig',
action = 'store_true',
default = False,
help = 'Python GUI menuconfig for RT-Thread BSP')
AddOption('--pyconfig-silent',
AddOption('--pyconfig-silent', '--defconfig',
dest = 'pyconfig-silent',
action = 'store_true',
default = False,
help = 'Don`t show pyconfig window')
if platform.system() != 'Windows':
AddOption('--menuconfig',
dest = 'menuconfig',
action = 'store_true',
default = False,
help = 'make menuconfig for RT-Thread BSP')
AddOption('--menuconfig',
dest = 'menuconfig',
action = 'store_true',
default = False,
help = 'make menuconfig for RT-Thread BSP')