feat(build): fixed esp_usb_cdc_rom_console always being included in build

This commit is contained in:
Marius Vikhammer
2026-08-24 14:19:21 +08:00
parent dfe99a4a41
commit 157d6b1669
11 changed files with 252 additions and 162 deletions

View File

@@ -96,16 +96,31 @@ else()
list(APPEND srcs "debug_assist.c")
endif()
set(priv_requires spi_flash esp_timer esp_mm
esp_hal_clock esp_hal_mspi esp_hal_wdt esp_hal_debug_assist
esp_hal_uart esp_hal_dma esp_hal_security
# [refactor-todo] requirements due to init code,
# should be removable once using component init functions
# link-time registration is used.
bootloader_support esp_pm)
if(NOT IDF_BUILD_V2)
# panic.c only calls into the ROM CDC console under CONFIG_ESP_CONSOLE_USB_CDC,
# but requirements are resolved before Kconfig here, so the dependency has to
# be unconditional. Under v2 it is added below based on the config value.
list(APPEND priv_requires esp_usb_cdc_rom_console)
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS include
PRIV_REQUIRES spi_flash esp_timer esp_mm
esp_hal_clock esp_hal_mspi esp_hal_wdt esp_hal_debug_assist
esp_hal_uart esp_hal_dma esp_hal_security
# [refactor-todo] requirements due to init code,
# should be removable once using component init functions
# link-time registration is used.
bootloader_support esp_pm esp_usb_cdc_rom_console
PRIV_REQUIRES ${priv_requires}
LDFRAGMENTS "linker.lf" "app.lf")
if(IDF_BUILD_V2 AND CONFIG_ESP_CONSOLE_USB_CDC)
idf_component_include(esp_usb_cdc_rom_console)
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::esp_usb_cdc_rom_console)
endif()
add_subdirectory(port)
# After system initialization, `start_app` (and its other cores variant) is called.

View File

@@ -82,6 +82,11 @@ tools/test_apps/system/g0_components:
- if: INCLUDE_DEFAULT == 1 or IDF_TARGET in ["esp32h21", "esp32h4", "esp32s31"] # preview targets
tools/test_apps/system/g1_components:
disable:
- if: IDF_BUILD_V2 == "1"
reason: the cmake v2 component closure is checked by g1_components_cmakev2
tools/test_apps/system/g1_components_cmakev2:
tools/test_apps/system/gdb:
disable_test:

View File

@@ -4,32 +4,7 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.22)
set(g0_components soc hal esp_common esp_rom) # also <arch>, i.e. xtensa or riscv, will be added below
set(g1_components spi_flash freertos log heap esp_libc esp_system esp_hw_support esp_mm esp_stdio)
# The HAL components that required by G1 components
# Most of these HAL components are required by `clk.c` in `esp_system` for peripherals clock initialization.
set(esp_hal_components
esp_hal_ana_conv
esp_hal_cam
esp_hal_dma
esp_hal_gpio
esp_hal_i2s
esp_hal_mspi
esp_hal_gpspi
esp_hal_timg
esp_hal_touch_sens
esp_hal_uart
esp_hal_usb
esp_hal_wdt
esp_hal_pmu
esp_hal_rtc_timer
esp_hal_clock
esp_hal_security
esp_hal_systimer
esp_hal_regi2c
esp_hal_debug_assist
)
set(COMPONENTS ${g0_components} ${g1_components} ${esp_hal_components} main)
include(${CMAKE_CURRENT_LIST_DIR}/g1_setup.cmake)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
@@ -37,121 +12,4 @@ idf_build_set_property(__BUILD_COMPONENT_DEPGRAPH_ENABLED 1)
project(g1_components)
set(extra_allowed_components
${CONFIG_IDF_TARGET_ARCH}
)
# These components are currently included into "G1" build, but shouldn't.
# After removing the extra dependencies, remove the components from this list as well.
set(extra_components_which_shouldnt_be_included
# bootloader is only included from esptool_py, which should be removed from G1
bootloader
# bootloader_support is a dependency of the following G1 components:
# spi_flash, esp_system, esp_hw_support.
# as well as the following non G1 components:
# efuse, app_update, esp_partition
# Challenging to remove: IDF-8581 for more details
bootloader_support
# should cxx be in G1? Can it exist without FreeRTOS? IDF-9511
cxx
# esp_driver_gpio is a dependency of esp_pm (should be removed from g1 builds),
# as well as spi_flash, esp_hw_support, IDF-10387
esp_driver_gpio
# esp_app_format is dependency of bootloader_support, app_update, efuse.
# All components that should be removed from G1
esp_app_format
# esp_bootloader_format is dependency of bootloader_support, app_update
# All components that should be removed from G1
esp_bootloader_format
# Dependency of bootloader_support, app_update, and esp_hw_support
# Figure out if the esp_hw_support component can exist without a dependency on efuse.
# efuse is used by the ADC calibration functions in esp_hw_support/adc_share_hw_ctrl.c,
# it could use the efuse hal (if virtual efuse mode is not used for tests).
# If not, see if esp_hw_support can provide minimal efuse component replacement in G1 build.
# Also used by security features (hmac and key-manager) and MAC support
efuse
# esp_pm is pulled in by esp_system due to pm_init and freertos idle hook
# both could be moved to pm component if esp-system idle hook provided a way to register hooks
# esp_hw_support dependency seems like it could be removed?
# It is also used by esp_driver_gpio, which should be removed from G1-only build.
# IDF-10415
esp_pm
# esp_timer is a dependency of esp_pm, esp_system, esp_security, esp_hw_support
# esp_pm should be removed from G1 build
# esp_system's dependency is due to task_wdt timer implementation on C2,
# we could possibly place this implementation in esp_timer instead
# esp_security uses it for esp_ds (used for timeout functionality)
# and for componensating time after sleep (dependency could be reversed) IDF-10416
esp_timer
# esptool_py is a dependency of bootloader, app_update, partition_table, all of which
# should be removed from G1-only build.
esptool_py
# partition_table is pulled in by app_update, esptool_py, bootloader, esp_partition; all to be removed
partition_table
# esp_partition is a new component for separated IDF partition APIs. Pulled in from app_update and efuse,
# both which should be removed
esp_partition
# esp_blockdev is a new component for separated IDF block storage device APIs. Pulled in from esp_partition
esp_blockdev
# pthread is required by cxx. See [refactor-todo] about cxx, can it work without pthread?
pthread
# esp_security is required by spi_flash
esp_security
# esp_usb_cdc_rom_console is used by the panic handler, will be conditional on cdc console option when
# the new build-system is implemented
esp_usb_cdc_rom_console
)
set(expected_components
${COMPONENTS}
${extra_allowed_components}
${extra_components_which_shouldnt_be_included}
)
list(SORT expected_components)
if(IDF_BUILD_V2)
get_target_property(library ${project_elf} LIBRARY_INTERFACE)
idf_library_get_property(build_components "${library}" LIBRARY_COMPONENTS_LINKED)
else()
idf_build_get_property(build_components BUILD_COMPONENTS)
endif()
list(SORT build_components)
if(NOT "${expected_components}" STREQUAL "${build_components}")
message(FATAL_ERROR "Unexpected components list in G1 build. "
"Expected: ${expected_components}. "
"Actual: ${build_components}")
endif()
set(comp_deps_dot "${CMAKE_BINARY_DIR}/component_deps.dot")
idf_build_get_property(target IDF_TARGET)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "Checking dependency violations"
COMMAND python "${CMAKE_SOURCE_DIR}/check_dependencies.py"
--component_deps_file ${comp_deps_dot}
--target ${IDF_TARGET}
RESULT_VARIABLE result
)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Found unexpected componend dependencies while running check_dependencies.py, "
"please update the dependency list in the script according to the error output.")
endif()
include(${CMAKE_CURRENT_LIST_DIR}/g1_check.cmake)

View File

@@ -5,7 +5,9 @@
This test application checks the list of components included into the build when "G1" components are added to the build. If G1 components don't have any dependencies outside of G1, then only G1 components themselves should be built.
Currently, this is not the case, and many other components are added to the build. See `extra_components_which_shouldnt_be_included` list inside CMakeLists.txt.
Currently, this is not the case, and many other components are added to the build. See `extra_components_which_shouldnt_be_included` list inside `g1_check.cmake`.
This app is built with build system v1. The sibling app `../g1_components_cmakev2` performs the same check with build system v2 and shares `g1_setup.cmake`, `g1_check.cmake`, `check_dependencies.py` and `main` with this one. The expected component lists differ between the two build systems, because v2 can express dependencies that are conditional on Kconfig options; both files branch on `IDF_BUILD_V2` where that matters.
The purpose of this example is to:

View File

@@ -53,18 +53,19 @@ g1_g0_components = g1_g0_components_base + get_all_esp_hal_components()
# Global expected dependency violations that apply to all targets
expected_dep_violations = {
'esp_system': ['esp_timer', 'bootloader_support', 'esp_pm', 'esp_usb_cdc_rom_console'],
'esp_system': ['esp_timer', 'bootloader_support', 'esp_pm'],
'spi_flash': ['bootloader_support', 'esp_blockdev', 'esp_driver_gpio'],
'esp_hw_support': ['efuse', 'bootloader_support', 'esp_driver_gpio', 'esp_timer', 'esp_pm'],
'cxx': ['pthread'],
}
# idf_component_optional_requires has a DEFERRED mode under build system v2
# that propagates the resolved dependency back into PRIV_REQUIRES, so the
# dependency graph captures edges that target_link_libraries creates at link
# time but were never recorded as requires.
if os.environ.get('IDF_BUILD_V2'):
expected_dep_violations['esp_system'].append('esp_app_format')
else:
# Requirements are resolved before Kconfig under build system v1, so esp_system
# depends on the ROM CDC console unconditionally. Under v2 the dependency is
# only added when the console is set to USB CDC.
expected_dep_violations['esp_system'].append('esp_usb_cdc_rom_console')
# Target-specific expected dependency violations
target_specific_expected_dep_violations = {

View File

@@ -0,0 +1,143 @@
# Closure and dependency checks shared by the cmakev1 (g1_components) and
# cmakev2 (g1_components_cmakev2) variants of this test app. Must be included after
# the project has been configured.
set(extra_allowed_components
${CONFIG_IDF_TARGET_ARCH}
)
# These components are currently included into "G1" build, but shouldn't.
# After removing the extra dependencies, remove the components from this list as well.
set(extra_components_which_shouldnt_be_included
# bootloader is only included from esptool_py, which should be removed from G1
bootloader
# bootloader_support is a dependency of the following G1 components:
# spi_flash, esp_system, esp_hw_support.
# as well as the following non G1 components:
# efuse, app_update, esp_partition
# Challenging to remove: IDF-8581 for more details
bootloader_support
# should cxx be in G1? Can it exist without FreeRTOS? IDF-9511
cxx
# esp_driver_gpio is a dependency of esp_pm (should be removed from g1 builds),
# as well as spi_flash, esp_hw_support, IDF-10387
esp_driver_gpio
# esp_app_format is dependency of bootloader_support, app_update, efuse.
# All components that should be removed from G1
esp_app_format
# esp_bootloader_format is dependency of bootloader_support, app_update
# All components that should be removed from G1
esp_bootloader_format
# Dependency of bootloader_support, app_update, and esp_hw_support
# Figure out if the esp_hw_support component can exist without a dependency on efuse.
# efuse is used by the ADC calibration functions in esp_hw_support/adc_share_hw_ctrl.c,
# it could use the efuse hal (if virtual efuse mode is not used for tests).
# If not, see if esp_hw_support can provide minimal efuse component replacement in G1 build.
# Also used by security features (hmac and key-manager) and MAC support
efuse
# esp_pm is pulled in by esp_system due to pm_init and freertos idle hook
# both could be moved to pm component if esp-system idle hook provided a way to register hooks
# esp_hw_support dependency seems like it could be removed?
# It is also used by esp_driver_gpio, which should be removed from G1-only build.
# IDF-10415
esp_pm
# esp_timer is a dependency of esp_pm, esp_system, esp_security, esp_hw_support
# esp_pm should be removed from G1 build
# esp_system's dependency is due to task_wdt timer implementation on C2,
# we could possibly place this implementation in esp_timer instead
# esp_security uses it for esp_ds (used for timeout functionality)
# and for componensating time after sleep (dependency could be reversed) IDF-10416
esp_timer
# esptool_py is a dependency of bootloader, app_update, partition_table, all of which
# should be removed from G1-only build.
esptool_py
# partition_table is pulled in by app_update, esptool_py, bootloader, esp_partition; all to be removed
partition_table
# esp_partition is a new component for separated IDF partition APIs. Pulled in from app_update and efuse,
# both which should be removed
esp_partition
# esp_blockdev is a new component for separated IDF block storage device APIs. Pulled in from esp_partition
esp_blockdev
# pthread is required by cxx. See [refactor-todo] about cxx, can it work without pthread?
pthread
# esp_security is required by spi_flash
esp_security
)
if(NOT IDF_BUILD_V2)
# esp_usb_cdc_rom_console is used by the panic handler. Under build system v1
# requirements are resolved before Kconfig, so esp_system has to depend on it
# unconditionally. Build system v2 only pulls it in when the console is set to
# USB CDC, which this app does not do.
list(APPEND extra_components_which_shouldnt_be_included esp_usb_cdc_rom_console)
endif()
set(expected_components
${COMPONENTS}
${extra_allowed_components}
${extra_components_which_shouldnt_be_included}
)
if(IDF_BUILD_V2)
# Build system v1 puts every component listed in COMPONENTS into the build, even
# when nothing depends on it. Under v2 the closure is whatever actually gets
# linked, so HAL components that only a single target pulls in are absent on all
# the others. Keep these conditions in sync with the components pulling them in.
idf_build_get_property(idf_target IDF_TARGET)
if(NOT idf_target STREQUAL "esp32p4")
# esp_hw_support only uses the CAM HAL for mipi_csi_share_hw_ctrl.c
list(REMOVE_ITEM expected_components esp_hal_cam)
endif()
if(NOT idf_target STREQUAL "esp32")
# esp_hal_ana_conv only uses the I2S HAL for the ESP32 SAR ADC
list(REMOVE_ITEM expected_components esp_hal_i2s)
endif()
endif()
list(SORT expected_components)
if(IDF_BUILD_V2)
get_target_property(library ${project_elf} LIBRARY_INTERFACE)
idf_library_get_property(build_components "${library}" LIBRARY_COMPONENTS_LINKED)
else()
idf_build_get_property(build_components BUILD_COMPONENTS)
endif()
list(SORT build_components)
if(NOT "${expected_components}" STREQUAL "${build_components}")
message(FATAL_ERROR "Unexpected components list in G1 build. "
"Expected: ${expected_components}. "
"Actual: ${build_components}")
endif()
set(comp_deps_dot "${CMAKE_BINARY_DIR}/component_deps.dot")
idf_build_get_property(target IDF_TARGET)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "Checking dependency violations"
COMMAND python "${CMAKE_CURRENT_LIST_DIR}/check_dependencies.py"
--component_deps_file ${comp_deps_dot}
--target ${IDF_TARGET}
RESULT_VARIABLE result
)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Found unexpected componend dependencies while running check_dependencies.py, "
"please update the dependency list in the script according to the error output.")
endif()

View File

@@ -0,0 +1,30 @@
# Component lists shared by the cmakev1 (g1_components) and cmakev2
# (g1_components_cmakev2) variants of this test app. Must be included before the
# project is configured, since cmakev1 uses COMPONENTS to restrict the build.
set(g0_components soc hal esp_common esp_rom) # also <arch>, i.e. xtensa or riscv, will be added below
set(g1_components spi_flash freertos log heap esp_libc esp_system esp_hw_support esp_mm esp_stdio)
# The HAL components that required by G1 components
# Most of these HAL components are required by `clk.c` in `esp_system` for peripherals clock initialization.
set(esp_hal_components
esp_hal_ana_conv
esp_hal_cam
esp_hal_dma
esp_hal_gpio
esp_hal_i2s
esp_hal_mspi
esp_hal_gpspi
esp_hal_timg
esp_hal_touch_sens
esp_hal_uart
esp_hal_usb
esp_hal_wdt
esp_hal_pmu
esp_hal_rtc_timer
esp_hal_clock
esp_hal_security
esp_hal_systimer
esp_hal_regi2c
esp_hal_debug_assist
)
set(COMPONENTS ${g0_components} ${g1_components} ${esp_hal_components} main)

View File

@@ -1,6 +1 @@
# Force VFS_SUPPORT_IO off so the conditional requires in esp_stdio and
# esp_libc do not pull vfs, esp_driver_uart, and their transitive deps
# into the g1_components closure. components/vfs/Kconfig defaults this
# symbol to y whenever it is processed, which happens for every discovered
# component under IDF_BUILD_V2 regardless of the COMPONENTS restriction.
CONFIG_VFS_SUPPORT_IO=n

View File

@@ -0,0 +1,21 @@
# Build system v2 variant of the g1_components test app. The component lists,
# the closure check and the main component are shared with the build system v1
# variant in ../g1_components, so the two cannot drift apart.
cmake_minimum_required(VERSION 3.22)
set(g1_components_dir "${CMAKE_CURRENT_LIST_DIR}/../g1_components")
include(${g1_components_dir}/g1_setup.cmake)
# main lives in the build system v1 variant of this app
set(EXTRA_COMPONENT_DIRS "${g1_components_dir}/main")
include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
idf_build_set_property(__BUILD_COMPONENT_DEPGRAPH_ENABLED 1)
project(g1_components_cmakev2 C CXX ASM)
idf_project_default()
include(${g1_components_dir}/g1_check.cmake)

View File

@@ -0,0 +1,14 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
# "G1"-components-only app (build system v2)
Build system v2 variant of `../g1_components`. The component lists (`g1_setup.cmake`), the closure and dependency checks (`g1_check.cmake`, `check_dependencies.py`) and the `main` component are shared with the v1 app, so the two cannot drift apart.
Having both apps in the tree means every pipeline that builds test apps checks the G1 closure under both build systems, without a dedicated build system v2 job.
The expected component lists are not identical between the two build systems. Build system v2 can make a dependency conditional on a Kconfig option, so some components that v1 always pulls into the G1 build are absent here. `esp_usb_cdc_rom_console` is one such case: `esp_system` only needs it when the console is set to USB CDC.
For the same reason the v2 list is target dependent: v1 builds everything listed in `COMPONENTS`, while v2 only links what something actually depends on. `esp_hal_cam` (needed by `esp_hw_support` on ESP32-P4 only) and `esp_hal_i2s` (needed by `esp_hal_ana_conv` on ESP32 only) are therefore expected on those targets alone; `g1_check.cmake` drops them from the expected list elsewhere.
See `../g1_components/README.md` for how to use the app and how to interpret failures.

View File

@@ -0,0 +1,6 @@
# Force VFS_SUPPORT_IO off so the conditional requires in esp_stdio and
# esp_libc do not pull vfs, esp_driver_uart, and their transitive deps
# into the g1_components closure. components/vfs/Kconfig defaults this
# symbol to y whenever it is processed, which happens for every discovered
# component under IDF_BUILD_V2 regardless of the COMPONENTS restriction.
CONFIG_VFS_SUPPORT_IO=n