# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 # Kconfig utilities for ESP-IDF CMake build system v2 # This module provides functions for Kconfig processing and sdkconfig generation include_guard(GLOBAL) include(utilities) include(build) include(component) #[[ __init_kconfig() Initialize the Kconfig system infrastructure for the build. This function performs the Kconfig initialization and setup by: 1. Setting up SDKCONFIG and SDKCONFIG_DEFAULTS build properties 2. Setting up ESP-IDF root Kconfig files and config directory 3. Creating the default config directory This should be called after component discovery but before component manager. Note: Regular component Kconfig files are collected during component discovery. #]] function(__init_kconfig) idf_build_get_property(idf_path IDF_PATH) # Initialize SDKCONFIG and SDKCONFIG_DEFAULTS build properties using environment # variables, CMake cache variables, or default values. if(EXISTS "${CMAKE_SOURCE_DIR}/sdkconfig.defaults") set(sdkconfig_defaults "${CMAKE_SOURCE_DIR}/sdkconfig.defaults") else() set(sdkconfig_defaults "") endif() __get_default_value(VARIABLE SDKCONFIG DEFAULT "${CMAKE_SOURCE_DIR}/sdkconfig" OUTPUT sdkconfig) __get_default_value(VARIABLE SDKCONFIG_DEFAULTS DEFAULT "${sdkconfig_defaults}" OUTPUT sdkconfig_defaults) __get_absolute_paths(PATHS "${sdkconfig}" OUTPUT sdkconfig) __get_absolute_paths(PATHS "${sdkconfig_defaults}" OUTPUT sdkconfig_defaults) set(sdkconfig_defaults_checked "") foreach(sdkconfig_default ${sdkconfig_defaults}) if(NOT EXISTS "${sdkconfig_default}") idf_die("SDKCONFIG_DEFAULTS '${sdkconfig_default}' does not exist.") endif() list(APPEND sdkconfig_defaults_checked ${sdkconfig_default}) endforeach() idf_build_set_property(SDKCONFIG "${sdkconfig}") idf_build_set_property(SDKCONFIG_DEFAULTS "${sdkconfig_defaults_checked}") # Setup ESP-IDF root Kconfig and sdkconfig.rename files. idf_build_set_property(__ROOT_KCONFIG "${idf_path}/Kconfig") idf_build_set_property(__ROOT_SDKCONFIG_RENAME "${idf_path}/sdkconfig.rename") # Setup and create the default config directory. idf_build_get_property(build_dir BUILD_DIR) set(config_dir "${build_dir}/config") file(MAKE_DIRECTORY "${config_dir}") idf_build_set_property(CONFIG_DIR "${config_dir}") endfunction() #[[ .. cmakev2:function:: __should_generate_sdkconfig .. code-block:: cmake __should_generate_sdkconfig(OUTPUT ) *OUTPUT[out]* The output variable will contain ``YES`` or ``NO`` depending on whether the sdkconfig should be generated. Check if any new ``Kconfig``, ``Kconfig.projbuild``, or ``sdkconfig.rename`` files have been added. If so, store ``YES`` in the ``OUTPUT`` variable; otherwise, store ``NO``. The ``__generate_sdkconfig()`` function can be called multiple times, such as when the initial sdkconfig is generated at the start of the build process and later after additional components are fetched by the component manager. There might be no components fetched by the component manager, for example, in the hello_world example, or the downloaded components may not contain any configuration files. In such cases, there is no need to regenerate the sdkconfig. This helper function stores the list of configuration files in the ``__PREV_KCONFIGS``, ``__PREV_KCONFIG_PROJBUILDS``, and ``__PREV_SDKCONFIG_RENAMES`` build properties at its end, and at the beginning, it compares them with the current lists of configuration files. #]] function(__should_generate_sdkconfig) set(options) set(one_value OUTPUT) set(multi_value) cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) if(NOT DEFINED ARG_OUTPUT) idf_die("OUTPUT option is required") endif() idf_build_get_property(kconfigs __KCONFIGS) idf_build_get_property(projbuilds __KCONFIG_PROJBUILDS) idf_build_get_property(renames __SDKCONFIG_RENAMES) list(SORT kconfigs) list(SORT projbuilds) list(SORT renames) idf_build_get_property(prev_kconfigs __PREV_KCONFIGS) idf_build_get_property(prev_projbuilds __PREV_KCONFIG_PROJBUILDS) idf_build_get_property(prev_renames __PREV_SDKCONFIG_RENAMES) list(SORT prev_kconfigs) list(SORT prev_projbuilds) list(SORT prev_renames) idf_build_set_property(__PREV_KCONFIGS "${kconfigs}") idf_build_set_property(__PREV_KCONFIG_PROJBUILDS "${projbuilds}") idf_build_set_property(__PREV_SDKCONFIG_RENAMES "${renames}") if("${kconfigs}" STREQUAL "${prev_kconfigs}" AND "${projbuilds}" STREQUAL "${prev_projbuilds}" AND "${renames}" STREQUAL "${prev_renames}") set(${ARG_OUTPUT} NO PARENT_SCOPE) else() set(${ARG_OUTPUT} YES PARENT_SCOPE) endif() endfunction() #[[ __generate_sdkconfig() This function performs the complete Kconfig generation process: 1. Collect Kconfig files from discovered components 2. Collect Kconfig files from bootloader components 3. Set up the Kconfig environment with all collected files 4. Generate all output files (sdkconfig.h, sdkconfig.cmake, etc.) #]] function(__generate_sdkconfig) # Collect Kconfig files from discovered components __consolidate_component_kconfig_files() # Collect Kconfig files from bootloader components __collect_kconfig_files_from_bootloader_components() # Check if sdkconfig needs to be generated __should_generate_sdkconfig(OUTPUT generate) if(NOT generate) idf_dbg("Configuration files have not changed, skipping sdkconfig generation.") return() endif() idf_msg("Generating sdkconfig configuration...") # Prepare Kconfig environment using collected files __setup_kconfig_environment() # Generate Kconfig outputs __generate_kconfig_outputs() idf_msg("Generated sdkconfig configuration") endfunction() # ============================================================================= # KCONFIG COLLECTION FUNCTIONS # ============================================================================= #[[ __consolidate_component_kconfig_files() Consolidate Kconfig files from discovered components into global build properties. This scans the COMPONENTS_DISCOVERED build property and for each component, retrieves its Kconfig files from component properties and adds them to the global __KCONFIGS, __KCONFIG_PROJBUILDS, and __SDKCONFIG_RENAMES build properties. #]] function(__consolidate_component_kconfig_files) idf_build_get_property(components_discovered COMPONENTS_DISCOVERED) if(NOT components_discovered) idf_die("No components discovered. This must be run after component discovery.") endif() # Clean the build properties before adding new ones. This ensures that # we don't have duplicate Kconfig files in the build properties. idf_build_set_property(__KCONFIGS "") idf_build_set_property(__KCONFIG_PROJBUILDS "") idf_build_set_property(__SDKCONFIG_RENAMES "") # Iterate through all discovered components and consolidate their Kconfig files foreach(component_name IN LISTS components_discovered) # Get Kconfig files from component properties idf_component_get_property(component_kconfig "${component_name}" __KCONFIG) idf_component_get_property(component_projbuild "${component_name}" __KCONFIG_PROJBUILD) idf_component_get_property(component_rename "${component_name}" __SDKCONFIG_RENAME) if(component_kconfig) idf_build_set_property(__KCONFIGS "${component_kconfig}" APPEND) endif() if(component_projbuild) idf_build_set_property(__KCONFIG_PROJBUILDS "${component_projbuild}" APPEND) endif() if(component_rename) idf_build_set_property(__SDKCONFIG_RENAMES "${component_rename}" APPEND) endif() endforeach() endfunction() #[[ __collect_kconfig_files_from_bootloader_components() Collect Kconfig files from bootloader components and store them in build properties. Bootloader components are located in the bootloader_components directory of the project. This function only runs if the bootloader component is discovered. #]] function(__collect_kconfig_files_from_bootloader_components) # Check if bootloader component is discovered - only then collect bootloader components idf_build_get_property(components_discovered COMPONENTS_DISCOVERED) if(NOT "bootloader" IN_LIST components_discovered) return() endif() idf_build_get_property(idf_target IDF_TARGET) idf_build_get_property(project_dir PROJECT_DIR) # Find bootloader component directories __get_component_paths(PATHS "${project_dir}/bootloader_components" OUTPUT bootloader_component_dirs) foreach(bootloader_component_dir ${bootloader_component_dirs}) __collect_kconfig_files_from_directory("${bootloader_component_dir}" "${idf_target}" bootloader_kconfig bootloader_projbuild bootloader_rename) # Set build properties. Bootloader components are only evaluated for Kconfig files at this stage. if(bootloader_kconfig) idf_build_set_property(__KCONFIGS "${bootloader_kconfig}" APPEND) endif() if(bootloader_projbuild) idf_build_set_property(__KCONFIG_PROJBUILDS "${bootloader_projbuild}" APPEND) endif() if(bootloader_rename) idf_build_set_property(__SDKCONFIG_RENAMES "${bootloader_rename}" APPEND) endif() endforeach() endfunction() #[[ __collect_kconfig_files_from_directory(directory target out_kconfigs out_projbuilds out_renames) Collect Kconfig files from a single directory. *directory[in]* Path to the directory to collect Kconfig files from. *target[in]* Target name for target-specific files. *out_kconfigs[out]* List of Kconfig files. *out_projbuilds[out]* List of projbuild files. *out_renames[out]* List of rename files. #]] function(__collect_kconfig_files_from_directory directory target out_kconfigs out_projbuilds out_renames) file(GLOB all_files "${directory}/*") set(kconfig_files "") set(projbuild_files "") set(rename_files "") foreach(file IN LISTS all_files) get_filename_component(filename "${file}" NAME) string(TOLOWER "${filename}" filename_lower) # Check for Kconfig file if(filename_lower STREQUAL "kconfig") list(APPEND kconfig_files "${file}") if(NOT filename STREQUAL "Kconfig") idf_warn("${filename} file should be named 'Kconfig' (uppercase K, rest lowercase). Full path to the file: ${file}") endif() # Check for Kconfig.projbuild file elseif(filename_lower STREQUAL "kconfig.projbuild") list(APPEND projbuild_files "${file}") if(NOT filename STREQUAL "Kconfig.projbuild") idf_warn("${filename} file should be named 'Kconfig.projbuild' (uppercase K, rest lowercase). Full path to the file: ${file}") endif() endif() # Check for sdkconfig.rename files if(filename_lower STREQUAL "sdkconfig.rename") list(APPEND rename_files "${file}") endif() # Look for target-specific sdkconfig.rename files if(target) if(filename_lower STREQUAL "sdkconfig.rename.${target}") list(APPEND rename_files "${file}") endif() endif() endforeach() list(SORT kconfig_files) list(SORT projbuild_files) list(SORT rename_files) set(${out_kconfigs} "${kconfig_files}" PARENT_SCOPE) set(${out_projbuilds} "${projbuild_files}" PARENT_SCOPE) set(${out_renames} "${rename_files}" PARENT_SCOPE) endfunction() # ============================================================================= # KCONFIG ENVIRONMENT FUNCTIONS # ============================================================================= #[[ __setup_kconfig_environment() Setup the Kconfig environment for kconfgen. This function creates the environment and prepares Kconfig source files. #]] function(__setup_kconfig_environment) # Create the config.env file, which contains all environment variables for the python script idf_build_get_property(build_dir BUILD_DIR) set(config_env_path "${build_dir}/config.env") __create_config_env_file("${config_env_path}") # Store environment path in build properties (used by kconfgen) idf_build_set_property(__CONFIG_ENV_PATH "${config_env_path}") # Now prepare Kconfig source files using the prepare_kconfig_files.py script idf_build_get_property(python PYTHON) idf_build_get_property(idf_path IDF_PATH) set(prepare_cmd ${python} "${idf_path}/tools/kconfig_new/prepare_kconfig_files.py" --list-separator=semicolon --env-file "${config_env_path}") idf_build_set_property(__PREPARE_KCONFIG_CMD "${prepare_cmd}") idf_dbg("Preparing Kconfig source files: ${prepare_cmd}") execute_process( COMMAND ${prepare_cmd} RESULT_VARIABLE prepare_result ) if(prepare_result) idf_die("Failed to prepare Kconfig source files: ${prepare_result}") endif() endfunction() #[[ __create_executable_config_env_file(executable) *executable[in]* Executable target for which to generate ``config.env`` file. Generate the ``config.env`` file for the specified ``executable``. The configuration file will be stored in the build directory, within a directory named after the ``executable`` target name. The ``kconfigs*.in`` files, which are generated by ``prepare_kconfig_files.py``, will also be stored in this directory. This function primarily prepares the arguments for the ``__create_config_env_file`` function based on the components linked to the ``executable``, ensuring that component Kconfig files are stored in the appropriate ``kconfigs*.in`` files, depending on whether the component is linked to the executable. The directory where the generated files are stored is added to the ``executable`` ``CONFIG_ENV_DIR`` property. #]] function(__create_executable_config_env_file executable) get_target_property(config_env_dir "${executable}" CONFIG_ENV_DIR) if(config_env_dir) return() endif() __get_executable_library_or_die(TARGET "${executable}" OUTPUT library) idf_library_get_property(components_linked "${library}" LIBRARY_COMPONENTS_LINKED) set(kconfigs "") set(kconfigs_projbuild "") set(kconfigs_excluded "") set(kconfigs_projbuild_excluded "") idf_build_get_property(components_discovered COMPONENTS_DISCOVERED) foreach(component_name IN LISTS components_discovered) idf_component_get_property(component_kconfig "${component_name}" __KCONFIG) idf_component_get_property(component_projbuild "${component_name}" __KCONFIG_PROJBUILD) if(component_kconfig) if("${component_name}" IN_LIST components_linked) list(APPEND kconfigs "${component_kconfig}") else() list(APPEND kconfigs_excluded "${component_kconfig}") endif() endif() if(component_projbuild) if("${component_name}" IN_LIST components_linked) list(APPEND kconfigs_projbuild "${component_projbuild}") else() list(APPEND kconfigs_projbuild_excluded "${component_projbuild}") endif() endif() endforeach() string(REGEX REPLACE "[^A-Za-z0-9_]" "_" executable_sanitized "${executable}") idf_build_get_property(build_dir BUILD_DIR) set(kconfigs_dir "${build_dir}/${executable_sanitized}") set(kconfigs_path "${kconfigs_dir}/kconfigs.in") set(kconfigs_projbuild_path "${kconfigs_dir}/kconfigs_projbuild.in") set(kconfigs_excluded_path "${kconfigs_dir}/kconfigs_excluded.in") set(kconfigs_projbuild_excluded_path "${kconfigs_dir}/kconfigs_projbuild_excluded.in") set(config_env_path "${kconfigs_dir}/config.env") __create_config_env_file("${config_env_path}" KCONFIGS "${kconfigs}" KCONFIGS_PROJBUILD "${kconfigs_projbuild}" KCONFIGS_EXCLUDED "${kconfigs_excluded}" KCONFIGS_PROJBUILD_EXCLUDED "${kconfigs_projbuild_excluded}") set_target_properties("${executable}" PROPERTIES CONFIG_ENV_DIR "${kconfigs_dir}") endfunction() #[[ __create_config_env_file(config_env_path [KCONFIGS ...] [KCONFIGS_PROJBUILD ...] [KCONFIGS_EXCLUDED ...] [KCONFIGS_PROJBUILD_EXCLUDED ...]) *config_env_path[in]* Path for the generated configuration environment file. *KCONFIGS[in,opt]* Kconfig file or list of Kconfig files to be sourced in the ``kconfigs.in`` file. Can be used multiple times. If not provided, the Kconfig files stored in the ``__KCONFIGS`` build property are used. *KCONFIGS_PROJBUILD[in,opt]* Kconfig file or list of Kconfig files to be sourced in the ``kconfigs_projbuild.in`` file. Can be used multiple times. If not provided, the Kconfig files stored in the ``__KCONFIGS`` build property are used. *KCONFIGS_EXCLUDED[in,opt]* Kconfig file or list of Kconfig files to be sourced in the ``kconfigs_excluded.in`` file. Can be used multiple times. *KCONFIGS_PROJBUILD_EXCLUDED[in,opt]* Kconfig file or list of Kconfig files to be sourced in the ``kconfigs_projbuild_excluded.in`` file. Can be used multiple times. Generate a configuration file for the ``prepare_kconfig_files.py`` script at ``config_env_path``. This file includes, among other details, the paths where ``prepare_kconfig_files.py`` should generate the ``kconfigs*.in`` files. These are Kconfig files, sourced in the main Kconfig file through environmental variables, and contain a list of component configurations that should be sourced. The ``kconfigs*.in`` file paths in the generated configuration file are located in the same directory as the configuration file itself. This means that ``prepare_kconfig_files.py`` will produce the ``kconfigs*.in`` files in the same directory where the configuration file created by this function is generated. #]] function(__create_config_env_file config_env_path) set(options) set(one_value) set(multi_value KCONFIGS KCONFIGS_PROJBUILD KCONFIGS_EXCLUDED KCONFIGS_PROJBUILD_EXCLUDED) cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) # Get all necessary build properties idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(build_dir BUILD_DIR) idf_build_get_property(kconfigs __KCONFIGS) idf_build_get_property(projbuilds __KCONFIG_PROJBUILDS) idf_build_get_property(renames __SDKCONFIG_RENAMES) idf_build_get_property(target IDF_TARGET) idf_build_get_property(toolchain IDF_TOOLCHAIN) idf_build_get_property(sdkconfig SDKCONFIG) if(ARG_KCONFIGS) set(kconfigs "${ARG_KCONFIGS}") endif() if(ARG_KCONFIGS_PROJBUILD) set(projbuilds "${ARG_KCONFIGS_PROJBUILD}") endif() set(kconfigs_excluded "") if(ARG_KCONFIGS_EXCLUDED) set(kconfigs_excluded "${ARG_KCONFIGS_EXCLUDED}") endif() set(kconfigs_projbuild_excluded "") if(ARG_KCONFIGS_PROJBUILD_EXCLUDED) set(kconfigs_projbuild_excluded "${ARG_KCONFIGS_PROJBUILD_EXCLUDED}") endif() # Get IDF version info __get_sdkconfig_option(OPTION CONFIG_IDF_INIT_VERSION SDKCONFIG "${sdkconfig}" OUTPUT idf_init_version) if(NOT idf_init_version) set(idf_init_version "$ENV{IDF_VERSION}") endif() set(ENV{IDF_INIT_VERSION} "${idf_init_version}") idf_build_set_property(__IDF_INIT_VERSION "${idf_init_version}") # Get IDF_ENV_FPGA from the environment set(idf_env_fpga "$ENV{IDF_ENV_FPGA}") if(NOT idf_env_fpga) set(idf_env_fpga "") endif() idf_build_set_property(__IDF_ENV_FPGA "${idf_env_fpga}") # Get the config.env.in template path set(template_path "${idf_path}/tools/kconfig_new/config_buildv2.env.in") if(NOT EXISTS "${template_path}") idf_die("Kconfig environment template file not found at ${template_path}") endif() get_filename_component(config_env_dir "${config_env_path}" DIRECTORY) # Set up variables for the config.env.in template set(kconfigs "${kconfigs}") set(kconfig_projbuilds "${projbuilds}") set(kconfigs_excluded "${kconfigs_excluded}") set(kconfigs_projbuild_excluded "${kconfigs_projbuild_excluded}") set(sdkconfig_renames "${renames}") set(idf_target "${target}") set(idf_toolchain "${toolchain}") set(idf_path "${idf_path}") set(kconfigs_path "${config_env_dir}/kconfigs.in") set(kconfigs_projbuild_path "${config_env_dir}/kconfigs_projbuild.in") set(kconfigs_excluded_path "${config_env_dir}/kconfigs_excluded.in") set(kconfigs_projbuild_excluded_path "${config_env_dir}/kconfigs_projbuild_excluded.in") # Generate the config.env file from the config.env.in template configure_file("${template_path}" "${config_env_path}") idf_dbg("Created config environment file: ${config_env_path}") endfunction() # ============================================================================= # KCONFIG OUTPUT GENERATION FUNCTIONS # ============================================================================= #[[ __generate_kconfig_outputs() Generate all Kconfig output files. Generates: sdkconfig.h, sdkconfig.cmake, sdkconfig.json, kconfig_menus.json Must be called after __setup_kconfig_environment(). #]] function(__generate_kconfig_outputs) # Get inputs from build properties idf_build_get_property(sdkconfig SDKCONFIG) idf_build_get_property(sdkconfig_defaults SDKCONFIG_DEFAULTS) idf_msg("Project sdkconfig file ${sdkconfig}") # Set up output paths idf_build_get_property(config_dir CONFIG_DIR) if(NOT config_dir) idf_die("Kconfig directory not created. Call __init_kconfig() first.") endif() set(sdkconfig_header "${config_dir}/sdkconfig.h") set(sdkconfig_cmake "${config_dir}/sdkconfig.cmake") set(sdkconfig_json "${config_dir}/sdkconfig.json") # Create and store base kconfgen command for this generation and target reuse __create_base_kconfgen_command("${sdkconfig}" "${sdkconfig_defaults}") # Create and store common kconfgen outputs command set(kconfgen_outputs_cmd --output header "${sdkconfig_header}" --output cmake "${sdkconfig_cmake}" --output json "${sdkconfig_json}" --output config "${sdkconfig}" ) idf_build_set_property(__KCONFGEN_OUTPUTS_CMD "${kconfgen_outputs_cmd}") # Generate Kconfig outputs using kconfgen __run_kconfgen() # Add the generated config header to build specifications idf_build_set_property(INCLUDE_DIRECTORIES "${config_dir}" APPEND) # Set up file dependencies for CMake reconfiguration set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig}") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig_header}") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig_cmake}") # Add dependency on kconfgen tool idf_build_get_property(idf_path IDF_PATH) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${idf_path}/tools/kconfig_new/confgen.py") # Set up clean files set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${sdkconfig_header}" "${sdkconfig_cmake}") # Store output paths in build properties idf_build_set_property(__SDKCONFIG_HEADER "${sdkconfig_header}") idf_build_set_property(__SDKCONFIG_CMAKE "${sdkconfig_cmake}") idf_build_set_property(__SDKCONFIG_JSON "${sdkconfig_json}") idf_build_set_property(__SDKCONFIG_JSON_MENUS "${sdkconfig_json_menus}") idf_msg("Generated Kconfig outputs in ${config_dir}") endfunction() #[[ __create_base_kconfgen_command(sdkconfig sdkconfig_defaults) *sdkconfig[in]* Path to sdkconfig file. *sdkconfig_defaults[in]* List of sdkconfig defaults files. Create the base kconfgen command and store it as a build property for reuse. #]] function(__create_base_kconfgen_command sdkconfig sdkconfig_defaults) # Get all necessary properties for base command idf_build_get_property(python PYTHON) idf_build_get_property(root_kconfig __ROOT_KCONFIG) idf_build_get_property(root_sdkconfig_rename __ROOT_SDKCONFIG_RENAME) idf_build_get_property(target IDF_TARGET) # Set up defaults arguments set(defaults_args "") if(sdkconfig_defaults) foreach(default_file IN LISTS sdkconfig_defaults) list(APPEND defaults_args "--defaults" "${default_file}") if(EXISTS "${default_file}.${target}") list(APPEND defaults_args "--defaults" "${default_file}.${target}") endif() endforeach() endif() # Create base kconfgen command set(base_kconfgen_cmd ${python} -m kconfgen --list-separator=semicolon --kconfig "${root_kconfig}" --sdkconfig-rename "${root_sdkconfig_rename}" --config "${sdkconfig}" ${defaults_args} --env "IDF_BUILD_V2=y") # Store base command as a build property idf_build_set_property(__BASE_KCONFGEN_CMD "${base_kconfgen_cmd}") endfunction() #[[ __run_kconfgen() Run kconfgen and generate all output files using the stored base command. Assumes that the base command is already created by __create_base_kconfgen_command(). #]] function(__run_kconfgen) idf_build_get_property(base_kconfgen_cmd __BASE_KCONFGEN_CMD) idf_build_get_property(kconfgen_outputs_cmd __KCONFGEN_OUTPUTS_CMD) idf_build_get_property(config_env_path __CONFIG_ENV_PATH) # Create full command with output file paths set(kconfgen_cmd ${base_kconfgen_cmd} ${kconfgen_outputs_cmd}) idf_dbg("Running kconfgen: ${kconfgen_cmd}") execute_process( COMMAND ${kconfgen_cmd} --env-file "${config_env_path}" RESULT_VARIABLE kconfgen_result ) if(kconfgen_result) idf_die("Failed to run kconfgen: ${kconfgen_result}") endif() endfunction() # ============================================================================= # KCONFIG TARGETS FUNCTIONS # ============================================================================= #[[ .. cmakev2:function:: idf_create_menuconfig .. code-block:: cmake idf_create_menuconfig( TARGET ) *executable[in]* Executable target for which to create the menuconfig target. *TARGET[in]* Name of the menuconfig target to be created. Create a menuconfig target with the name specified by the ``TARGET`` option for an ``executable``. #]] function(idf_create_menuconfig executable) set(options) set(one_value TARGET) set(multi_value) cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) if(NOT DEFINED ARG_TARGET) idf_die("TARGET option is required") endif() if(TARGET "${ARG_TARGET}") idf_die("TARGET '${ARG_TARGET}' for menuconfig already exists") endif() idf_build_get_property(python PYTHON) idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(kconfgen_cmd __BASE_KCONFGEN_CMD) idf_build_get_property(sdkconfig SDKCONFIG) idf_build_get_property(root_kconfig __ROOT_KCONFIG) idf_build_get_property(build_dir BUILD_DIR) idf_build_get_property(target IDF_TARGET) idf_build_get_property(toolchain IDF_TOOLCHAIN) idf_build_get_property(idf_init_version __IDF_INIT_VERSION) idf_build_get_property(idf_env_fpga __IDF_ENV_FPGA) idf_build_get_property(kconfgen_outputs_cmd __KCONFGEN_OUTPUTS_CMD) # Newer versions of esp-idf-kconfig renamed menuconfig to esp_menuconfig # Order matters here, we want to use esp_menuconfig if it is available execute_process( COMMAND "${python}" -c "import esp_menuconfig" RESULT_VARIABLE ESP_MENUCONFIG_AVAILABLE OUTPUT_QUIET ERROR_QUIET ) if(ESP_MENUCONFIG_AVAILABLE EQUAL 0) set(MENUCONFIG_CMD "${python}" -m esp_menuconfig) else() set(MENUCONFIG_CMD "${python}" -m menuconfig) endif() __create_executable_config_env_file("${executable}") get_target_property(config_env_dir "${executable}" CONFIG_ENV_DIR) add_custom_target("${ARG_TARGET}" # Prepare Kconfig source files COMMAND ${python} "${idf_path}/tools/kconfig_new/prepare_kconfig_files.py" --list-separator=semicolon --env-file "${config_env_dir}/config.env" # Generate config with current settings COMMAND ${kconfgen_cmd} --env "IDF_TARGET=${target}" --env "IDF_TOOLCHAIN=${toolchain}" --env "IDF_ENV_FPGA=${idf_env_fpga}" --env "IDF_INIT_VERSION=${idf_init_version}" --dont-write-deprecated ${kconfgen_outputs_cmd} --env-file "${config_env_dir}/config.env" # Check terminal capabilities COMMAND ${python} "${idf_path}/tools/check_term.py" # Run menuconfig COMMAND ${CMAKE_COMMAND} -E env "COMPONENT_KCONFIGS_SOURCE_FILE=${config_env_dir}/kconfigs.in" "COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE=${config_env_dir}/kconfigs_projbuild.in" "COMPONENT_KCONFIGS_EXCLUDED_SOURCE_FILE=${config_env_dir}/kconfigs_excluded.in" "COMPONENT_KCONFIGS_PROJBUILD_EXCLUDED_SOURCE_FILE=${config_env_dir}/kconfigs_projbuild_excluded.in" "KCONFIG_CONFIG=${sdkconfig}" "IDF_TARGET=${target}" "IDF_TOOLCHAIN=${toolchain}" "IDF_ENV_FPGA=${idf_env_fpga}" "IDF_INIT_VERSION=${idf_init_version}" "IDF_BUILD_V2=y" ${MENUCONFIG_CMD} "${root_kconfig}" # Post-menuconfig: insert deprecated options for backward compatibility COMMAND ${kconfgen_cmd} --env "IDF_TARGET=${target}" --env "IDF_TOOLCHAIN=${toolchain}" --env "IDF_ENV_FPGA=${idf_env_fpga}" --env "IDF_INIT_VERSION=${idf_init_version}" ${kconfgen_outputs_cmd} --env-file "${config_env_dir}/config.env" USES_TERMINAL COMMENT "Running menuconfig..." ) endfunction() #[[ .. cmakev2:function:: idf_create_confserver .. code-block:: cmake idf_create_confserver( TARGET ) *executable[in]* Executable target for which to create the confserver target. *TARGET[in]* Name of the confserver target to be created. Create a confserver target with the name specified by the ``TARGET`` option for an ``executable``. #]] function(idf_create_confserver executable) set(options) set(one_value TARGET) set(multi_value) cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) if(NOT DEFINED ARG_TARGET) idf_die("TARGET option is required") endif() idf_build_get_property(python PYTHON) idf_build_get_property(sdkconfig SDKCONFIG) idf_build_get_property(root_kconfig __ROOT_KCONFIG) idf_build_get_property(root_sdkconfig_rename __ROOT_SDKCONFIG_RENAME) idf_build_get_property(base_kconfgen_cmd __BASE_KCONFGEN_CMD) idf_build_get_property(config_dir CONFIG_DIR) __create_executable_config_env_file("${executable}") get_target_property(config_env_dir "${executable}" CONFIG_ENV_DIR) add_custom_target("${ARG_TARGET}" # Prepare Kconfig source files COMMAND ${python} "${idf_path}/tools/kconfig_new/prepare_kconfig_files.py" --list-separator=semicolon --env-file "${config_env_dir}/config.env" # Generate kconfig_menus.json COMMAND ${base_kconfgen_cmd} --env-file "${config_env_dir}/config.env" --output json_menus "${config_dir}/kconfig_menus.json" # Run confserver COMMAND ${python} -m kconfserver --env-file "${config_env_dir}/config.env" --kconfig "${root_kconfig}" --sdkconfig-rename "${root_sdkconfig_rename}" --config "${sdkconfig}" VERBATIM USES_TERMINAL COMMENT "Running confserver..." ) endfunction() #[[ .. cmakev2:function:: idf_create_save_defconfig .. code-block:: cmake idf_create_save_defconfig() Create the save-defconfig target. #]] function(idf_create_save_defconfig) idf_build_get_property(prepare_cmd __PREPARE_KCONFIG_CMD) idf_build_get_property(config_env_path __CONFIG_ENV_PATH) idf_build_get_property(kconfgen_cmd __BASE_KCONFGEN_CMD) add_custom_target(save-defconfig # Prepare Kconfig source files COMMAND ${prepare_cmd} # Generate save-defconfig COMMAND ${kconfgen_cmd} --dont-write-deprecated --output savedefconfig "${CMAKE_SOURCE_DIR}/sdkconfig.defaults" --env-file "${config_env_path}" USES_TERMINAL COMMENT "Saving defconfig..." VERBATIM ) endfunction()