Merge branch 'fix/cmakev2_component_manager_disabled_v6.0' into 'release/v6.0'

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

See merge request espressif/esp-idf!46954
This commit is contained in:
Jiang Jiang Jian
2026-03-25 19:16:35 +08:00
5 changed files with 48 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)
+8 -2
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 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)
@@ -6,8 +6,10 @@ import subprocess
from pathlib import Path
import pytest
from test_build_system_helpers import EnvDict
from test_build_system_helpers import IdfPyFunc
from test_build_system_helpers import replace_in_file
from test_build_system_helpers import run_idf_py
@pytest.mark.usefixtures('test_app_copy')
@@ -377,3 +379,18 @@ def test_depgraph_generation(idf_py: IdfPyFunc) -> None:
dot_content = dot_file.read_text()
assert 'digraph' in dot_content, 'component_deps.dot should contain a digraph definition'
assert '->' in dot_content, 'component_deps.dot should contain at least one dependency edge (->)'
@pytest.mark.usefixtures('test_app_copy')
def test_build_with_component_manager_disabled(default_idf_env: EnvDict) -> None:
"""Setting IDF_COMPONENT_MANAGER=0 should skip the component manager
flow entirely and still produce a successful build."""
logging.info('Testing build with IDF_COMPONENT_MANAGER=0')
default_idf_env['IDF_COMPONENT_MANAGER'] = '0'
ret = run_idf_py('build', env=default_idf_env)
assert 'Component manager round' not in (ret.stdout or ''), (
'Component manager should not run when IDF_COMPONENT_MANAGER=0'
)
assert Path('build/build_test_app.elf').exists(), 'Build should succeed with component manager disabled'