The build2 Kconfig Module

Revision 0.1.0, October 2021
This revision of the document describes the build2 Kconfig module 0.1.X series.

Copyright © 2020-2021 the build2 authors.
Permission is granted to copy, distribute and/or modify this document under the terms of the GPLv2 license.

Table of Contents

Preface
1Introduction
1.1What is Kconfig?
1.2What is build2 Kconfig module?
2Interface and Functionality
2.1Configuration Methods
2.2Configuring and Loading
2.3External Kconfig Macro Variables
3Kconfig Language
3.1Option (config)
3.1.1Prompt and Help
3.1.2Type, Default Value, and Range
3.1.3Dependencies
3.1.4Reverse Dependencies
3.1.5Expressions
3.2Menu (menu)
3.3Choice (choice)
3.4Comment (comment)
3.5Source (source)
3.6Macro Language
3.7Helper Options
3.8Modularity Support
3.9Backwards Compatibility

Preface

This document describes the build2 Kconfig module. It starts with an introduction to the Linux kernel configuration system (Kconfig) and the build2 Kconfig module. The next chapter expands on that and describes the integration of Kconfig into the build2 configuration model in more detail.

The remainder of the document serves as a guide to the Kconfig language with examples based on the kconfig-hello package. Besides this guide, see also the official Kconfig Language and Kconfig Macro Language documentation as well as the Kconfig Tips and Best Practices from the Zephyr project.

1 Introduction

This chapter provides a brief overview of the Linux kernel configuration system (Kconfig) and the functionality provided by the build2 Kconfig module. Its aim is to show how everything fits and works together based on a customary "Hello, World!" example.

1.1 What is Kconfig?

Kconfig is the configuration system of the Linux kernel. Over the years it has evolved into a sophisticated variability modeling language and a toolset that are used by the Linux kernel to manage over ten thousand configuration options. It is also increasingly being used by other projects that need to manage complex configurations.

The Kconfig system consists of the following main parts:

The configuration definition language, or the Kconfig language for short, defines a hierarchy of menus containing configuration options as well as relationships between them. Traditionally, configuration definitions are stored in files called Kconfig (with a capital K). Here is a simple configuration containing two options:

config FANCY
        bool "Fancy options"
        help
          Enable more fancy configuration options.

config GREETING
        string "Custom greeting"
        default "Hello"
        depends on FANCY
        help
          Custom string to use as a greeting.

While the examples in this document assume a UNIX-like operation system, they should work with minimal modifications on Windows.

To create and manage configurations, the Kconfig system includes a number of tools called configurators. The most prominent of those are kconfig-conf which provides a terminal-based question-and-answer configuration method, kconfig-mconf which provides a terminal-based menu configuration method based on a curses library, and kconfig-qconf which provides a graphical configuration method based on Qt. The kconfig-conf configurator also provides a number of non-interactive configuration methods (default, random, etc), support for updating old configurations to new definitions (both interactively and non), as well as other configuration management facilities (creation of default configurations, etc).

Given the above configuration definition saved in the Kconfig file, we can run one of the configurators to create a new configuration. For example:

$ kconfig-conf Kconfig
*
* Main menu
*
Fancy options (FANCY) [N/y/?] (NEW) y
  Custom greeting (GREETING) [Hello] (NEW) Hi
#
# configuration written to .config
#

The configuration values are saved into a file that is traditionally called .config though this naming convention is not as universal as for the definition file (Kconfig). If we examine the .config file produced by the above command, we will see the following:

#
# Automatically generated file; DO NOT EDIT.
# Main menu
#
CONFIG_FANCY=y
CONFIG_GREETING="Hi"

The Kconfig system is best suited for complex configuration requirements where user input is needed at least in some situations (for example, new platforms, custom/optimized configurations, etc). Some of its more advanced features include:

1.2 What is build2 Kconfig module?

The build2 Kconfig module provides the ability to use the Linux kernel configuration system to configure build2 projects. Specifically, it integrates the execution of one of the Kconfig configurators into the build2 configure meta-operation and loads the resulting configuration file presenting its values as kconfig.* Buildfile variables. We can then use these kconfig.* values to make decisions in buildfiles, testscripts, and/or propagate them to our source code, similar to config.* values (Project Configuration).

As an example, let's see what it takes to add the Kconfig configuration shown in the previous section to a simple build2 project. As a first step, let's create the libhello library using bdep-new(1):

$ bdep new -l c++ -t lib --no-init libhello
$ cd libhello

Next we copy the Kconfig definition file from the previous section into the libhello/build/ subdirectory:

$ cp ../Kconfig build/

Finally, we edit libhello/build/bootstrap.build and load the kconfig module. Here is what the new bootstrap.build could look like:

project = libhello

using version
using config
using kconfig
using test
using install
using dist

The kconfig module is part of the standard pre-installed build2 modules and no extra integration steps are required other than the using directive in bootstrap.build.

Now if we configure our project, we will see the familiar prompt:

$ b configure
kconfig build/config.kconfig.new
*
* libhello 0.1.0-a.0.19700101000000
*
Fancy options (FANCY) [N/y/?] (NEW) y
  Custom greeting (GREETING) [Hello] (NEW) Hi
save build/config.build
mv build/config.kconfig.new build/config.kconfig

From other diagnostics we can gather that the configuration file was saved as build/config.kconfig. The reason for first saving it as config.kconfig.new is explained in the next chapter. We can confirm that its contents are similar to what we have already seen:

$ cat build/config.kconfig
#
# Automatically generated file; DO NOT EDIT.
# libhello 0.1.0-a.0.19700101000000
#
CONFIG_FANCY=y
CONFIG_GREETING="Hi"

The only difference in this file (as well as in the above prompt) is the replacement of Main menu with libhello 0.1.0-a.0.19700101000000. As the name suggests, this is the title of the main menu which is the root of the Kconfig menu hierarchy. Customarily, it is set to the project name and version which the kconfig module does automatically. However, it can also be set to a custom value with the kconfig.kconfig.title variable, as discussed later.

By default the kconfig module uses the terminal-based question-and-answer configurator. It's a conservative choice that will work in most circumstances and is built into the module, so the presence of the kconfig-conf executable is not required. However, we can use the config.kconfig variable to select a different configurator. For example, we can reconfigure our project using the graphical kconfig-qconf configurator This requires the presence of the kconfig-qconf executable:

$ b configure config.kconfig=qconf

The CONFIG_* values from the configuration file are made available as kconfig.<project>.* variables in buildfiles with the configuration option name converted to the lower case. For example, we can examine our values by adding the following info directives at the beginning of libhello/buildfile:

info "fancy: $kconfig.libhello.fancy"
info "greeting: $kconfig.libhello.greeting"

If we now update our libhello project, we should see the following output:

$ b
libhello/buildfile:1:1: info: fancy: true
libhello/buildfile:2:1: info: greeting: Hi
...

The Kconfig configuration is also reported at a sufficiently high verbosity level (Configuration Report). For example:

$ b configure -v
kconfig libhello@/tmp/libhello/
  fancy      true
  greeting   Hi

The configuration values (fancy and greeting) used in this example are the same as what's shown in Project Configuration and the same mechanisms for post-processing and propagating configuration values apply here; in most examples from that chapter you can simply replace config.libhello.* with kconfig.libhello.*.

Note, however, that if a non-bool option is disabled (for example, because its dependencies are unsatisfied), then the corresponding kconfig.* variable will be null. At the same time, the in module treats a null substitution as an error unless a fallback value is specified with the in.null variable. As a result, if non-bool kconfig.* variables are used in the .in file substitutions, then it is a good idea to specify the fallback, for example:

h{config}: in{config}
{
  # Instruct the in rule to substitute null with empty.
  #
  in.null = ''
}

See kconfig-hello for a complete example that uses these mechanisms.

Analogous to configure, the standard disfigure meta-operation removes the Kconfig configuration, or, more precisely, moves it to config.kconfig.old. For example:

$ b disfigure
mv build/config.kconfig build/config.kconfig.old
rm build/config.build

And that's pretty much all we have to do to integrate Kconfig-based configuration management into our project. One last touch would be to add config.kconfig to build/.gitignore, next to config.build:

/config.build
/config.kconfig*
...

We've used a wildcard after config.kconfig to also ignore intermediate config.kconfig.new files (discussed later) as well as the config.kconfig.old file where Kconfig configurators traditionally save the previous configuration.

The next chapter, Interface and Functionality, provides more details on the functionality offered by the kconfig module, including the available configurators, customization points, etc. For an introduction to the Kconfig language that also covers relevant build2 integration aspects, refer to Kconfig Language.

2 Interface and Functionality

This chapter provides a more detailed discussion of the kconfig module's interface and functionality including its integration with the config module's configuration process as well as the customization points available to projects that use Kconfig.

2.1 Configuration Methods

As we have seen in the introduction, the config.kconfig variable can be used to select an alternative configurator, such as mconf or qconf. This variables also controls a few other aspects of producing new or updating an existing configuration which together we will call a configuration method. It has the following overall structure:

[(new|old)-](def|ask|reask|mconf|qconf|env) [...]

The optional first component controls the reuse of existing config.kconfig. If new is specified, then the configuration is created from scratch (with existing config.kconfig, if exists, saved as config.kconfig.old). If old is specified, then the configuration is created based on existing config.kconfig (with what "based" means determined by the second component). In this case, it's an error for there to be no existing config.kconfig. If the first component is omitted, then existing config.kconfig is reused if present (old semantics) and created from scratch otherwise (new semantics).

Given a configuration option definition in the Kconfig file, its value can come from the following sources:

  1. Existing config.kconfig file.
  2. Default configuration file.
  3. Default value from the Kconfig file.

A configuration option that does not have a value in existing config.kconfig is referred to as a newly-defined configuration option. Naturally, if config.kconfig does not exist or is not used (because of the new first component), then all options are newly-defined.

The second component determines the configurator and its mode and has the following possible values:

def [file]
Set newly-defined configuration options to values from file if specified and to their default values from Kconfig otherwise (if some options are missing in file, they are set to default values as well). To reset all the configuration options, use new-def.
ask [file]
Ask for values of only newly-defined configuration options. For default answers use values from file if specified and default values from Kconfig otherwise.

Note that if config.kconfig does not exist or is not used (new-ask) then this method is equivalent to reask.

reask [file]
Ask for values of all the configuration options. For default answers use values from config.kconfig if exists, from file if specified, and default values from Kconfig otherwise.
mconf
Present all the configuration options in a menu interface. For default answers, use values from config.kconfig if exists and default values from Kconfig otherwise.
qconf
Present all the configuration options in a graphical interface. For default answers, use values from config.kconfig if exists and default values from Kconfig otherwise.
env prog [args]
Run prog in the configuration environment (KCONFIG_CONFIG, etc) passing the Kconfig file as the last argument. For example:
config.kconfig="env kconfig-conf --savedefconfig defconfig.kconfig"

The def, ask, and reask methods are implemented as builtins and do not require the presence of the kconfig-conf executable.

If no configuration method is specified with config.kconfig, then ask is used by default. However, a project may specify a different default configuration method as discussed in the next section.

Mapping for some of the kconfig-conf options to the above methods:

--oldconfig             ask
--oldaskconfig          reask
--olddefconfig          def
--alldefconfig      new-def
--defconfig <file>  new-def <file>

Note that the following methods have no kconfig-conf equivalents:

old-def <file>
[re]ask <file>

Another useful application of the env method is the generation of random configurations with the kconfig-conf --randconfig mode. For example:

$ b configure config.kconfig="env kconfig-conf -s --randconfig"
kconfig build/config.kconfig.new
KCONFIG_SEED=0xD6A72753
save build/config.build
mv build/config.kconfig.new build/config.kconfig

This can be used to automatically try various configurations, for example, by continuously configuring and testing the project in a loop This example is UNIX-specific:

$ while \
  b configure config.kconfig="env kconfig-conf -s --randconfig" && \
  b test; do :; done

As can be seen on the previous listing, in the --randconfig mode, kconfig-conf prints the seed that it used to generate the configuration. This seed can be passed back to kconfig-conf as an environment variable in order to recreate the same random configuration. For example:

$ KCONFIG_SEED=0xD6A72753 \
  b configure config.kconfig="env kconfig-conf -s --randconfig"

Another useful --randconfig environment variable is KCONFIG_ALLCONFIG which can be used to specify a configuration file containing a subset of options that must be set to specific rather than random values.

2.2 Configuring and Loading

As mentioned briefly in the introduction, kconfig acts as a second-level configuration mechanism to the builtin support in the form of config.* variables and the config module. In particular, the kconfig module hooks into the configure and disfigure meta-operations of the config module providing an integrated configuration process. It is also possible to use the config.* variables (as well as other Buildfile variables) as inputs to the kconfig configuration. This chapter provides more details on how this is achieved and the available customization points.

To understand how kconfig fits in, we begin with an overview of the builtin configuration process, that is, what happens when we execute the configure meta-operation. While the config module is loaded in bootstrap.build, the config.build file (if exists) is loaded as a first step of loading root.build (more precisely, config.build is loaded before any bootstrapped module is initialized, which happens prior to loading root.build). After that, root.build and the rest of the project are loaded as usual. In particular, during this stage, root.build or any other buildfile can examine the config.* variables (as loaded from config.build and/or specified as command line overrides) and cause this stage to fail (for example, using the assert directive) if any values are deemed invalid. If, however, loading of the project succeeds, the config module saves the new config.build file which completes the configure meta-operation.

The important point about this process is that the new configuration is saved as the last step, after successfully loading the project. And the kconfig module attempts to provide the second-level configuration semantics that is consistent with this behavior. Specifically, while the kconfig module must also be loaded (bootstrapped) in bootstrap.build, it also delays loading config.kconfig until later. However, unlike the config module, by default, kconfig loads its configuration after root.build. This semantics was chosen to allow the first-level configuration as well as any other information made available by modules loaded in root.build to influence the Kconfig configuration. However, we can also load config.kconfig at any point in root.build by explicitly loading (initializing) the kconfig module. For example, continuing with the libhello project from the previous chapter, we could have something like this in our root.build:

using cxx

using kconfig

if ($kconfig.libhello.fancy && $cxx.target.class == 'windows')
  fail "have to keep it basic on Windows"

Similar to the config behavior, the kconfig module also saves the configuration only after the project has successfully been loaded. Achieving this semantics, however, is not as straightforward as in the config module because the configuration must also be made available during the project loading, as discussed above. To implement this, kconfig first saves the configuration to a temporary file, config.kconfig.new, and then renames it to config.kconfig at the end. Specifically, the kconfig module performs the following steps during configure:

bootstrap.build
Register the post-configure callback with the config module.
root.build
Run the configurator saving the result to config.kconfig.new.
configure
In post-configure rename config.kconfig.new to config.kconfig.

When not configuring, the kconfig module simply loads config.kconfig and verifies it is up-to-date with definitions in Kconfig. If that's not the case, for example, because we've added or removed a configuration option, then kconfig fails suggesting that we reconfigure the project.

As mentioned in the previous section, a project may specify the default configuration method that will be used if not explicitly specified with config.kconfig. More precisely, the project may set any of the kconfig.kconfig.{configure,reconfigure,retryconfigure} variables to select the default method for creating new, updating existing, and trying to fix previously created/updated configuration, respectively.

To elaborate, the kconfig.kconfig.configure method is used when configuring a project from scratch, without existing config.kconfig, while kconfig.kconfig.reconfigure is used while reconfiguring a project with existing config.kconfig. The kconfig.kconfig.retryconfigure method is used when reconfiguring a project with existing config.kconfig.new, which normally means that the previous (re)configuration attempt has failed or was interrupted. The default values for these variables are reask, ask, and reask, respectively.

Setting kconfig.kconfig.retryconfigure to a method that does not allow the user to adjust every configuration option may result in an invalid configuration that can only be fixed by first disfiguring the project.

As an example, if we wanted our project to use the default values from Kconfig and only use interactive configuration if explicitly requested by the user (or if the default configuration turned out to be invalid), we could add the following to our root.build before loading kconfig:

kconfig.kconfig.configure = new-def
kconfig.kconfig.reconfigure = old-def

using kconfig

Provided this makes sense for your project, it's a good idea to make the default configuration method non-interactive. This will allow you to use the CI service and, if desired, publish your project to a package repository. While interactive default configuration may make sense for an end-product kind of projects, for reusable components such as libraries a non-interactive default that enables most of the functionality is probably the best choice. See Project Configuration for background.

What happens if we try to build our project without config.kconfig? By default kconfig fails suggesting that we configure the project. However, this behavior can be altered with the kconfig.kconfig.transient variable. Setting it to ask (which is the default), disables the ability to use transient configurations. But in the above project it would make sense to also use default values for transient configurations, for example:

kconfig.kconfig.configure = new-def
kconfig.kconfig.reconfigure = old-def
kconfig.kconfig.transient = def

using kconfig

Besides the default values from Kconfig files, another common source of default values are default configurations. This method becomes more appropriate when we have multiple sets of default values, for instance, one per target platform. As an example, let's convert the above project to use the default configuration files in the defconfig-platform.kconfig form where platform is the target class as supplied by the cxx.target.class variable (linux, windows, macos, etc). Here are the changes to root.build:

using cxx

defconfig = $src_root/build/defconfig-$(cxx.target.class).kconfig

kconfig.kconfig.configure = new-def $defconfig
kconfig.kconfig.reconfigure = old-def $defconfig
kconfig.kconfig.transient = def $defconfig

using kconfig

The build/Kconfig file and files that it sources (transitively) as well as build/defconfig*.kconfig are automatically added to the distribution and need not be explicitly mentioned as prerequisites in buildfiles.

While any Kconfig configuration file can serve as a default configuration, normally a minimal version is produced using kconfig-conf --savedefconfig. Given a suitably configured project, we can extract the corresponding default configuration using the env method:

$ b configure config.kconfig=\
"env kconfig-conf --savedefconfig defconfig-linux.kconfig"

We can also do it manually given just the configuration file, for example:

$ KCONFIG_CONFIG=config.kconfig \
  kconfig-conf --savedefconfig defconfig-linux.kconfig Kconfig

If your Kconfig definition file relies on external inputs (as discussed next), then with the manual extraction you will also need to manually supply such inputs via environment variables.

2.3 External Kconfig Macro Variables

Selecting the default configuration based on the target platform as shown in the previous section is one example of using information from the first-level configuration and/or modules loaded before kconfig to adjust the Kconfig configuration. It is, however, also possible to modify the Kconfig definition file itself based on such information by setting external Kconfig macro variables.

The Kconfig language includes a macro variable facility that can be used for textual substitution (see Macro Language for details). As an example, let's try to improve on our previous attempt to only allow fancy options in certain cases. To recap, this is what we did:

using cxx

using kconfig

if ($kconfig.libhello.fancy && $cxx.target.class == 'windows')
  fail "have to keep it basic on Windows"

Ideally, instead of allowing the user to select the FANCY option and then complaining that it can't be selected for certain platforms, we would want to make it impossible to select it in the first place when configuring for such platforms. As a first step, let's introduce a Kconfig macro variable and make the FANCY option depend on its value:

ENABLE_FANCY := y

config FANCY
        bool "Fancy options"
        depends on $(ENABLE_FANCY)
        help
          Enable more fancy configuration options.

...

With this change we can now enable/disable the fancy options by adjusting the ENABLE_FANCY Kconfig macro variable. The next step is to somehow set it from outside the Kconfig file. With the kconfig module we can do that by simply setting the corresponding Kconfig.* variable (with a capital K) in our buildfile. If invoking one of the configurators directly, then such variables are set via the environment. In our example, let's remove the ENABLE_FANCY assignment from Kconfig and rewrite root.build as follows:

using cxx

Kconfig.ENABLE_FANCY = ($cxx.target.class != 'windows')

using kconfig

Kconfig.* values of type bool are automatically converted from Buildfile true/false to Kconfig y/n. Other value types are passed to Kconfig by converting to string.

The Kconfig macro variables can be used in many contexts, for example, in default values. However, such dynamically-changing Kconfig definitions become hard to reason about and can lead to surprises. As a result, it's probably wise to limit the use of external variables to disabling options and menus rather than altering their definitions.

A macro substitution referencing a variable that is not set inside the Kconfig file nor via the Kconfig.* Buildfile variable is an error. The only builtin variable set automatically by the kconfig module is SRC_ROOT which contains the project's source root directory (the same as the src_root Buildfile variable). It is normally used to source (Source) additional Kconfig files, for example:

source "$(SRC_ROOT)/libhello/Kconfig"

3 Kconfig Language

Kconfig is a line-oriented language. That is, a construct ends at the end of the line unless escaped with line continuation (trailing \). The # character starts a comment with everything from this character until the end of the line ignored. This character and other special characters (quotes, $, etc) can be escaped with a backslash.

Kconfig has single-quoted (') and double-quoted (") strings with identical semantics. Inside strings, all characters except the closing quote and $ (macro substitution) are treated literally. For example, the following two Kconfig strings are the same:

"foo \"bar\" \$(baz)"
'foo "bar" \$(baz)'

A Kconfig file starts with zero or more macro variable assignments (Macro Language) followed by zero or more Kconfig definitions which may source (Source) other Kconfig files. Each definition starts with a keyword. For example:

# This is a comment.

DEFAULT_GREETING := Hello

config GREETING
        string "Custom greeting"
        default "$(DEFAULT_GREETING)"

source "$(SRC_ROOT)/Kconfig"

The following synopsis lists all the available Kconfig definitions with the subsequent sections explaining their semantics using examples from the kconfig-hello package. For additional background and details see also the official Kconfig Language and Kconfig Macro Language documentation as well as the Kconfig Tips and Best Practices from the Zephyr project.

config symbol
      type [prompt [if expr]]
      prompt prompt [if expr]
      default value [if expr]
      range integer integer [if expr]
      depends on expr
      select symbol [if expr]
      imply symbol [if expr]
      help
        text

if expr
...
endif

menu prompt
      visible if expr
      depends on expr
...
endmenu

menuconfig symbol
      ...

choice [symbol]
      optional
      default symbol [if expr]
      ...
...
endchoice

comment prompt
      depends on expr

source path

type    = bool | string | int | hex | tristate
value   = (y|n) | string | integer | (y|m|n)
string  = "text" | 'text'
integer = dec-integer | 0xhex-integer
prompt  = string
path    = string

term = symbol | value
expr = term            |
       term = term     |
       term != term    |
       term < term     |
       term > term     |
       term <= term    |
       term >= term    |
       ( expr )        |
       ! expr          |
       expr && expr    |
       expr || expr

3.1 Option (config)

config symbol
      type [prompt [if expr]]
      prompt prompt [if expr]
      default value [if expr]
      range integer integer [if expr]
      depends on expr
      select symbol [if expr]
      imply symbol [if expr]
      help
        text

if expr
...
endif

type    = bool | string | int | hex | tristate
value   = (y|n) | string | integer | (y|m|n)
string  = "text" | 'text'
integer = dec-integer | 0xhex-integer
prompt  = string

term = symbol | value
expr = term            |
       term = term     |
       term != term    |
       term < term     |
       term > term     |
       term <= term    |
       term >= term    |
       ( expr )        |
       ! expr          |
       expr && expr    |
       expr || expr

The central part of Kconfig is the configuration option definition with the rest of the language is mostly serving to organize options into sub-menus. A simple Kconfig file may consist of just option definitions which all become entries of the implicitly-defined main menu (discussed in the next section).

The option definition starts with the config keyword followed by the option name, which in the Kconfig language is called a symbol. For example:

config IO
        bool "IO support"
        help
          Enable stdin/stdout input/output. Note that if this option
          is disabled, then you won't see any output.

Other Kconfig documentation often uses the term symbol to mean the configuration option, not just its name.

The name is traditionally spelled in upper case and is the same name that will end up in the configuration file but prefixed with CONFIG_ and as a Buildfile variable but converted into lower case and prefixed with kconfig.<project>..

Following the config keyword and the name we have a number of lines that define the option's attributes. They are traditionally indented by 8 spaces (or an equivalent TAB). While none of the attributes are mandatory, a definition will normally include at least the type and usually also the prompt and help, as in the above example.

A number of attributes support the trailing if expr condition. If specified, the attribute only applies if the expression evaluates to true (Expressions). Such attributes can also be specified multiple times. For example:

config GREETING_TEXT
        string "Custom greeting" if GREETING_CUSTOM
        default "Hello" if GREETING_HELLO
        default "Hi"    if GREETING_HI
        default "Howdy" if GREETING_HOWDY
        help
          Custom string to use as a greeting.

In this example, the GREETING_TEXT option will only be visible if the GREETING_CUSTOM option is selected and the default value is chosen based on which GREETING_H* option is selected.

3.1.1 Prompt and Help

config symbol
      type [prompt [if expr]]
      prompt prompt [if expr]
      help
        text

string  = "text" | 'text'
prompt  = string

The configuration option prompt is a short text that describes the option to the user while the option help provides a more detailed description. For example:

config IO
        bool
        prompt "IO support"
        help
          Enable stdin/stdout input/output. Note that if this option
          is disabled, then you won't see any output.

If an option has a visible prompt (that is, the prompt is not disabled with if expr) and its dependencies are satisfied (Dependencies), then the option is presented to the user for customization. For example:

$ b configure
IO support (IO) [N/y/?] (NEW) ?

CONFIG_IO:

Enable stdin/stdout input/output. Note that if this option
is disabled, then you won't see any output.

Symbol: IO [=n]
Type  : bool
Defined at kconfig-hello/build/Kconfig:18
  Prompt: IO support
  Location:
    -> Basic options

The option prompt can be specified with the prompt attribute as in the above example or it can be combined with the type attribute for brevity. For example:

config IO
        bool "IO support"
        ...

This shorter version is customarily preferred unless selecting between several prompts with if expr. In both versions the prompt text can be specified using either single or double quotes.

The option help often contains several lines of text and is specified indented (customarily with 2 spaces) relative to the line that contains the help keyword. The help text ends at the line that has a smaller indentation than the first line of the help text.

While an option with an invisible prompt cannot be modified by the user, it can still be modified by other options through reverse dependencies and its value is accessible via the corresponding kconfig.* variable. An option with an absent prompt that is selected through such reverse dependencies is called a helper option. See Helper Options for more information on their use-cases.

3.1.2 Type, Default Value, and Range

config symbol
      type [prompt [if expr]]
      default value [if expr]
      range integer integer [if expr]

type    = bool | string | int | hex | tristate
value   = (y|n) | string | integer | (y|m|n)
string  = "text" | 'text'
integer = dec-integer | 0xhex-integer

Configuration option type can be bool (boolean), string, int (decimal integer), hex (hexadecimal integer), and tristate:

bool
True or false state. Values of this type are spelled as y or n, for example:
config FOO
        bool
        default y

When converted to the kconfig.* variables, such values have the bool Buildfile type.

string
Text string. Values of this type are spelled using either single or double quotes, for example:
config FOO
        string
        default "foo"

When converted to the kconfig.* variables, such values have the string Buildfile type.

int
Signed 64-bit decimal integer. Values of this type are spelled as a sequence of decimal digits, for example:
config FOO
        int
        default 123

When converted to the kconfig.* variables, such values have the int64 Buildfile type.

hex
Unsigned 64-bit hexadecimal integer. Values of this type are spelled as a sequence of hexadecimal digits prefixed with 0x, for example:
config FOO
        hex
        default 0x1ab2c3d4

When converted to the kconfig.* variables, such values have the uint64 Buildfile type.

tristate
Like bool but with an extra state (m) used to express modularity. See Modularity Support for details on this functionality.

The kconfig.* variables are overridable which means, similar to the first-level configuration, we can temporarily tweak the Kconfig configuration (as seen by buildfiles) without reconfiguring the project. For example:

$ b kconfig.hello.io=false

Note, however, that such changes do not go through the usual Kconfig processing which, in particular, means no option dependency resolution is performed. As a result, care must be taken not to end up with an invalid configuration.

The default value for a configuration option can be specified with the default attribute. For example:

config PUNCT
        string "End of greeting punctuation"
        default "!"
        help
          Character for punctuating the end of the greeting sentence.

This value will be used as the suggested answer in interactive configurations methods and as a fallback in non-interactive ones (see Configuration Methods for details). If no default value is specified, n is assumed for bool and tristate and empty string for string while there is no assumed default for int and hex.

While int and hex options without default values are valid, creating a configuration in a way that would require default values (for example with the config.kconfig=def method) is an error.

Options of type int and hex can also specify the expected value range with the range attribute (both ends are inclusive). If specified, the user will not be allowed to enter a value that is out of this range. For example:

config NAME_ASK_MAX
        int "Max times to ask for name"
	default 5
	range 1 10
        help
          Maximum number of times to ask for the name to greet.

3.1.3 Dependencies

config symbol
      depends on expr

if expr
...
endif

The depends on attribute is used to specify a dependency of one option on another. Collectively, dependencies determine what configurations are valid. For example:

config IO
        bool "IO support"

config NAME_ASK
        bool "Ask for name"
        depends on IO

If an option's dependency is not satisfied, then the option becomes disabled: the user is not prompted for its value and its default value is not used. For bool and tristate, the disabled option is set to n. For other types, the disabled option's value is not set and the corresponding kconfig.* variable is null.

We use the term enabled/disabled when we refer to the option's state based on its dependencies and visible/invisible – based on its prompt. An option is only presented to the user for customization if it is both enabled and visible. If a bool option is set to y, we call it selected.

The depends on attribute can also be used to specify a dependency on an expression involving more than one option or non-boolean options (see Expressions for details). For example:

config IO
        bool "IO support"

config RETRY
        int "Max times to retry"

config NAME_ASK
        bool "Ask for name"
        depends on IO && RETRY != 0

Specifying multiple depends on attributes is equivalent to specifying their expressions with a single depends on attribute combined with &&. For example, this variant is equivalent to the above:

config NAME_ASK
        bool "Ask for name"
        depends on IO
        depends on RETRY != 0

If we have multiple options with the same dependency, then instead of repeating the depends on attribute for each of them we can use the if-block for a more succinct result. For example:

config IO
        bool "IO support"

if IO

config NAME_ASK
        bool "Ask for name"

config TRACE
        bool "Trace execution"

endif

The semantics of the if-block is equivalent to specifying an explicit depends on attribute with the if-expression for each entry until endif.

3.1.4 Reverse Dependencies

config symbol
      select symbol [if expr]
      imply symbol [if expr]

A reverse dependency is used to select an option from another option. For example:

config IO
        bool "IO support"

config NAME_ASK
        bool "Ask for name"
        select IO

In this example, if NAME_ASK is set to y, then IO is forced to y as well.

Reverse dependencies can only be used with bool and tristate options and there are two flavors: strong and weak.

A strong reverse dependency is specified with the select attribute. It forces the option specified after the select keyword to y whenever the option containing this attribute is set to y (for tristate options, the same logic applies for m). And by forces we mean just that: it disregards unsatisfied dependencies and user selection.

Note that this forceful nature of strong reverse dependencies often leads to puzzling configuration issues. For example, a user may be trying to unsuccessfully disable a feature without realizing that it is forced by another, seemingly unrelated option. Such issues can be very frustrating and time-consuming to figure out and, as a result, the use of reverse dependencies on user-visible options is not recommended. Using select on invisible options, however, is a useful technique as described in Helper Options.

A weak reverse dependency is specified with the imply attribute. As the name suggests, it does not force but merely recommends. The other option can still be set to n by the user or if any of its dependencies are unsatisfied. For example:

config IO
        bool "IO support"
        default y
        imply NAME_ASK

config NAME_ASK
        bool "Ask for name"

In this example, if the user selects y for IO, then the prompt for NAME_ASK will also have y as the default answer. However, the user can still disable NAME_ASK by answering n. Similarly, if configuring non-interactively using the default values (config.kconfig=def), then NAME_ASK will be set to y because IO is set to y (because of its default y attribute).

3.1.5 Expressions

value   = (y|n) | string | integer | (y|m|n)
string  = "text" | 'text'
integer = dec-integer | 0xhex-integer

term = symbol | value
expr = term            |
       term = term     |
       term != term    |
       term < term     |
       term > term     |
       term <= term    |
       term >= term    |
       ( expr )        |
       ! expr          |
       expr && expr    |
       expr || expr

Kconfig expressions are used in a number of option attributes to determine visibility, establish dependencies, and to enable default values. And as we will see in later sections, they are also used for similar purposes in other Kconfig definitions. The result of evaluating an expression is boolean y (true) or n (false).

More precisely, Kconfig expressions use the tristate logic with the extra m state used to represent modularity. For the evaluation purposes, the m state is equivalent to y if modules are enabled. See Modularity Support for details.

Expression alternatives in the above production are listed in the decreasing order of precedence. Values in expressions are spelled as in the default attribute (Type, Default Value, and Range).

A terminal expression consisting of a symbol evaluates to true if the corresponding option is of type bool (or tristate) and is y (or m and modules are enabled). In this context options of all other types always evaluate to n.

A terminal expression consisting of a value evaluates to true if it is either y or "y" (or m or "m" and modules are enabled). For example See External Kconfig Macro Variables for a more realistic example:

ENABLE_FANCY := y

config IO
        bool "IO support"

config FANCY
        bool "Fancy options"
        depends on IO
        depends on $(ENABLE_FANCY)

Terminals (symbol or value) can be compared for being equal/unequal less/greater, and less-or-equal/greater-or-equal. Finally, sub-expression can be grouped with parenthesis, negated, and combined with logical AND and OR. For example:

FALLBACK_NAME := ...

config IO
        bool "IO support"

config RETRY
        int "Max times to retry"

config NAME_ASK
        bool "Ask for name"
        depends on IO && (RETRY != 0 || "$(FALLBACK_NAME)" = "")

3.2 Menu (menu)

menu prompt
      visible if expr
      depends on expr
...
endmenu

menuconfig symbol
      ...

Menus are used to organize options into a tree-like hierarchy as an aid to the user. Normally a menu would contain related options. If a menu contains a large number of options, then some of them can be organized into sub-menus and so on.

The menu definition starts with the menu keyword followed by the menu prompt. Similar to an option, a menu may specify a number of attributes on the following lines. After the menu definition and before the matching endmenu keyword, any option, sub-menu, etc., all belong to this menu and are collectively called menu entries. For example:

menu "Basic options"

config IO
        bool "IO support"
        help
          Enable stdin/stdout input/output. Note that if this option
          is disabled, then you won't see any output.

config PUNCT
        string "End of greeting punctuation"
        default "!"
        help
          Character for punctuating the end of the greeting sentence.

endmenu

Similar to option prompts, menu prompts are presented to the user during option customization. For example:

$ b configure
*
* Basic options
*
IO support (IO) [N/y/?] (NEW) y
End of greeting punctuation (PUNCT) [!] (NEW) !!!

The menu visibility can be controlled with the visible if attribute. If its expression evaluates to false, then neither the menu itself nor any of its entries are presented to the user. For example:

menu "Fancy options"
        visible if IO

...

endmenu

Menu visibility is the extension of the option prompt visibility in that an option that belongs to an invisible menu has the same semantics as if it had an invisible prompt (Prompt and Help).

Another attribute of a menu definition is depends on. Specifying this attribute is equivalent to specifying it for every option that belongs to this menu, recursively (Dependencies).

The Kconfig menu hierarchy always starts with an implicitly-defined main menu. While it is possible to customize its prompt in the Kconfig file using the mainmenu definition, customarily it is set to the project name and version which the kconfig module does automatically. It can also be customized by setting the kconfig.kconfig.title variable in root.build before loading the kconfig module.

Specifying mainmenu in the Kconfig file is not recommended when used with build2 because there can only be one such definition thus making the result non-composable. And there are plans for the kconfig module to automatically aggregate Kconfig configurations of multiple projects into a single configurator invocation.

When organizing options into menus we often encounter a pattern where a configuration option enables a menu, for example:

config FANCY
        bool "Fancy options"
        help
          Enable more fancy configuration options.

menu "Fancy options"
  depends on FANCY

config GREETING
        string "Custom greeting"
        help
          Custom string to use as a greeting.

config NAME_ASK
        bool "Ask for name"
        help
          Ask for the name to greet if it is unspecified on the
          command line.
endmenu

Regardless of how we structure this (option outside or inside the menu), the user interface will have a separate entry for the option and the menu while what we want here is to combine them. To achieve this we use the menuconfig hybrid menu/option. For example:

menuconfig FANCY
        bool "Fancy options"
        help
          Enable more fancy configuration options.

if FANCY

config GREETING
        string "Custom greeting"
        ...

config NAME_ASK
        bool "Ask for name"
        ...

endif

The menuconfig definition has the same semantics and attributes as config but additionally establishes a sub-menu and treats all the following entries (options, menus) that have a dependency on its symbols as sub-menu entries until encountering the first entry without such a dependency. The common approach to establish such a dependency is to use the if-block as in the example above.

If you are wondering why menuconfig does not use an explicit end marker similar to endmenu, you are not alone. It is probably a remnant of the automatic menu generation described next.

Even if we didn't use menuconfig in the above example, Kconfig would analyze the dependency relationship and generate a menu-like structure automatically. Specifically, all the immediately following entries that have a dependency on the preceding option are treated as its sub-entries and displayed as belonging to this option. What "displayed as belonging" means, exactly, depends on the configurator and in some it may be indistinguishable from menuconfig.

3.3 Choice (choice)

choice [symbol]
      optional
      default symbol [if expr]
      ...
...
endchoice

Choices are used to restrict the selection to the at most one option from a set. In a way, they can be viewed as a variant of the menu concept but where instead of all the options the user can select only one.

The choice definition starts with the choice keyword optionally followed by the choice name. Similar to options and menus, a choice may specify a number of attributes on the following lines. After the choice definition and before the matching endchoice keyword comes a number of options (normally two or more) collectively called choice options. Choice options can only be of type bool and tristate. For example:

choice
        prompt "Greeting"
        default GREETING_HELLO
        help
          String to use as a greeting.

config GREETING_HELLO
        bool "\"Hello\""
        select GREETING_BUILTIN

config GREETING_HI
        bool "\"Hi\""
        select GREETING_BUILTIN

config GREETING_HOWDY
        bool "\"Howdy\""
        select GREETING_BUILTIN

config GREETING_CUSTOM
        bool "Custom greeting"

endchoice

Given the above choice, the user could be presented with the following interface:

$ b configure
Greeting
> 1. "Hello" (GREETING_HELLO) (NEW)
  2. "Hi" (GREETING_HI) (NEW)
  3. "Howdy" (GREETING_HOWDY) (NEW)
  4. Custom greeting (GREETING_CUSTOM) (NEW)
choice[1-4?]:

Choices with tristate options allow selecting multiple options provided they are all set to m. See Modularity Support for details.

Two commonly used choice attributes are default and optional. The default attribute is used to specify the default selection as shown in the example above. The optional attribute makes the choice optional allowing the user not to select any of the choice options.

A non-optional choice without a default value will currently result in an invalid configuration if configuring non-interactively using the default values (config.kconfig=def). As a result, it is recommended to always specify default values for non-optional choices.

A choice definition can specify any of the other configuration option attributes, however, not all of them make sense in all situations. In practice, there are two common patterns of choice usage: a simple choice without a name and an optional choice with a name. Here is the overall structure of the first pattern (which is also used in the above example):

choice
        prompt "Prompt text"
        default DEFAULT_OPTION

...

endchoice

In the second pattern, the optional choice is given a name that is used as a helper (Helper Options) to determine whether any of the choice options were selected. Such a choice may or may not have the default value. Here is its overall structure:

choice CHOICE_NAME
       bool "Prompt text"
       optional
       default DEFAULT_OPTION

...

endchoice

And here is a concrete example of such a choice:

choice NAME_FALLBACK
       bool "Name fallback"
       optional
       help
         Fallback name to use if it is unspecified on the command
         line.

config NAME_ASK
        bool "Ask for name"
        help
          Ask for the name to greet if it is unspecified on the
          command line.

config NAME_DEF
        bool "Use default name"
        help
          Use the default name to greet if it is unspecified on the
          command line.

endchoice

At the Buildfile level we can then use kconfig.<project>.name_fallback to determine if any of the choice options were selected, for example:

if $kconfig.hello.name_fallback
{
  if $kconfig.hello.name_ask
    ...

  if $kconfig.hello.name_def
    ...
}

3.4 Comment (comment)

comment prompt
      depends on expr

A comment is used to add a notice to the user during configuration. It is also written into the resulting configuration file.

The comment definition starts with the comment keyword followed by the comment prompt (text). For example:

comment "IO disabled, no output will be shown"
        depends on !IO

Similar to other entries, a comment may specify a number of attributes on the following lines. Currently the only valid comment attribute is depends on which can be used to make a comment conditional, as shown in the example above.

3.5 Source (source)

source path

path = string

The source definition is used to source (include) one Kconfig file into another. It starts with the source keyword followed by the path string.

For example, if you would like your Kconfig file to reside in the root directory of your project (which is customary in several projects that use Kconfig, including the Linux kernel), then you can place the following line in your build/Kconfig and then write the rest of the definitions in the root Kconfig:

source "$(SRC_ROOT)/Kconfig"

As mentioned in External Kconfig Macro Variables, SRC_ROOT is the pre-defined variable that contains the project's source root directory (the same as src_root in buildfiles). It should normally be used as a base for all your source definitions.

While we can specify a relative path to source, the historic Kconfig semantics is to first try to open such a path relative to the current working directory. Since build2 does not assume any particular current working directory, the use of absolute paths based on SRC_ROOT is strongly recommended.

Note also that on Windows all Kconfig paths use forward slashes as directory separators, including the SRC_ROOT macro variable. You should also use the forward slashes when forming paths based on SRC_ROOT, as in the above example.

As another example, consider the following Kconfig fragment which is commonly misunderstood:

if IO
source "$(SRC_ROOT)/build/Kconfig-io"
endif

This is not a conditional inclusion. Rather, it is an unconditional inclusion with all the definitions inside Kconfig-io now depending on IO (Dependencies).

There is no conditional inclusion in Kconfig nor, more generally, any ability to conditionally exclude a fragment of the Kconfig file. The closest we can get is probably a conditional selection of the file to source based on the external macro variable. For example, in our root.build we could have the following fragment:

using cxx

Kconfig.PLATFORM = $cxx.target.class

using kconfig

And then in the Kconfig file write the following which would include Kconfig-linux, Kconfig-windows, etc., depending on the platform we are targeting:

source "$(SRC_ROOT)/build/Kconfig-$(PLATFORM)"

Note also that if you are using this technique, then you will need to explicitly mention such Kconfig-* files as prerequsites in a buildfile in order for them to be included into the distribution. For example, in your root buildfile you could have:

./: ... build/file{Kconfig-*}

3.6 Macro Language

The Kconfig language provides support for make-like macro substitution. Conceptually, there are two languages layered one on top of the other: the bottom layer is the macro language that performs plain textual substitutions. The result is then used as input to the top layer, which is the Kconfig definition language. For example:

DEFAULT_GREETING := Hey there

config GREETING
        string "Custom greeting"
        default "$(DEFAULT_GREETING)"

After the macro substitution, the top layer will see:

config GREETING
        string "Custom greeting"
        default "Hey there"

Macro substitutions can appear in pretty much any context, including prompts, default values, expressions, and so on. It is, however, important to keep in mind that macro variable names and option names/symbols operate in different languages. In particular, while a macro variable can contain an option name (symbol) it cannot contain an "expansion" (that is, a value) of an option. For example, the following does not make sense:

GREETING_VALUE = $(GREETING)

config GREETING
        string "Custom greeting"
        default "Hello"

While this conceptual model is helpful as an understanding aid, this is not exactly how the implementation works and there are some restrictions. Specifically, Kconfig keywords cannot be the result of the macro substitution nor can substitutions span multiple Kconfig tokens. Refer to the official Kconfig Macro Language documentation for details.

Macro variables can only be assigned at the beginning of a Kconfig file before any Kconfig definitions (options, menus, etc). Similar to make, there is no need to quote values in a macro variable assignment unless we want the value to contain literal quotes. For example, this version is equivalent to the above:

DEFAULT_GREETING := "Hey there"

config GREETING
        string "Custom greeting"
        default $(DEFAULT_GREETING)

During substitution, the corresponding value is first looked up in the variable assignments of the Kconfig file. If not found, then the value is looked up in the Kconfig.* Buildfile variables with SRC_ROOT being the only pre-defined variable (see External Kconfig Macro Variables for details). An undefined variable substitution is an error.

For example, instead of setting DEFAULT_GREETING in the Kconfig file as above, we could set it from root.build:

Kconfig.DEFAULT_GREETING = '"Hey there"'

using kconfig

As another example, we can pass the platform we are targeting as a macro variable:

using cxx

Kconfig.PLATFORM = $cxx.target.class

using kconfig

And then use it in Kconfig to conditionally enable options, choose their default values, and so on:

config IO
        bool "IO support"
        depends on "$(PLATFORM)" != "windows"

config GREETING
        string "Custom greeting"
        default "Hey" if "$(PLATFORM)" = "linux"
        default "Hello"

comment "Targeting $(PLATFORM)"

Note also that due to the two-layer textual substitution semantics all variable references are always substituted. For example:

config GREETING
        string "Custom greeting"
        default $(DEFAULT_GREETING_IO) if IO
        default $(DEFAULT_GREETING) if !IO

In this example, both DEFAULT_GREETING and DEFAULT_GREETING_IO must always be defined regardless of which default value is (later) used.

Similar to make, Kconfig supports both simple and recursively-expanding variables with the latter used as a building block to support functions. For details, refer to the official Kconfig Macro Language documentation.

The use of the builtin shell function in the context of build2 is not recommended since it will most likely result in portability issues and poor performance.

3.7 Helper Options

An option without a prompt or with a prompt that is disabled by if expr is invisible to the user. However, such an option can still take on a default value or be set by select and imply (Reverse Dependencies) with the result still usable inside the Kconfig file, for example, for other option's dependencies, as well as accessible outside through the kconfig.* Buildfile variables. Such options are called helper options. For example:

choice
        prompt "Greeting"
        default GREETING_HELLO

config GREETING_HELLO
        bool "\"Hello\""
        select GREETING_BUILTIN

config GREETING_HI
        bool "\"Hi\""
        select GREETING_BUILTIN

config GREETING_HOWDY
        bool "\"Howdy\""
        select GREETING_BUILTIN

config GREETING_CUSTOM
        bool "Custom greeting"

endchoice

config GREETING_BUILTIN
        bool

In this example GREETING_BUILTIN is a helper option that is set to true when one of the builtin greeting strings is selected. It can then be used as a dependency for another option, for example:

config PUNCT
        string "End of greeting punctuation"
        default "!"
        depends on !GREETING_BUILTIN
        help
          Character for punctuating the end of the custom greeting
          sentence.

Continuing with the above example, here is another option that becomes a helper if we are using one of the builtin greeting strings:

config GREETING_TEXT
        string "Custom greeting" if GREETING_CUSTOM
        default "Hello" if GREETING_HELLO
        default "Hi"    if GREETING_HI
        default "Howdy" if GREETING_HOWDY
        help
          Custom string to use as a greeting.

The idea here is that now we have an option that contains the greeting string in both the builtin and custom cases. As a result, instead of having to write something like this in our buildfile:

if $kconfig.hello.greeting_builtin
{
  if $kconfig.hello.greeting_hello
    greeting = 'Hello'
  elif $kconfig.hello.greeting_hi
    greeting = 'Hi'
  elif $kconfig.hello.greeting_howdy
    greeting = 'Howdy'
  else
    fail 'unhandled builtin greeting'
}
else
  greeting = $kconfig.hello.greeting_text

We can just have:

greeting = $kconfig.hello.greeting_text

3.8 Modularity Support

The Kconfig language provides support for configuration options that besides being selected (y) or not (n) can also be selected as a module (m).

While it may be tempting to try to re-purpose this support for something similar but not quite the same, modularity in Kconfig is fairly purpose-built for the Linux kernel needs and straying too far from its intended semantics will likely result in a poor fit.

The central part of this functionality is the tristate type which, in addition to the bool's y and n states, has the third m state. When converted to the kconfig.* variables, tristate is mapped to the string Buildfile type with the true, false, and module possible values.

The availability of this third state is also gated by the specially-designated bool option that determines whether overall modules support is enabled. Similarly, in expressions (Expressions) m is equivalent to y only if modules are enabled. For example:

config MODULES
       bool "Modules support"
       option modules

config IO
       tristate "IO support"

In the above example, MODULES is designated as the modules option with the option attribute. If we answer y to MODULES, then for IO we will be able to choose between y, m, and n. However, if MODULES is n, then our choice for IO will be between y and n:

$ b configure
Modules support (MODULES) [Y/n/?] (NEW) y
IO support (IO) [N/m/y/?] (NEW)

$ b configure
Modules support (MODULES) [Y/n/?] (NEW) n
IO support (IO) [N/y/?] (NEW)

If we want to unconditionally enable modules in our project, then we can make the MODULES option prompt-less with y default, for example:

config MODULES
       bool
       default y
       option modules

Only one configuration option can be designated as the module option. This makes it difficult to compose project configuration that use this functionality.

Besides normal options, tristate can also be used in choices. Such a choice allows the user to select only one option as y but more than one as m (again, provided modules are enabled). For example:

choice
        prompt "Name fallback"

config NAME_ASK
        tristate "Ask for name"
        help
          Ask for the name to greet if it is unspecified on the
          command line.

config NAME_DEF
        tristate "Use default name"
        help
          Use the default name to greet if it is unspecified on the
          command line.

endchoice

3.9 Backwards Compatibility

It is typical and well supported by Kconfig to reuse an old configuration when upgrading to a new version of the project (see Configuration Methods for details). As a result, when evolving a project that uses Kconfig, it makes sense to keep backwards compatibility in mind.

Besides a full old configuration, users of our project can also keep minimal default configurations produced with kconfig-conf --savedefconfig. Unlike the full configuration which contains all the values, default configurations only contain values that differ from the defaults. Based on this understanding, these changes normally lead to reasonable backwards compatibility:

In contrast, these changes should normally be avoided: