Merge branch 'bugfix/cmakev2-coredump-default-component' into 'master'

fix(cmakev2): include config-selected default components

See merge request espressif/esp-idf!49614
This commit is contained in:
Marius Vikhammer
2026-08-21 10:16:27 +08:00
6 changed files with 97 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
idf_build_get_property(target IDF_TARGET)
idf_build_get_property(non_os_build NON_OS_BUILD)
if(IDF_BUILD_V2 AND NOT non_os_build AND NOT "${target}" STREQUAL "linux")
if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME OR CONFIG_ESP_SYSTEM_PANIC_GDBSTUB)
idf_project_add_default_build_component(esp_gdbstub)
endif()
endif()

View File

@@ -0,0 +1,11 @@
idf_build_get_property(target IDF_TARGET)
idf_build_get_property(non_os_build NON_OS_BUILD)
if(IDF_BUILD_V2 AND CONFIG_ESP_COREDUMP_ENABLE
AND NOT non_os_build
AND NOT "${target}" STREQUAL "linux")
# This ensures that the component is added to the build when coredump is enabled,
# even if no other component depends on it.
# This allows users to simply enable it in menuconfig without needing to modify their component dependencies.
idf_project_add_default_build_component(espcoredump)
endif()

View File

@@ -319,3 +319,13 @@ How the Component is Built
--------------------------
A component is compiled and linked only if it is required, directly or transitively, by a component that is being built. :cmakev2:ref:`idf_project_default` builds the application from the ``main`` component, so a native component becomes part of the application when ``main`` or one of its dependencies includes it. ``main`` is a convention of :cmakev2:ref:`idf_project_default`, not a requirement of the build system; a project that drives the build with the lower-level API can build the application from any component (see :doc:`multiple-binaries` and :doc:`idf-as-library`). The difference between discovering a component and including it is described in :doc:`design`.
Some components are enabled solely by project configuration and contribute behavior through linker-section registrations, rather than through a dependency from another component. Such a component can add itself to the executable created by :cmakev2:ref:`idf_project_default` from its ``project_include.cmake`` file:
.. code-block:: cmake
if(CONFIG_MY_FEATURE_ENABLE)
idf_project_add_default_build_component(my_component)
endif()
Use this only when the component must be linked whenever its configuration enables it, but no ordinary component dependency expresses that requirement. For example, ``espcoredump`` registers startup and panic handlers, and ``esp_gdbstub`` registers its panic handler; both are selected by their configuration options.

View File

@@ -708,6 +708,13 @@ endfunction()
.. cmakev2:build_property:: IDF_COMPONENT_OPTIONAL_REQUIRES_MODE
How :cmakev2:ref:`idf_component_optional_requires` is resolved, ``IMMEDIATE`` or ``DEFERRED``.
.. cmakev2:build_property:: PROJECT_DEFAULT_EXTRA_COMPONENTS
Internal list of additional components to include in the executable
created by ``idf_project_default``. Components should use
``idf_project_add_default_build_component`` rather than modifying this
property directly.
#]]
add_library(idf_build_properties INTERFACE)

View File

@@ -860,6 +860,28 @@ function(idf_build_generate_flasher_args)
INPUT "${build_dir}/flasher_args.json.in")
endfunction()
#[[api
.. cmakev2:function:: idf_project_add_default_build_component
.. code-block:: cmake
idf_project_add_default_build_component(<component>...)
*component[in]*
Component name to include in the executable created by
:cmakev2:ref:`idf_project_default`.
Add components to the default project executable. This is intended for
components that need to be built based on sdkconfig alone, for example to
provide linker-section registrations, without making another component
depend on them. This is e.g. the case with coredump which is simply enabled
based on CONFIG_ESP_COREDUMP_ENABLE option, but no other components depend it.
#]]
function(idf_project_add_default_build_component)
idf_build_set_property(PROJECT_DEFAULT_EXTRA_COMPONENTS "${ARGN}" APPEND)
endfunction()
#[[
.. cmakev2:macro:: __project_default
@@ -881,6 +903,11 @@ function(__project_default)
set(root_components ${shim_components})
else()
set(root_components main)
idf_build_get_property(extra_default_components PROJECT_DEFAULT_EXTRA_COMPONENTS)
if(extra_default_components)
list(APPEND root_components ${extra_default_components})
list(REMOVE_DUPLICATES root_components)
endif()
endif()
idf_build_executable("${executable}"

View File

@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import json
import logging
from pathlib import Path
import pytest
from test_build_system_helpers import IdfPyFunc
@pytest.mark.usefixtures('test_app_copy')
def test_config_selected_default_components(idf_py: IdfPyFunc) -> None:
"""Components with a project_include.cmake that calls idf_project_add_default_build_component()
must be pulled into the default build when their Kconfig feature is enabled, even though nothing
in the project explicitly depends on them.
Enable coredump and gdbstub via sdkconfig.defaults, build, and assert both components end up in
build_components.
"""
logging.info('Testing config-selected default components (coredump, gdbstub)')
# Coredump to UART (no dedicated coredump partition needed) and runtime gdbstub.
Path('sdkconfig.defaults').write_text('CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y\nCONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME=y\n')
idf_py('build')
proj_desc = json.loads(Path('build/project_description.json').read_text())
build_components = proj_desc.get('build_components', [])
for comp in ('espcoredump', 'esp_gdbstub'):
assert comp in build_components, (
f'{comp} should be added as a default build component when its feature is enabled, '
f'got build_components: {build_components}'
)