[riot-notifications] [RIOT-OS/RIOT] Modelling modules in Kconfig (#15429)
notifications at github.com
Wed Nov 11 16:14:44 CET 2020
There is currently an ongoing effort to model all RIOT modules' dependencies in Kconfig, in order to use this system for module configuration and selection. This would replace our current Make-based dependency resolution system.
Currently the dependency resolution is done in a sort of top-down fashion (with some caveats), where a module is enabled by adding it to the `USEMODULE` list, and that module is responsible for pulling all the modules it needs, and indicating the features it needs. This happens iteratively until no new modules are added to the list.
Many RIOT developers are used to 'just enable module FOO', which would in many cases (although not all) bring the needed modules to use it. There are some cases where intermediate modules need to be explicitly added, but the logic is not always defined.
### The Kconfig options
The Kconfig approach is based on modelling RIOT modules as Kconfig symbols, leveraging Kconfig's dependency system. Kconfig allows to express dependencies among symbols in the following ways:
#### `depends on`
Expresses a normal dependency, reducing the upper limit of a symbol. In the following example if `MODULE_BAR` is not set to `y`, `MODULE_FOO` can't be enabled by the user (either via `menuconfig` or a configuration file).
<details><summary><b>Example of `depends on`</b></summary>
bool "Bar support"
bool "Foo support"
depends on MODULE_BAR
This expresses a reverse dependency. From the [Linux Kconfig language](https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html) definition:
> While normal dependencies reduce the upper limit of a symbol (see below), reverse dependencies can be used to force a lower limit of another symbol.
The caveat with this attribute is that it does not take into account the direct dependencies of the `select`ed symbol. That's why this note is also present:
> Note: select should be used with care. select will force a symbol to a value without visiting the dependencies. By abusing select you are able to select a symbol FOO even if FOO depends on BAR that is not set. In general use select only for non-visible symbols (no prompts anywhere) and for symbols with no dependencies. That will limit the usefulness but on the other hand avoid the illegal configurations all over.
Currently we are using `select` in our Kconfig files to indicate features, CPUs and to select other *non visible* symbols, and with peripheral drivers. This is because the drivers map 1 to 1 to the features, so the user of the peripheral driver can depend on the feature to avoid selecting the module when the feature is not present.
<details><summary><b>Example of `select`</b></summary>
bool "I2C support"
depends on HAS_PERIPH_I2C
bool "APDS99XX light sensor"
depends on HAS_PERIPH_I2C
A good explanation with examples and alternatives can be found in Zephyr's [Kconfig tips](https://docs.zephyrproject.org/latest/guides/kconfig/tips.html#select-statements).
This attribute expresses a weak reverse dependency between two symbols:
>This is similar to “select” as it enforces a lower limit on another symbol except that the “implied” symbol’s value may still be set to n from a direct dependency or with a visible prompt.
The `imply`ed symbol is enabled only when its dependencies are met, but being disabled is also a valid configuration for the symbol that implies it. This is usually used to enable "nice to have" modules.
### How should we model?
The current make approach has much more in common to dependencies modelled using `select` (top-down) than with `depends on` (bottom-up). There are some cases where this does not work. For instance, when there can be multiple modules that provide a certain feature, or that implement a certain API, or when there are complex conditions for a module to be enabled.
When modelling dependencies using `depends on` more steps may be needed to enable the module we want to use, but there is no risk of illegal conditions (provided that the dependencies are modelled correctly :). Having long chains of `select` does not scale well, and tends to get out of sync when updating dependencies. With `depends on` there is always more control on which is being included on the binary. In both cases interfaces like `menuconfig` can be used to check dependencies and which
symbols select each other.
To try to mitigate the need for extra steps certain modules that are commonly needed can be `default`ed to `y`. This would cause that users that do not need the module will have to explicitly disable it. In the end this is a trade-off between what is enabled usually and what not.
To me the safest way is to limit the usage of `select` to:
- non-visible symbols
- modules that have no dependencies
- particular cases where the dependencies are controlled
The rest should be modelled with `depends on`. Of course common sense always applies.
<details><summary><b>Example of dependencies of AT driver modules</b></summary>
- `MODULE_AT_ISR` depends on `MODULE_EVENT_THREAD` that is why I assumed it was
safe to select `MODULE_EVENT_THREAD_%` modules from the choices.
- `MODULE_FMT` does not present dependencies, so it's selected.
bool "AT (Hayes) command set library"
depends on HAS_PERIPH_UART
depends on TEST_KCONFIG
depends on MODULE_ISRPIPE
depends on MODULE_ISRPIPE_READ_TIMEOUT
bool "Support Unsolicited Result Codes (URC)"
bool "Process URCs when they arrive"
depends on MODULE_AT_URC
depends on MODULE_EVENT_THREAD
To process URCs upon arrival an event thread is used. The
MODULE_EVENT_THREAD symbol should be set. Choose a priority for the
thread that processes the URCs.
endchoice # MODULE_AT_URC_ISR
endif # MODULE_AT
bool "Event queue"
depends on TEST_KCONFIG
This module offers an event queue framework like libevent or libuev.
An event queue is basically a FIFO queue of events, with some functions
to efficiently and safely handle adding and getting events to / from
such a queue.
bool "Support for event handler threads"
There are three threads of different priorities that can be enabled.
bool "Low priority thread"
bool "Medium priority thread"
bool "Highest priority thread"
endif # MODULE_EVENT_THREAD
endif # MODULE_EVENT
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the notifications