Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modelling modules in Kconfig #15429

Open
leandrolanzieri opened this issue Nov 11, 2020 · 7 comments
Open

Modelling modules in Kconfig #15429

leandrolanzieri opened this issue Nov 11, 2020 · 7 comments
Labels
Area: Kconfig Area: Kconfig integration Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR State: don't stale State: Tell state-bot to ignore this issue TF: Config Marks issues and PRs related to the work of the Configuration Task Force

Comments

@leandrolanzieri
Copy link
Contributor

leandrolanzieri commented Nov 11, 2020

Introduction

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).

Example of `depends on`
config MODULE_BAR
    bool "Bar support"

config MODULE_FOO
    bool "Foo support"
    depends on MODULE_BAR

select

This expresses a reverse dependency. From the Linux Kconfig language 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 selected 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.

Example of `select`
config MODULE_PERIPH_I2C
    bool "I2C support"
    depends on HAS_PERIPH_I2C

config MODULE_APDS99XX
    bool "APDS99XX light sensor"
    depends on HAS_PERIPH_I2C
    select MODULE_PERIPH_I2C

A good explanation with examples and alternatives can be found in Zephyr's Kconfig tips.

imply

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 implyed 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 defaulted 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.

Proposal

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.

Example of dependencies of AT driver modules

Note that:

  • MODULE_AT_URC_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.
# drivers/at/Kconfig

menuconfig MODULE_AT
    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
    select MODULE_FMT
    select MODULE_PERIPH_UART

if MODULE_AT

config MODULE_AT_URC
    bool "Support Unsolicited Result Codes (URC)"

config MODULE_AT_URC_ISR
    bool "Process URCs when they arrive"
    depends on MODULE_AT_URC
    depends on MODULE_EVENT_THREAD

choice
    bool "Thread priority"
    depends on MODULE_AT_URC_ISR
    help
        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.

config MODULE_AT_URC_ISR_LOW
    bool "Low"
    select MODULE_EVENT_THREAD_LOW

config MODULE_AT_URC_ISR_MEDIUM
    bool "Medium"
    select MODULE_EVENT_THREAD_MEDIUM

config MODULE_AT_URC_ISR_HIGHEST
    bool "Highest"
    select MODULE_EVENT_THREAD_HIGHEST

endchoice

endif # MODULE_AT
# sys/event/Kconfig

menuconfig MODULE_EVENT
    bool "Event queue"
    depends on TEST_KCONFIG
    select CORE_THREAD_FLAGS
    help
        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.

if MODULE_EVENT

menuconfig MODULE_EVENT_THREAD
    bool "Support for event handler threads"
    help
        There are three threads of different priorities that can be enabled.

if MODULE_EVENT_THREAD

config MODULE_EVENT_THREAD_LOW
    bool "Low priority thread"

config MODULE_EVENT_THREAD_MEDIUM
    bool "Medium priority thread"

config MODULE_EVENT_THREAD_HIGHEST
    bool "Highest priority thread"

endif # MODULE_EVENT_THREAD

[...]

endif # MODULE_EVENT
@leandrolanzieri leandrolanzieri added Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR Area: Kconfig Area: Kconfig integration labels Nov 11, 2020
@leandrolanzieri
Copy link
Contributor Author

Tagging people who I think, might be interested on this: @fjmolinas @aabadie @cgundogan @jia200x @miri64 @maribu

@akshaim
Copy link
Member

akshaim commented Nov 30, 2020

Hi @leandrolanzieri

Can you please elaborate on this?

particular cases where the dependencies are controlled

@leandrolanzieri
Copy link
Contributor Author

@akshaim

Can you please elaborate on this?

particular cases where the dependencies are controlled

With this I mean symbols that have dependencies that are known, and somehow fixed (will not change), so it's safe to move them 'one level up'. The main example for this are the peripheral drivers modules, which always depend on their respective feature:

menuconfig MODULE_PERIPH_SPI
bool "SPI peripheral driver"
depends on HAS_PERIPH_SPI
select MODULE_PERIPH_COMMON

We can safely assume that when the SPI feature is there it is OK to select the SPI peripheral, so we check that feature from the driver symbol. For example:

config MODULE_ADT7310
bool "ADT7310 temperature sensor"
depends on HAS_PERIPH_SPI
depends on TEST_KCONFIG
select MODULE_PERIPH_SPI

@fjmolinas
Copy link
Contributor

Tagging people who I think, might be interested on this: @fjmolinas @aabadie @cgundogan @jia200x @miri64 @maribu

I agree with your proposal.

In order to alleviate the pain of all modules, could we think of providing some default or "starter" configuration files? Examples and
tests would of course be a good source for this. What do you think?

@leandrolanzieri
Copy link
Contributor Author

In order to alleviate the pain of all modules, could we think of providing some default or "starter" configuration files? Examples and
tests would of course be a good source for this. What do you think?

Yes, definitely. Together with the migration the configurations for the applications are needed of course:

# dependencies of AT driver
CONFIG_MODULE_ISRPIPE=y
CONFIG_MODULE_ISRPIPE_READ_TIMEOUT=y
CONFIG_MODULE_AT=y
# support URC processing
CONFIG_MODULE_AT_URC=y
# enable event thread to process URCs upon arrival
CONFIG_MODULE_EVENT=y
CONFIG_MODULE_EVENT_THREAD=y
# support URC upon arrival
CONFIG_MODULE_AT_URC_ISR=y
# enable shell
CONFIG_MODULE_SHELL=y

We could as well place other configurations in some folder and add documentation to them if needed (maybe some sort of "cookbook"?). I can imagine some configuration guide may be needed for complex systems like the network stack.

@stale
Copy link

stale bot commented Jun 4, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Jun 4, 2021
@jeandudey jeandudey added State: don't stale State: Tell state-bot to ignore this issue and removed State: stale State: The issue / PR has no activity for >185 days labels Jun 4, 2021
@MrKevinWeiss MrKevinWeiss added this to the Release 2021.07 milestone Jun 22, 2021
@MrKevinWeiss MrKevinWeiss removed this from the Release 2021.07 milestone Jul 15, 2021
@leandrolanzieri leandrolanzieri added the TF: Config Marks issues and PRs related to the work of the Configuration Task Force label Sep 17, 2021
@MrKevinWeiss
Copy link
Contributor

I guess we can close this now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Kconfig Area: Kconfig integration Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR State: don't stale State: Tell state-bot to ignore this issue TF: Config Marks issues and PRs related to the work of the Configuration Task Force
Projects
None yet
Development

No branches or pull requests

5 participants