fix(cmakev2): skip component manager flow when IDF_COMPONENT_MANAGER=0

When the component manager is disabled via IDF_COMPONENT_MANAGER=0, the
cmakev2 build system still entered the full component manager flow
(__fetch_components_from_registry), which called
__download_managed_component(). That function returned early with
result=0 without creating the expected output file, violating the
post-condition in __download_component_level_managed_components() that
checks result==0 => file exists, causing a fatal error.

Instead of patching the low-level function to write an empty stub file,
this commit properly skips the entire component manager flow when the
manager is disabled:

- Move __init_component_manager() to idf.cmake global initialization
  sequence alongside other __init_*() calls, so IDF_COMPONENT_MANAGER
  build property is available early.

- Set __SDKCONFIG_ORIG to the real sdkconfig path in __init_kconfig()
  as its default value. Previously it was only set inside
  __create_sdkconfig_orig_copy() and had a defensive fallback in
  __create_base_kconfgen_command(). The default ensures __SDKCONFIG_ORIG
  is always valid regardless of whether the component manager runs.

- Guard __create_sdkconfig_orig_copy() with an IDF_COMPONENT_MANAGER
  check. The sdkconfig backup exists solely to preserve unknown Kconfig
  options from managed components during intermediate kconfgen rounds.
  When the manager is disabled, no managed components exist, so the
  backup is unnecessary.

- Guard __fetch_components_from_registry() call in project.cmake behind
  IDF_COMPONENT_MANAGER == 1. When disabled, only the manifest warning
  is issued. No download loop runs, no temp files are created, and no
  "Component manager round N..." messages are printed.

- Remove the now-redundant IDF_COMPONENT_MANAGER guard from
  __download_managed_component(), since it is only reachable when the
  manager is enabled.

Closes https://github.com/espressif/esp-idf/issues/18372

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
This commit is contained in:
Frantisek Hrbata
2026-03-22 10:03:03 +01:00
parent ed7c90c8aa
commit 3cbca31571
4 changed files with 31 additions and 29 deletions
+3
View File
@@ -594,6 +594,9 @@ __init_python()
# Initialize Kconfig system infrastructure.
__init_kconfig()
# Initialize component manager build properties (IDF_COMPONENT_MANAGER, etc.).
__init_component_manager()
# Set IDF_TARGET.
__init_idf_target()
+12 -5
View File
@@ -55,6 +55,7 @@ function(__init_kconfig)
endforeach()
idf_build_set_property(SDKCONFIG "${sdkconfig}")
idf_build_set_property(__SDKCONFIG_ORIG "${sdkconfig}")
idf_build_set_property(SDKCONFIG_DEFAULTS "${sdkconfig_defaults_checked}")
# Setup ESP-IDF root Kconfig and sdkconfig.rename files.
@@ -83,6 +84,16 @@ endfunction()
and write the actual file.
#]]
function(__create_sdkconfig_orig_copy)
# The backup is only needed when the component manager is enabled.
# Managed components may introduce Kconfig options unknown to kconfgen
# during intermediate sdkconfig regeneration rounds. The backup preserves
# those options. When the manager is disabled, __SDKCONFIG_ORIG already
# points to the real sdkconfig (set in __init_kconfig).
idf_build_get_property(idf_component_manager IDF_COMPONENT_MANAGER)
if(NOT idf_component_manager EQUAL 1)
return()
endif()
idf_build_get_property(sdkconfig SDKCONFIG)
idf_build_get_property(build_dir BUILD_DIR)
set(sdkconfig_orig "${build_dir}/sdkconfig.orig")
@@ -704,12 +715,8 @@ function(__create_base_kconfgen_command sdkconfig sdkconfig_defaults)
endif()
# Use __SDKCONFIG_ORIG for --config so that unknown options from managed
# components are preserved during intermediate kconfgen runs. Falls back
# to the real sdkconfig when __SDKCONFIG_ORIG is not yet set.
# components are preserved during intermediate kconfgen runs.
idf_build_get_property(sdkconfig_orig __SDKCONFIG_ORIG)
if(NOT sdkconfig_orig)
set(sdkconfig_orig "${sdkconfig}")
endif()
# Create base kconfgen command
set(base_kconfgen_cmd ${python} -m kconfgen
+7 -21
View File
@@ -20,6 +20,8 @@ function(__init_component_manager)
OUTPUT component_manager_env)
if(component_manager_env STREQUAL "" OR NOT component_manager_env STREQUAL "0")
idf_build_set_property(IDF_COMPONENT_MANAGER 1)
else()
idf_build_set_property(IDF_COMPONENT_MANAGER 0)
endif()
# Set IDF_COMPONENT_MANAGER_INTERFACE_VERSION.
@@ -29,13 +31,9 @@ function(__init_component_manager)
OUTPUT cmgr_iface)
idf_build_set_property(IDF_COMPONENT_MANAGER_INTERFACE_VERSION ${cmgr_iface})
# Set DEPENDENCIES_LOCK if set by the user. Otherwise, use the
# project directory and IDF_TARGET to determine the lock file path.
# Note: This deviates from the build system v1 behavior where we allow
# users to specify the lock file path via idf_build_set_property.
idf_build_get_property(deps_lock_file DEPENDENCIES_LOCK)
# Set DEPENDENCIES_LOCK if provided via environment or CMake variable.
__get_default_value(VARIABLE DEPENDENCIES_LOCK
DEFAULT "${deps_lock_file}"
DEFAULT ""
OUTPUT deps_lock_file)
idf_build_set_property(DEPENDENCIES_LOCK "${deps_lock_file}")
endfunction()
@@ -48,15 +46,11 @@ endfunction()
kconfig option. This behavior is similar to the build system v1.
This routine performs the following steps:
1. Initialize the component manager.
2. Run the component manager for all discovered components.
3. Re-collect Kconfig and regenerate sdkconfig with managed components included.
4. If the component manager run failed, error out.
1. Run the component manager for all discovered components.
2. Re-collect Kconfig and regenerate sdkconfig with managed components included.
3. If the component manager run failed, error out.
#]]
function(__fetch_components_from_registry)
# Initialize the component manager.
__init_component_manager()
# Iteratively run the component manager and Kconfig until stable or error out.
set(__cmgr_round 0)
while(TRUE)
@@ -71,8 +65,6 @@ function(__fetch_components_from_registry)
# If component manager run failed, use the failure result
if(cmgr_result EQUAL 0)
# If manager is disabled but manifests were detected, issue a warning
__component_manager_warn_if_disabled_and_manifests_exist()
break()
elseif(cmgr_result EQUAL 10 AND __cmgr_round LESS 2)
# We can retry once if the manager fails with a missing kconfig option
@@ -130,12 +122,6 @@ function(__download_managed_component)
idf_die("RESULT option is required")
endif()
idf_build_get_property(idf_component_manager IDF_COMPONENT_MANAGER)
if(NOT idf_component_manager EQUAL 1)
set(${ARG_RESULT} 0 PARENT_SCOPE)
return()
endif()
idf_build_get_property(python PYTHON)
idf_build_get_property(project_dir PROJECT_DIR)
idf_build_get_property(component_manager_interface_version IDF_COMPONENT_MANAGER_INTERFACE_VERSION)
+9 -3
View File
@@ -579,14 +579,20 @@ macro(idf_project_init)
# Discover and initialize components
__init_components()
# Save original sdkconfig before kconfgen may drop unknown options
# Save original sdkconfig before kconfgen may drop unknown options.
# Only creates a backup when the component manager is enabled.
__create_sdkconfig_orig_copy()
# Generate initial sdkconfig with discovered components
__generate_sdkconfig()
# Initialize the component manager and fetch components in a loop
__fetch_components_from_registry()
# Fetch managed components from registry if the component manager is enabled
idf_build_get_property(idf_component_manager IDF_COMPONENT_MANAGER)
if(idf_component_manager EQUAL 1)
__fetch_components_from_registry()
else()
__component_manager_warn_if_disabled_and_manifests_exist()
endif()
# Include sdkconfig.cmake
idf_build_get_property(sdkconfig_cmake __SDKCONFIG_CMAKE)