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