Guidelines for Writing Good Kconfig Files

Kconfig is very powerful configuration language, but some constructs allowed by syntax may lead to unpredicted consequences. This guide is divided into two sections. In the first_section documentation, kconfcheck, a tool that checks Kconfig and various sdkconfig.* files is described. In the second section, common situations that may lead to problems are described.

The kconfcheck Tool

The kconfcheck tool enforces a specific style of Kconfig and various sdkconfig.* files in order to be more uniform across all ESP-IDF components. In this section, tips and tricks for this tool will be described in the future. In the meantime, please visit the Kconfig Files Checking section in ESP-IDF Documentation.

Useful Tips and Tricks

Dependencies

Sometimes, developers tends to use construct:

if CONDITION

    config OPTION
        bool "Prompt"

endif

Although it may seem similar to many programming languages and thus be favorable by some, it is generally not recommended to use if block in this situation as it is not a proper Kconfig way to write a dependency. Below, there is a revised version of the above code:

config OPTION
    bool "Prompt"
    depends on CONDITION

The if block is primarily used in situations where depends on syntax is not possible (e.g. conditional including of other Kconfig files via source entry).

Reverse Dependencies With non-bool Source Configs

To briefly summarize dependencies in Kconfig, there are two types of dependencies: direct and reverse. Direct dependencies are defined in the target symbol (symbol whose value is changed based on the value of another symbol), while reverse dependencies are defined in the source symbol (symbol whose value changes independently). Although there is no restriction on the type of the target symbol, the source symbol must be of bool type in order to define a reverse dependency.

Note

Please visit the select, imply and set and set default sections for more information about reverse dependencies.

However, in certain situations, it may be necessary to set a value of a non-bool target symbol based on the value of a non-bool source symbol. For example, you may want to set a string target symbol based on the value of a string source symbol. In such cases, there is no way to do this directly. However, by introducing another symbol (a “mapper”), you can achieve the desired result.

Note

All of the following examples can be solved more easily with direct dependencies and/or by default option. Direct dependencies should be preferred if possible. However, target symbol may not be in the same Kconfig file, but e.g. in another component (or more generally, somewhere you cannot edit it) and thus it would be impossible to use direct dependencies.

Suppose you want to set JEDI_NAME to Mace Windu if LIGHTSABER_COLOR is set to purple. In this example, LIGHTSABER_COLOR is a source symbol and JEDI_NAME is a target symbol. It is not possible to do this directly, as the source symbol LIGHTSABER_COLOR is not a bool-type config option. However, if you define a bool-type config option that will be used as a mapper (LIGHTSABER_COLOR_PURPLE), you can achieve the desired result. See the example below:

# This is the target symbol (the one whose value is based on the value of source symbol)
config JEDI_NAME
    string "Name of the Jedi"

# This is the source symbol (the one whose value changes independently)
# It is a string, which means that we cannot use any of the reverse dependency options
# (select, imply, set, set default) on it.
config LIGHTSABER_COLOR
    string "Color of the lightsaber"
    default "purple"

# This is the mapper symbol that will be used to set the target symbol based on the source symbol
config LIGHTSABER_COLOR_PURPLE
    # without a prompt, this symbol will not appear in menuconfig (we don't want the user to change it)
    bool
    default y if LIGHTSABER_COLOR="purple"
    set JEDI_NAME="Mace Windu"

# You can use more mapper symbols for other colors

Previous example supposed that every mapping from LIGHTSABER_COLOR to JEDI_NAME is done by a separate mapper symbol. However, all the mapper symbols can be combined into a single one, which will set the value of JEDI_NAME based on the value of LIGHTSABER_COLOR. See the example below:

# This is the target symbol (the one whose value is based on the value of source symbol)
config JEDI_NAME
    string "Name of the Jedi"

# This is the source symbol (the one whose value changes independently)
# It is a string, which means that we cannot use any of the reverse dependency options
# (select, imply, set, set default) on it.
config LIGHTSABER_COLOR
    string "Color of the lightsaber"
    default "purple"

# This mapper symbol will map any specific value of LIGHTSABER_COLOR to a specific value of JEDI_NAME
config LIGHTSABER_TO_JEDI_NAME
    bool
    default y # needs to be set to y for the set options to take effect
    set JEDI_NAME="Mace Windu" if LIGHTSABER_COLOR="purple"
    set JEDI_NAME="Anakin Skywalker" if LIGHTSABER_COLOR="blue"
    set JEDI_NAME="Darth Vader" if LIGHTSABER_COLOR="red"
    # ...and so on for other colors

In both cases, if none of the set options are satisfied, the value of JEDI_NAME will be empty. You can also add a default value to the JEDI_NAME symbol to avoid JEDI_NAME being empty if none of the set options are satisfied.

You can also use the mapper symbol when source is a non-bool type config option and the target is a bool type config option. Below, there is an example for separate mapper symbols for each name:

# This is the target symbol (the one whose value is based on the value of source symbol)
config IS_JEDI
    bool "Is the person a Jedi?"
    default n

# This is the source symbol (the one whose value changes independently)
config NAME
    string "Name of the person"
    default "Yoda"

# This mapper symbol will map the value of NAME to a boolean value of IS_JEDI
config YODA_IS_JEDI
    bool
    default y if NAME="Yoda"
    select IS_JEDI

# You can add more mapper symbols for other names

It is also possible to use a single mapper symbol that will set the value of IS_JEDI based on several values of NAME. See the example below:

# This is the target symbol (the one whose value is based on the value of source symbol)
config IS_JEDI
    bool "Is the person a Jedi?"
    default n

# This is the source symbol (the one whose value changes independently)
config NAME
    string "Name of the person"
    default "Yoda"

# This mapper symbol will map the value of NAME to a boolean value of IS_JEDI
config NAME_TO_IS_JEDI
    bool
    default y
    select IS_JEDI if NAME="Yoda"
    select IS_JEDI if NAME="Anakin Skywalker"
    # if none of the above conditions are satisfied, IS_JEDI will be set to n