Kconfig

This document covers the following aspects of Kconfig:

  1. Kconfig language.

  2. Kconfig naming conventions.

  3. Kconfig file structure.

  4. Use of Kconfig in CMake scripts.

  5. Best practices and tips.

Kconfig is a powerful configuration system. When integrated with CMake, it can achieve an efficient, flexible, and customizable build process for software development. Developers can flexibly configure, customize, and integrate project functionalities based on varied requirements, selecting the appropriate configuration to meet specific project without modifing the macros in the source code.

The generation of a Kconfig configuration file depends on a third-party Python library called Kconfiglib, available at Kconfiglib. To set up the Kconfig configurable file generation environment:

  1. Install Kconfiglib using pip:

    pip install kconfiglib
    
  2. After installation, ensure the Kconfiglib path is added to the environment variables.

  3. Kconfig will generate three files under the include\generated directory: .config, config.cmake and config.h. The CONFIG_ prefix will be added to the configuration symbol in these files. Therefore, do not add the CONFIG_ prefix to symbol names in the Kconfig file.

    • .config is the classic configuration file generated by Kconfig, storing all configuration options as key-value pairs.

    • config.cmake converts Kconfig configurations into CMake variables for CMake-based build systems.

    • config.h converts Kconfig configurations into C/C++ header files for source code integration.

Kconfig syntax is the same as the configuration system used by the Linux kenrnel. User can also refer to the official documentation for the Linux kernel: Kconfig Language and Kconfig macro language.

Kconfig Language

Kconfig symbols include mainmenu, menu/endmenu, config, choice/endchoice, conditional control with if/endif, and the inclusion of other Kconfig files using source/rsource/osource. Configuration item attributes in Kconfig include type (bool/int/hex/string/tristate), prompt message, default values, and the ability to set different values based on various conditions. Visibility can be controlled by dependencies using depends on. Here are some commonly used Kconfig symbols:

  • mainmenu

  • menu/endmenu

  • config

  • menuconfig

  • choice/endchoice

  • source/rsource/osource/orsource

  • if/endif

Config

A config is used to define a configurable option under menu or menconfig, and can also be controlled by conditional statements using if and endif. Each config entry typically includes the name of a configuration option and a series of attributes. Attributes can be the type of the configuration option, input prompt, dependencies, help text and default values.

To ensure clarity and consistency in configuration, each configuration option should have a unique name and should preferably be defined only once in the project. If a configuration option is defined multiple times, especially with the same prompt but different default values, it can lead to confusion and unexpected behavior. It is recommended to use conditional statements and dependencies to manage configuration complexity.

A config can be a visual symbol item when it is defined with a prompt. It will show up in the interactive configuration interfaces, and can be updated by the defconfig file and saved in the configuration file. If a config is without a prompt, it will be invisible. Invisible symbols are not shown in the interactive configuration interface, and can't update this configuration value by the defconfig file.

//example of a invisible configuration symbol
config REALTEK_SOC_SERIES_NAME
   string
   default "RTL8763E"

//example of a visiable configuration symbol
config REALTEK_APP_COMMON_CFU_ENABLE
   bool "use app common cfu"
   default n
   help
      compile app_common_cfu.c

Choice/Endchoice

choice and endchoice are used to define a mutually exclusive set of configuration options, where a user must select exactly one option from the specified list. This is particularly useful when there are multiple ways to configure a feature, but only one can be chosen at a time to prevent conflicting options from being simultaneously selected.

The choice can include a prompt to describe what the selection is about. This prompt is displayed in the configuration interface. Each choice must specify a type. bool is commonly used for options that are either enabled or disabled. A default option can be specified to indicate which choice should be pre-selected if the user doesn't explicitly make a selection. Additionally, depends on directive can be used within the choice block to specify conditions under which the entire set of options becomes visible or available for selection.

choice REALTEK_COMPILE_BANK
   prompt "bank type"
   default REALTEK_COMPILE_BANK0

   config REALTEK_COMPILE_BANK0
      bool "bank 0"

   config REALTEK_COMPILE_BANK1
      bool "bank 1"

endchoice

Source/Rsource/Osource/Orsource

The source, rsource, osource, and orsource directives are used to include other Kconfig files into the current Kconfig file. These statements support glob patterns and include each matching file. A pattern is required to match at least one file. Each of these directives has a specific behavior that dictates how the file paths are resolved or handled.

  1. The source directive is used to include required configuration files with a relative or absolute path. If a relative path is provided, it's relative to the directory of the current Kconfig file that's including it. If the specified file cannot be found or does not exist, an error is generated.

    source "flash_map_config/Kconfig"
    source "drivers/*/Kconfig"
    
  2. The rsource directive is used to include required configuration file with the path relative to the directory of the current Kconfig file that contains the rsource statement, and if the file cannot be found, an error will be generated.

    rsource "../../../Kconfig"
    
  3. osource is used to optionally include another Kconfig file with a relative or absolute path. If the specified file does not exist, no error is generated, and the inclusion is simply skipped.

    osource "Kconfig.RTL8763E"
    
  4. orsource is used to optionally include another Kconfig file with the path relative to the directory of the current Kconfig file that contains the orsource statement, If the specified file does not exist, no error is generated, and the inclusion is simply skipped.

    orsource "./gui/Kconfig.gui"
    

If/Endif

The if directive is used to specify a condition, and any configuration entries between if and endif are included only if the condition evaluates to true. This is useful for enabling or disabling sections of the configuration based on the presence or value of certain options. Conditions are typically based on the value of configuration symbols. They can involve logical operations such as && (AND), || (OR), and ! (NOT).

config FEATURE_A
   bool "Enable Feature A"

config FEATURE_B
   bool "Enable Feature B"

if FEATURE_A

   config OPTION_1
      bool "Option 1"

endif

if !FEATURE_B

   config OPTION_2
      bool "Option 2"

endif

if FEATURE_A && FEATURE_B

   config OPTION_3
      bool "Option 3"

endif

Kconfig Naming Convention

When Kconfig generates macros, it automatically adds the prefix CONFIG_. For example, the macro used in the source code is CONFIG_SAMPLE_ABC, while the configuration used in Kconfig is SAMPLE_ABC.

A defconfig file is a set of configurations to achieve specific functions based on the default values ​​of Kconfig configurations. It is not a complete set of Kconfig configurations. Therefore, the default values ​​of Kconfig configurations should not be changed easily, as this will affect the overall configuration status after loading defconfig. If changes to the default values are necessary, the scope of impact needs to be carefully evaluated.

  1. SOC series configuration:

    The macro prefix for distinguishing IC series is uniformly CONFIG_SOC_SERIES_, such as CONFIG_SOC_SERIES_RTL8763E, CONFIG_SOC_SERIES_RTL8773D, CONFIG_SOC_SERIES_RTL8773E.

  2. IC cut version:

    The macro for distinguishing IC cuts is based on the IC type macro and adds _V0, _V1, _V2 to indicate a cut, b cut, c cut. For example, CONFIG_SOC_SERIES_RTL8763E_V1, CONFIG_SOC_SERIES_RTL8763E_V2, CONFIG_SOC_SERIES_RTL8763E_V3.

  3. Low-level configuration:

    For low-level modules, such as BSP, and application modules that can be replaced with non-REALTEK solutions, the macro prefix is ​​CONFIG_REALTEK_ to distinguish vendors. For example. REALTEK_GPIOB_SUPPORT in Kconfig. When Kconfig generates macros, it will automatically add the CONIFG_ prefix to become CONFIG_REALTEK_GPIOB_SUPPORT.

  4. Application-level configuration:

    For general application-level modules, REALTEK_ prefix is not necessary to be added to Kconfig configuration names.

In general, macro names are composed of module name_function. It is recommended that the string be named from left to right in Kconfig macro naming with each field reflecting the hierarchy level or domain relationship.

The defconfig name corresponds to the Kconfig name, and its naming convention is as follows:

  • The IC series name (RTL8763E/RTL8773E/RTL8773D/RTL8773G) is added in the defconfig file name for applicaiton to identify the IC series type in the CMake configure procedure, such as defconfig.RTL8763E and defconfig.RTL8773D.

  • If target distinction is needed, user can add the target name in the defconfig name, such as defconfig.RTL8763E.bt_audio_trx_4M_lea_dual_bank0 and defconfig.RTL8773D.bt_audio_trx_16M_dual_bank0 for bt_audio_trx applicaiton, defconfig.RTL8763E.all and defconfig.RTL8763E.default for library project. For different library targets, the generated library names are also different, such as libble_mgr_all and libble_mgr_default.

Kconfig File Structure

For SDK user who develop applications based on pre-compiled static libraries, user can configure static library type without modifying the libraries. The detailed configurations in the static libraries remain invisible for the user. Taking the application bt_audio_trx as an example, the Kconfig structure in the SDK package is as follows:

├── sdk
    ├── Kconfig                            SDK Kconfig, rsource "./config/$(BOARD_DIR)/Kconfig.release".
    ├── config
        ├── RTL8763E                       The BOARD_DIR variable is set to RTL8763E.
            ├── Kconfig.release            Configure SOC series type and name, rsource "../../bin/rtl87x3e/Kconfig.board" and "Kconfig.RTL8763E.sdk".
            ├── Kconfig.RTL8763E.sdk       rsource "../../bin/rtl87x3e/Kconfig.soc.sdk".
    ├── bin                                Contains all binary symbol files that user applications are built upon.
        ├── rtl87x3e
            ├── Kconfig.soc.sdk            Configures library used by application and define the library name and target type. All these libraries are compiled and ready for use.
            ├── Kconfig.board              Configures the IC part number related type and target. rsource "flash_map_config/Kconfig"
            ├── flash_map_config
                ├── Kconfig                Configures flash map type, flash map file path, and compile bank type.
    ├── board
        ├── evb
            ├── bt_audio_trx
                ├── gcc
                    ├── defconfig.RTL8763E.bt_audio_trx_4M_lea_dual_bank0      The defconfig file of bt_audio_trx_4M_lea_dual_bank0 for RTL8763E.
                ├── Kconfig                Defines mainmenu in the application Kconfig, define configuration in the application and include SDK Kconfig under the SDK. rsource "../../../src/Kconfig" to get the configuration in the application source code, and rsource the SDK Kconfig of "../../../Kconfig".

The defconfig file of an application should be located in the gcc subdirectory of the applicaiton's main directory. The Kconfig file of the applicaiton should be placed directly in the applicaiton's root directory. This relative path structure is essential for the CMake compilation process.

When developing application libraries, it's necessary to prepare a library-specific Kconfig file. In this Kconfig, the configurations that directly impact the compilation results need to be defined. Additionally, it should define the library target type configurations and the target name for different targets.

├── sdk
    ├── Kconfig                            SDK Kconfig with library detailed configurations, rsource "./config/$(BOARD_DIR)/Kconfig".
    ├── Kconfig.release                    SDK Kconfig, rsource "./config/$(BOARD_DIR)/Kconfig.release", This file will be renamed as "Kconfig" in the SDK package with compiled libraries.
    ├── config
        ├── RTL8763E                       The BOARD_DIR variable is set to RTL8763E.
            ├── Kconfig                    Configure SOC series type and name, rsource "../../bin/rtl87x3e/Kconfig.board". If compiling applicaiton only, rsource "Kconfig.RTL8763E.sdk". If compiling both applicaiton and library projects, rsource "Kconfig.RTL8763E".
            ├── Kconfig.RTL8763E.sdk       rsource "../../bin/rtl87x3e/Kconfig.soc.sdk".
            ├── Kconfig.RTL8763E           rsource library Kconfig from "../../board/evb/Kconfig.soc.RTL8763E".
    ├── bin                                Contains all binary symbol files that user applications are built upon.
        ├── rtl87x3e
            ├── Kconfig.soc.sdk            Configures libraries used by applications and defines the library names and target types. All these libraries are pre-compiled and ready for use.
            ├── Kconfig.board              Configures the IC part number related types and targets. rsource "flash_map_config/Kconfig"
            ├── flash_map_config
                ├── Kconfig                Configures flash map type, flash map file path, and compile bank type.
    ├── board
        ├── evb
            ├── bt_audio_trx
                ├── Kconfig                Defines mainmenu in the application Kconfig, defines configurations in the application and includes SDK Kconfig under the SDK. rsource "../../../src/Kconfig" to get the configuration in the application source code, and rsource the SDK Kconfig from "../../../Kconfig".
            ├── ble_audio_lib              Library directory.
                ├── Kconfig                Configures the library target type and library name for different targets. Adds configurations which can affect the compilation result for different requirements.
                ├── gcc
                    ├── defconfig.RTL8763E.default      Adds defconfig configurations of the default target for RTL8763E. The defconfig file will be loaded based on the default configuration values defined in Kconfig.

For library projects, the top-level Kconfig is the Kconfig file under the SDK directory. For application projects, the top-level Kconfig is the Kconfig file under the applicaiton directory.

The mainmenu of bt_audio_trx is in board\evb\bt_audio_trx\Kconfig. The guiconfig and menuconfig commands can be run through the command line:

  1. First, Set the variable of BOARD_DIR to the IC directory name under the config directory of the SDK, e.g. RTL8763E, RTL8773D, RTL8773E and RTL8773G. If the config directory doesn't exist under the SDK directory, skip this step. For various command line environment, the methods to set variable are different:

    • In Windows Command Prompt, use set VAR=variable_name.

    • In PowerShell, use $env:VAR="variable_name".

    • In bash, use exprot VAR=variable_name.

    In this example, it is set to RTL8763E:

    In Windows Command Prompt:

    set BOARD_DIR=RTL8763E
    

    In PowerShell:

    $env:BOARD_DIR="RTL8763E"
    

    In bash:

    exprot BOARD_DIR=RTL8763E
    
  2. Run the guiconfig command. The parameter of guiconfig or menuconfig is the absolute or relative path of the top-level Kconfig. For example, run guiconfig command under the board\evb\bt_audio_trx directory.

    guiconfig Kconfig
    

    The execution of the guiconfig command in different command line windows are as follows:

    ../../../../_images/cmd_guiconfig.png

    guiconfig in Windows Command Prompt

    ../../../../_images/powershell_guiconfig.png

    guiconfig in PowerShell

    ../../../../_images/git_bash_guiconfig.png

    guiconfig in Git Bash

    Run guiconfig command under the SDK directory, use the relative path to the Kconfig file:

    guiconfig .\board\evb\bt_audio_trx\Kconfig
    

    The guiconfig interface for bt_audio_trx is as follows:

    ../../../../_images/guiconfig_btaudiotrx.png

    Configuration Interface of bt_audio_trx by guiconfig

    User can configure the settings through the guiconfig interface, save as defconfig file, and switch between single-menu mode and full-tree mode. User can also click Open... to load a defconfig file, update configurations based on it and save as a new defconfig file.

    ../../../../_images/btaudiotrx_load_defconfig.png

    Load defconfig File by guiconfig

    User can also run menuconfig command under the board\evb\bt_audio_trx directory. The python library windows-curses is required for menuconfig command on Windows. Install this library using:

    pip install windows-curses
    

    Then run:

    menuconfig Kconfig
    

    The menuconfig interface for bt_audio_trx is as follows:

    ../../../../_images/menuconfig_btaudiotrx.png

    Configuration Interface of bt_audio_trx by menuconfig

    User can configure the settings through the menuconfig interface following the on-screen tips. For example, load a defconfig by pressing O:

    ../../../../_images/menuconfig_load.png

    Open defconfig File by menuconfig

    After loading gcc\defconfig.RTL8763E.4M_bank0, the menuconfig updates as follows:

    ../../../../_images/menuconfig_load_defconfig.png

    Load defconfig File Result by menuconfig

Use of Kconfig in CMake Script

The configurations defined in Kconfig and updated by the defconfig file can be generated into three files (config.cmake, config.h, .config) through tool\Gadgets\gcc_tool\kconfig.py during the CMake configure phase. The usuage of Kconfig.py is as follows:

python kconfig.py -h
usage: kconfig.py [-h] [--board {RTL8773D,RTL8773E,RTL8763E,RTL8773G}]
                  kconfig_file config_out header_out cmake_out kconfig_list_out configs_in [configs_in ...]

positional arguments:
  kconfig_file          Top-level Kconfig file
  config_out            Output configuration file
  header_out            Output header file
  cmake_out             Output cmake config file
  kconfig_list_out      Output file for list of parsed Kconfig files
  configs_in            Input configuration fragments. Will be merged together.

options:
  -h, --help            show this help message and exit
  --board {RTL8773D,RTL8773E,RTL8763E,RTL8773G}
                        Top-level Kconfig file

The usage of Kconfig in the CMake script is in the config\cmake\build.cmake:

find_program(Python_EXECUTABLE python NO_CMAKE_FIND_ROOTO_PATH)
set(Python_ARGS "${CMAKE_CURRENT_SOURCE_DIR}/tool/Gadgets/gcc_tool/kconfig.py ${general_kconfig_path} ${gen_dir}/.config ${gen_dir}/config.h ${gen_dir}/config.cmake ${gen_dir}/sourcelist.txt ${kconfig_path} --board ${board}")
STRING(REPLACE " " ";" Python_ARGS ${Python_ARGS})
message(STATUS "[KCONFIG] Python_EXECUTABLE: ${Python_EXECUTABLE}")
message(STATUS "[KCONFIG] Python_ARGS: ${Python_ARGS}")
execute_process(
  COMMAND ${Python_EXECUTABLE} ${Python_ARGS}
)
include(${gen_dir}/config.cmake)

A sample command line for kconfig.py is as follows:

python tool/Gadgets/gcc_tool/kconfig.py ./board/evb/bt_audio_trx/gcc/../Kconfig ./build/include/generated/.config ./build/include/generated/config.h ./build/include/generated/config.cmake ./build/include/generated/sourcelist.txt ./board/evb/bt_audio_trx/gcc/defconfig.RTL8763E.bt_audio_trx_4M_lea_dual_bank0 --board RTL8763E

The generated config.cmake will be used in the CMake script, and the config.h will be used in C/C++ source files precompilation by the command target_precompile_headers(btAudioTrx PRIVATE  ${kconfig_header_dir_path}/config.h). The .config contains the total configuration definition.

Best Practices and Tips

Here are some tips in the practices:

  1. Locate Kconfig files near the source code for easier modification and portability.

  2. Group configuration items by functional modules to enhance readability and maintainability.

  3. Use meaningful and consistent naming conventions for config options. And select the appropriate Kconfig type based on how the macro is used (bool, tristate, string, int, hex).

  4. For bool type config:

    • When not selected, the CONFIG_XXX macro is not defined. This macro can't be used for calculation or assignment.

    • Use only conditional compilation directive (#if, #ifdef, #ifndef, #if defined).

    • It's recommended to use the same if or #ifdef for a configuration macro.

  5. For macros used as integers with values not limited to 0 or 1, define them as int type and specify an optional range.

  6. Be aware that config without a prompt:

    • Use their default value and are invisible in guiconfig or menuconfig.

    • They can't be updated by defconfig files.

  7. Use default values ​​and range constraints appropriately.

    • Default values are often used directly in compilation scenarios without setting in the defconfig.

    • Be cautious when adjusting default values, as changes ​​may affect defconfig configurations.

  8. Provide clear, concise, and informative help text for each configuration option.

  9. Use select and imply directives carefully to manage the relationships between configurations and avoid circular dependencies.

  10. It is crucial to prevent redundant definitions of configurations. Maintaining a single point of definition for each configuration ensures system-wide consistency, mitigates potential conflicts, and eliminates ambiguity in the configuration process.

  11. Consider the impact on build systems and scripts when adding or modifying configuration options.

How to Add a Kconfig Configuration to Control Source Code Compilation?

When adding a configuration to control source code compilation:

  1. In Keil C/C++ preprocessor symbols definition settings of Keil projects:

    • Set the configuration macro to 1 (enabled) or 0 (disabled).

  2. In the Kconfig file

    • Define the configuration as a bool type.

    • Add the configuration definition in the Kconfig file with an appropriate default value:

      • If the feature should be enabled by default:

        • Set the default value to y.

        • For targets needing it disabled, set to n in the defconfig files.

      • If the feature should be disabled by default:

        • Set the default value to n.

        • For targets needing it enabled, set to y in the defconfig files.

    Example:

    config REALTEK_FEATURE_A
       bool "enable feaure A"
       default y
       help
          Description about feaure A
    
  3. In the source code, add the configuration conditional compile control code.

    #if (CONFIG_REALTEK_FEATURE_A == 1)
        //source code content
    #endif
    
  4. In the defconfig files, for targets requiring a non-default configuration:

    • If default is y and feature should be disabled, set to n.

    • If default is n and feature should be enabled, set to y.

How to Remove a Kconfig Configuration?

Before removing a configuration, carefully review all usage scenarios to ensure it can be safely deleted. Once confirmed, follow these steps to clean up all instances of the macro:

  1. Source code: Remove all usage of the configuration macro in the source code.

  2. Kconfig: Delete the configuration definition from the Kconfig file.

  3. Defconfig files: Remove the configuration value settings from all relevant defconfig files.

  4. Keil project: Delete the configuration definition from the C/C++ preprocessor symbols definition settings.

  5. Update any relevant documentation or any build scripts or CMakeLists that mentions this configuration.

  6. After removal, thoroughly test the system to ensure no unexpected side effects.

When removing a configuration in Kconfig, considering a transition period is a also very good practice. This can reduce the impact on existing systems and users, and provide sufficient time for necessary adjustments.

  • Before completely removing the configuration, mark it as deprecated first.

  • Clearly state in comments or help text that the configuration will be removed in the future. If there are alternative configurations or new implementation methods, provide clear migration guidance in the help text.

  • Use conditional compilation in the code to gradually phase out the use of this configuration.

How to Adjust the Default Value of a Kconfig Configuration?

Once set, it is generally not recommended to modify the default values of macros in Kconfig, primarily due to the following two considerations:

  • Potential issues arising from SDK version iterations are easily overlooked.

  • Incomplete revisions may lead to unexpected risks.

However, if changes are absolutely necessary, follow these steps to maintain system consistency:

  1. Modify the Kconfig file:

    • Locate the relevant macro definition in the Kconfig file.

    • Update the default value to the new desired default value.

  2. Check and update defconfig files:

    • Review all defconfig files for all compilation scenarios.

    • For cases where the new default value differs from the current setting in defconfig:

      • If you want to maintain the original behavior, explicitly set the original value in defconfig.

      • If you accept the new default value, you can remove that setting from defconfig.

  3. Check and update the documentation or any build scripts or CMakeLists that mentions this configuration.

  4. Conduct a code review to ensure the impact of the change is fully understood and accepted. Inform related development.

  5. Do comprehensive testing in all affected compilation scenarios to ensure the change hasn't introduced unexpected issues.