From 749e7c7205cca9cc4be05122a38e12072f51c738 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 13 May 2026 16:04:06 +0200 Subject: [PATCH] feat(cmakev2/component): add OPTIONAL flag to idf_component_include Add an OPTIONAL flag to idf_component_include so callers can ask "include this component if it exists" without aborting the build when the component is unknown. Without OPTIONAL, the function behaves exactly as before -- it calls __get_component_interface_or_die and the build aborts on a miss. With OPTIONAL, the function performs a non-fatal interface lookup and returns silently if the component is not known. When combined with INTERFACE , the variable is set to the empty string on miss and to the component's interface target on hit, so callers can write: idf_component_include(button OPTIONAL INTERFACE button_iface) if(button_iface) target_sources(${COMPONENT_TARGET} PRIVATE button_glue.c) target_link_libraries(${COMPONENT_TARGET} PRIVATE ${button_iface}) endif() This gives consumers a public, non-fatal way to wire up integrations with components that may or may not be in the build (managed dependencies pulled in only by some board configurations, optional feature glue, etc.) without reaching into the private __get_component_interface helper or doing dual-namespace COMPONENTS_DISCOVERED checks against both and __ forms. Backward compatible: existing call sites do not pass OPTIONAL and continue to fail loudly on miss. Signed-off-by: Frantisek Hrbata --- tools/cmakev2/component.cmake | 40 ++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/tools/cmakev2/component.cmake b/tools/cmakev2/component.cmake index 8a07d0a91d6..cde6f103d8f 100644 --- a/tools/cmakev2/component.cmake +++ b/tools/cmakev2/component.cmake @@ -807,12 +807,20 @@ endfunction() .. code-block:: cmake idf_component_include( + [OPTIONAL] [INTERFACE ]) *name[in]* Component name. + *OPTIONAL[opt]* + + If specified, the call is a silent no-op when the component is not + known to the build, instead of aborting. When combined with + ``INTERFACE``, the output variable is set to the empty string on + miss, so callers can use ``if(${variable})`` as a truth check. + *INTERFACE[out,opt]* Optional variable where the name of the target interface for the @@ -830,15 +838,41 @@ endfunction() When the ``INTERFACE`` variable is provided, the name of the included component interface target will be stored in it. + + By default, the function aborts the build if ```` is not known to + the build system. Pass ``OPTIONAL`` to make the call non-fatal -- useful + for integrations with components that may or may not be in the build, + such as managed dependencies that only some board configurations pull + in. + + .. code-block:: cmake + + # Wire up an optional integration only when the component is present. + idf_component_include(button OPTIONAL INTERFACE button_iface) + if(button_iface) + target_sources(${COMPONENT_TARGET} PRIVATE button_glue.c) + target_link_libraries(${COMPONENT_TARGET} PRIVATE ${button_iface}) + endif() #]] function(idf_component_include name) - set(options) + set(options OPTIONAL) set(one_value INTERFACE) set(multi_value) cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) - __get_component_interface_or_die(COMPONENT "${name}" - OUTPUT component_interface) + if(ARG_OPTIONAL) + __get_component_interface(COMPONENT "${name}" + OUTPUT component_interface) + if("${component_interface}" STREQUAL "NOTFOUND") + if(DEFINED ARG_INTERFACE) + set(${ARG_INTERFACE} "" PARENT_SCOPE) + endif() + return() + endif() + else() + __get_component_interface_or_die(COMPONENT "${name}" + OUTPUT component_interface) + endif() # Check if the component is already included, meaning the add_subdirectory # has already been called for it and the component has been processed. If