From 5c0facdaba9a0b5f310c776e29f44a9245e75e29 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 11 Jun 2026 11:51:37 +0800 Subject: [PATCH] fix(cmakev2): include config-selected default components --- components/esp_gdbstub/project_include.cmake | 8 +++++ components/espcoredump/project_include.cmake | 11 ++++++ .../build-system-v2/creating-component.rst | 10 ++++++ tools/cmakev2/idf.cmake | 7 ++++ tools/cmakev2/project.cmake | 27 +++++++++++++++ .../buildv2/test_default_components.py | 34 +++++++++++++++++++ 6 files changed, 97 insertions(+) create mode 100644 components/esp_gdbstub/project_include.cmake create mode 100644 components/espcoredump/project_include.cmake create mode 100644 tools/test_build_system/buildv2/test_default_components.py diff --git a/components/esp_gdbstub/project_include.cmake b/components/esp_gdbstub/project_include.cmake new file mode 100644 index 00000000000..7b1ee4cf05f --- /dev/null +++ b/components/esp_gdbstub/project_include.cmake @@ -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() diff --git a/components/espcoredump/project_include.cmake b/components/espcoredump/project_include.cmake new file mode 100644 index 00000000000..efa1b6cc35e --- /dev/null +++ b/components/espcoredump/project_include.cmake @@ -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() diff --git a/docs/en/api-guides/build-system-v2/creating-component.rst b/docs/en/api-guides/build-system-v2/creating-component.rst index b72d526efe5..12ecf9bb267 100644 --- a/docs/en/api-guides/build-system-v2/creating-component.rst +++ b/docs/en/api-guides/build-system-v2/creating-component.rst @@ -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. diff --git a/tools/cmakev2/idf.cmake b/tools/cmakev2/idf.cmake index f4fc09ec99b..ac605923b4f 100644 --- a/tools/cmakev2/idf.cmake +++ b/tools/cmakev2/idf.cmake @@ -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) diff --git a/tools/cmakev2/project.cmake b/tools/cmakev2/project.cmake index 8e2f8413780..ab8579459c7 100644 --- a/tools/cmakev2/project.cmake +++ b/tools/cmakev2/project.cmake @@ -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[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}" diff --git a/tools/test_build_system/buildv2/test_default_components.py b/tools/test_build_system/buildv2/test_default_components.py new file mode 100644 index 00000000000..5853df7233b --- /dev/null +++ b/tools/test_build_system/buildv2/test_default_components.py @@ -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}' + )