cmake: Add component dependency support

Components should set the COMPONENT_REQUIRES & COMPONENT_PRIVATE_REQUIRES variables to define their
requirements.
This commit is contained in:
Angus Gratton 2018-03-22 17:27:10 +11:00 committed by Angus Gratton
parent 4a2f1f0354
commit 1cb5712463
56 changed files with 562 additions and 201 deletions

View File

@ -14,6 +14,9 @@ if(CONFIG_SYSVIEW_ENABLE)
"sys_view/esp32")
endif()
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES xtensa-debug-module)
register_component()
# disable --coverage for this component, as it is used as transport

View File

@ -1,4 +1,7 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES "")
set(COMPONENT_PRIV_REQUIRES bootloader_support spi_flash)
register_component()

View File

@ -28,6 +28,7 @@
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"
#include "esp_spi_flash.h"
#include "sdkconfig.h"
#include "esp_ota_ops.h"

View File

@ -20,7 +20,6 @@
#include <stddef.h>
#include "esp_err.h"
#include "esp_partition.h"
#include "esp_spi_flash.h"
#ifdef __cplusplus
extern "C"

View File

@ -1,8 +1,11 @@
if(NOT CONFIG_AWS_IOT_SDK)
return()
if(CONFIG_AWS_IOT_SDK)
set(COMPONENT_ADD_INCLUDEDIRS "include aws-iot-device-sdk-embedded-C/include")
set(COMPONENT_SRCDIRS "aws-iot-device-sdk-embedded-C/src port")
else()
message(STATUS "Building empty aws_iot component due to configuration")
endif()
set(COMPONENT_ADD_INCLUDEDIRS "include aws-iot-device-sdk-embedded-C/include")
set(COMPONENT_SRCDIRS "aws-iot-device-sdk-embedded-C/src port")
set(COMPONENT_REQUIRES "mbedtls")
set(COMPONENT_PRIV_REQUIRES "jsmn")
register_component()

View File

@ -1,2 +1,7 @@
# TODO: add config stuff for bootloader here
# bootloader component logic is all in project_include.cmake,
# and subproject/CMakeLists.txt.
#
# This file is only included so the build system finds the
# component

View File

@ -9,6 +9,8 @@ set(COMPONENTS bootloader esptool_py esp32 soc bootloader_support log spi_flash
set(BOOTLOADER_BUILD 1)
add_definitions(-DBOOTLOADER_BUILD=1)
set(COMPONENT_REQUIRES_COMMON log esp32 soc)
set(MAIN_SRCS main/bootloader_start.c)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@ -2,9 +2,13 @@ set(COMPONENT_SRCDIRS "src")
if(${BOOTLOADER_BUILD})
set(COMPONENT_ADD_INCLUDEDIRS "include include_priv")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc)
else()
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "include_priv")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls micro-ecc)
endif()
register_component()

View File

@ -1,83 +1,90 @@
if(NOT CONFIG_BT_ENABLED)
return()
if(CONFIG_BT_ENABLED)
set(COMPONENT_SRCDIRS .)
set(COMPONENT_ADD_INCLUDEDIRS include)
if(CONFIG_BLUEDROID_ENABLED)
list(APPEND COMPONENT_ADD_INCLUDEDIRS
bluedroid/bta/include
bluedroid/bta/sys/include
bluedroid/btcore/include
bluedroid/device/include
bluedroid/hci/include
bluedroid/osi/include
bluedroid/external/sbc/decoder/include
bluedroid/external/sbc/encoder/include
bluedroid/btc/profile/esp/blufi/include
bluedroid/btc/profile/esp/include
bluedroid/btc/profile/std/a2dp/include
bluedroid/btc/profile/std/include
bluedroid/btc/include
bluedroid/stack/gap/include
bluedroid/stack/gatt/include
bluedroid/stack/l2cap/include
bluedroid/stack/sdp/include
bluedroid/stack/smp/include
bluedroid/stack/avct/include
bluedroid/stack/avrc/include
bluedroid/stack/avdt/include
bluedroid/stack/a2dp/include
bluedroid/stack/rfcomm/include
bluedroid/stack/include
bluedroid/api/include
bluedroid/include
)
list(APPEND COMPONENT_SRCDIRS
bluedroid/bta/dm
bluedroid/bta/gatt
bluedroid/bta/hh
bluedroid/bta/sdp
bluedroid/bta/av
bluedroid/bta/ar
bluedroid/bta/sys
bluedroid/bta/jv
bluedroid/btcore
bluedroid/btif
bluedroid/device
bluedroid/hci
bluedroid/main
bluedroid/osi
bluedroid/external/sbc/decoder/srce
bluedroid/external/sbc/encoder/srce
bluedroid/btc/core
bluedroid/btc/profile/esp/blufi
bluedroid/btc/profile/std/gap
bluedroid/btc/profile/std/gatt
bluedroid/btc/profile/std/a2dp
bluedroid/btc/profile/std/avrc
bluedroid/btc/profile/std/spp
bluedroid/stack/btm
bluedroid/stack/btu
bluedroid/stack/gap
bluedroid/stack/gatt
bluedroid/stack/hcic
bluedroid/stack/l2cap
bluedroid/stack/sdp
bluedroid/stack/smp
bluedroid/stack/avct
bluedroid/stack/avrc
bluedroid/stack/avdt
bluedroid/stack/a2dp
bluedroid/stack/rfcomm
bluedroid/api
)
endif()
endif()
set(COMPONENT_SRCDIRS .)
set(COMPONENT_ADD_INCLUDEDIRS include)
# requirements can't depend on config
set(COMPONENT_PRIV_REQUIRES lwip nvs_flash)
if(CONFIG_BLUEDROID_ENABLED)
list(APPEND COMPONENT_ADD_INCLUDEDIRS
bluedroid/bta/include
bluedroid/bta/sys/include
bluedroid/btcore/include
bluedroid/device/include
bluedroid/hci/include
bluedroid/osi/include
bluedroid/external/sbc/decoder/include
bluedroid/external/sbc/encoder/include
bluedroid/btc/profile/esp/blufi/include
bluedroid/btc/profile/esp/include
bluedroid/btc/profile/std/a2dp/include
bluedroid/btc/profile/std/include
bluedroid/btc/include
bluedroid/stack/gap/include
bluedroid/stack/gatt/include
bluedroid/stack/l2cap/include
bluedroid/stack/sdp/include
bluedroid/stack/smp/include
bluedroid/stack/avct/include
bluedroid/stack/avrc/include
bluedroid/stack/avdt/include
bluedroid/stack/a2dp/include
bluedroid/stack/rfcomm/include
bluedroid/stack/include
bluedroid/api/include
bluedroid/include)
list(APPEND COMPONENT_SRCDIRS
bluedroid/bta/dm
bluedroid/bta/gatt
bluedroid/bta/hh
bluedroid/bta/sdp
bluedroid/bta/av
bluedroid/bta/ar
bluedroid/bta/sys
bluedroid/bta/jv
bluedroid/btcore
bluedroid/btif
bluedroid/device
bluedroid/hci
bluedroid/main
bluedroid/osi
bluedroid/external/sbc/decoder/srce
bluedroid/external/sbc/encoder/srce
bluedroid/btc/core
bluedroid/btc/profile/esp/blufi
bluedroid/btc/profile/std/gap
bluedroid/btc/profile/std/gatt
bluedroid/btc/profile/std/a2dp
bluedroid/btc/profile/std/avrc
bluedroid/btc/profile/std/spp
bluedroid/stack/btm
bluedroid/stack/btu
bluedroid/stack/gap
bluedroid/stack/gatt
bluedroid/stack/hcic
bluedroid/stack/l2cap
bluedroid/stack/sdp
bluedroid/stack/smp
bluedroid/stack/avct
bluedroid/stack/avrc
bluedroid/stack/avdt
bluedroid/stack/a2dp
bluedroid/stack/rfcomm
bluedroid/api
)
endif()
# currently uses libcoap's hash table in hashkey.h
set(COMPONENT_REQUIRES coap)
register_component()
target_link_libraries(bt "-L${CMAKE_CURRENT_LIST_DIR}/lib")
target_link_libraries(bt btdm_app)
if(CONFIG_BT_ENABLED)
target_link_libraries(bt "-L${CMAKE_CURRENT_LIST_DIR}/lib")
target_link_libraries(bt btdm_app)
endif()

View File

@ -19,6 +19,8 @@ set(COMPONENT_SRCS
port/coap_io_socket.c
)
set(COMPONENT_REQUIRES lwip)
register_component()
# Needed for coap headers in public builds, also.

View File

@ -1,5 +1,7 @@
set(COMPONENT_ADD_INCLUDEDIRS .)
set(COMPONENT_SRCDIRS linenoise argtable3 .)
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,4 +1,5 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_REQUIRES)
register_component()
target_link_libraries(cxx stdc++)

View File

@ -2,4 +2,6 @@ set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "include/driver")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -0,0 +1,7 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS ".")
set(COMPONENT_REQUIRES mbedtls)
set(COMPONENT_PRIV_REQUIRES lwip nghttp)
register_component()

View File

@ -1,7 +1,9 @@
if(BOOTLOADER_BUILD)
# For bootloader, all we need from esp32 is headers
add_library(esp32 INTERFACE)
target_include_directories(esp32 INTERFACE include)
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_REQUIRES ${COMPONENTS})
set(COMPONENT_SRCDIRS "")
register_component(esp32)
# as cmake won't attach linker args to a header-only library, attach
# linker args directly to the bootloader.elf
@ -18,6 +20,11 @@ else()
set(COMPONENT_SRCDIRS ". hwcrypto")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES driver) # required because esp_sleep.h uses gpio_num_t & touch_pad_t
set(COMPONENT_PRIV_REQUIRES
adapter app bootloader_debug ethernet_flash flash_log mbedtls_module nvs_pthread
spi-supplicant-support tcpip trace_vfs wpa xtensa)
register_component()
target_link_libraries(esp32 "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib")

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,4 +1,7 @@
set(COMPONENT_SRCDIRS . eth_phy)
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES tcpip_adapter)
register_component()

View File

@ -1,6 +1,8 @@
set(COMPONENT_ADD_INCLUDEDIRS port/include include/expat)
set(COMPONENT_SRCDIRS library port)
set(COMPONENT_REQUIRES)
register_component()
component_compile_definitions(HAVE_EXPAT_CONFIG_H)

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS src)
set(COMPONENT_ADD_INCLUDEDIRS src)
set(COMPONENT_REQUIRES wear_levelling sdmmc)
register_component()

View File

@ -1,6 +1,8 @@
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_PRIV_INCLUDEDIRS include/freertos)
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_REQUIRES)
register_component()
target_link_libraries(freertos "-Wl,--undefined=uxTopUsedPriority")

View File

@ -6,6 +6,8 @@ endif()
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES "")
register_component()
if(CONFIG_HEAP_TRACING)

View File

@ -1,2 +1,3 @@
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS "src")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES "")
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS cJSON)
set(COMPONENT_ADD_INCLUDEDIRS cJSON)
set(COMPONENT_REQUIRES "")
register_component()

View File

@ -1,5 +1,7 @@
set(SRC libsodium/src/libsodium)
set(COMPONENT_REQUIRES "mbedtls")
set(COMPONENT_SRCDIRS
port

View File

@ -1,3 +1,4 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -16,6 +16,9 @@ set(COMPONENT_SRCDIRS
${LWIP_PPP_DIRS} netif
port/freertos port/netif port/debug port)
set(COMPONENT_REQUIRES "")
set(COMPONENT_PRIV_REQUIRES ethernet tcpip_adapter)
register_component()
component_compile_options(-Wno-address)

View File

@ -1,6 +1,8 @@
set(COMPONENT_ADD_INCLUDEDIRS port/include include)
set(COMPONENT_SRCDIRS library port)
set(COMPONENT_REQUIRES lwip)
register_component()
target_compile_definitions(mbedtls PUBLIC

View File

@ -1,5 +1,7 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "private_include")
set(COMPONENT_REQUIRES lwip mbedtls console tcpip_adapter)
register_component()

View File

@ -3,4 +3,6 @@ set(COMPONENT_SRCS micro-ecc/uECC.c)
set(COMPONENT_ADD_INCLUDEDIRS micro-ecc)
set(COMPONENT_REQUIRES)
register_component()

View File

@ -15,6 +15,8 @@ else()
set(LIBM m)
endif()
set(COMPONENT_REQUIRES vfs) # for sys/ioctl.h
register_component()
target_link_libraries(newlib "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib")

View File

@ -1,4 +1,6 @@
set(COMPONENT_ADD_INCLUDEDIRS port/include nghttp2/lib/includes)
set(COMPONENT_SRCDIRS nghttp2/lib port)
set(COMPONENT_REQUIRES lwip mbedtls)
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS src)
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_REQUIRES spi_flash)
register_component()

View File

@ -2,4 +2,6 @@ set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_PRIV_INCLUDEDIRS include/internal include/platform include/openssl)
set(COMPONENT_SRCDIRS library platform)
set(COMPONENT_REQUIRES mbedtls)
register_component()

View File

@ -1,5 +1,7 @@
set(partition_table_offset 0x8000)
register_config_only_component()
# Set partition_csv to the configured partition source file
#
if(CONFIG_PARTITION_TABLE_CUSTOM)
@ -56,4 +58,3 @@ set_property(GLOBAL APPEND_STRING PROPERTY
ESPTOOL_WRITE_FLASH_ARGS
"${partition_table_offset} ${final_partition_bin} ")
register_config_only_component()

View File

@ -1,3 +1,4 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,4 +1,4 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES driver)
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_REQUIRES lwip tcpip_adapter)
register_component()

View File

@ -3,4 +3,7 @@ set(SOC_NAME esp32)
set(COMPONENT_SRCDIRS ${SOC_NAME})
set(COMPONENT_ADD_INCLUDEDIRS ${SOC_NAME}/include include)
set(COMPONENT_REQUIRES)
register_component()

View File

@ -2,10 +2,13 @@ if(BOOTLOADER_BUILD)
# Bootloader needs SPIUnlock from this file, but doesn't
# need other parts of this component
set(COMPONENT_SRCS spi_flash_rom_patch.c)
set(COMPONENT_PRIV_REQUIRES bootloader_support)
else()
set(COMPONENT_SRCDIRS .)
set(COMPONENT_PRIV_REQUIRES bootloader_support app_update)
endif()
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,5 +1,9 @@
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "spiffs/src")
set(COMPONENT_SRCDIRS ". spiffs/src")
set(COMPONENT_REQUIRES spi_flash)
set(COMPONENT_PRIV_REQUIRES bootloader_support)
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES lwip)
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View File

@ -1,4 +1,5 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS private_include)
set(COMPONENT_REQUIRES spi_flash)
register_component()

View File

@ -1,6 +1,9 @@
set(COMPONENT_SRCDIRS src/crypto port src/fast_crypto)
set(COMPONENT_ADD_INCLUDEDIRS include port/include)
set(COMPONENT_REQUIRES "")
set(COMPONENT_PRIV_REQUIRES lwip mbedtls)
register_component()
component_compile_definitions(__ets__)

View File

@ -1,4 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES "")
register_component()

View File

@ -78,7 +78,7 @@ The :ref:`getting started guide <get-started-configure-cmake>` contains a brief
``idf.py`` should be run in an ESP-IDF "project" directory, ie one containing a ``CMakeLists.txt`` file. Older style projects with a Makefile will not work with ``idf.py``.
Type ``idf.py --help`` for a full list of commands. Here are a summary of a few:
Type ``idf.py --help`` for a full list of commands. Here are a summary of the most useful ones:
- ``idf.py menuconfig`` runs the "menuconfig" tool to configure the project.
- ``idf.py build`` will build the project found in the current directory. This can involve multiple steps:
@ -207,7 +207,8 @@ These variables all have default values that can be overridden for custom behavi
- ``COMPONENT_DIRS``: Directories to search for components. Defaults to `${IDF_PATH}/components`, `${PROJECT_PATH}/components`, and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places.
- ``EXTRA_COMPONENT_DIRS``: Optional list of additional directories to search for components. Paths can be relative to the project directory, or absolute.
- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the ``COMPONENT_DIRS`` directories. Use this variable to "trim down" the project for faster build times.
- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the ``COMPONENT_DIRS`` directories. Use this variable to "trim down" the project for faster build times. Note that any component which "requires" another component via ``COMPONENT_REQUIRES`` will automatically have it added to this list, so the ``COMPONENTS`` list doesn't need to include dependencies in this way.
- ``COMPONENT_REQUIRES_COMMON``: A list of components that every component requires. These components are automatically treated to be in every component's ``COMPONENT_PRIV_REQUIRES`` list and also the project's ``COMPONENTS`` list. By default, this is set to the minimal set of core "system" components needed for any ESP-IDF project.
Any paths in these variables can be absolute paths, or set relative to the project directory.
@ -273,22 +274,18 @@ The following variables are set at the project level, but available for use in c
If you modify any of these variables inside ``CMakeLists.txt`` then this will not prevent other components from building but it may make your component hard to build and/or debug.
Optional Project-Wide Component Variables
-----------------------------------------
The following variables can be set inside component ``CMakeLists.txt`` to control build settings across the entire project:
- ``COMPONENT_ADD_INCLUDEDIRS``: Paths, relative to the component
directory, which will be added to the include search path for
all components in the project. If an include directory is only needed to compile
all other components which require this one. If an include directory is only needed to compile
this specific component, add it to ``COMPONENT_PRIV_INCLUDEDIRS`` instead.
- ``COMPONENT_DEPENDS``: Optional list of component names that should be
compiled before this component. This is not necessary for
link-time dependencies, because all component include directories
are available at all times. It is necessary if one component
generates an include file which you then want to include in another
component. Most components do not need to set this variable.
- ``COMPONENT_REQUIRES`` is a (space-separated) list of components that are required to include this project's header files into other components. If a public header header file listed in ``COMPONENT_ADD_INCLUDEDIRS`` includes a header from another component, that component should be listed in ``COMPONENT_REQUIRES``. Requirements are recursive.
The ``COMPONENT_REQUIRES`` list can be empty because some very common components (like newlib for libc, freertos for RTOS functions, etc) are always required by all components. This list is found in the project-level variable ``COMPONENT_REQUIRES_COMMON``.
If a component only requires another component's headers to compile its source files (not for including this component's headers), then these components should be listed in ``COMPONENT_PRIV_REQUIRES`` instead.
See `Component Requirements` for more details.
Optional Component-Specific Variables
-------------------------------------
@ -298,6 +295,7 @@ The following variables can be set inside ``component.mk`` to control the build
- ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to
the component directory, which will be added to the include search
path for this component's source files only.
- ``COMPONENT_PRIV_REQUIRES`` is a (space-separated) list of components that are required to either compile or link this component's source files. These components' header paths do not propagate to other components which require it, they are only used to compile this component's sources. See `Component Requirements` for more details.
- ``COMPONENT_SRCDIRS``: Directory paths, must be relative to the
component directory, which will be searched for source files (``*.cpp``,
``*.c``, ``*.S``). Set this to specify a list of directories
@ -345,6 +343,45 @@ The ESP-IDF build system adds the following C preprocessor definitions on the co
- ``ESP_PLATFORM`` — Can be used to detect that build happens within ESP-IDF.
- ``IDF_VER`` — Defined to a git version string. E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit.
Component Requirements
======================
When compiling each component, the ESP-IDF build system recurisvely evaluates its components.
Each component's source file is compiled with these include path directories:
- The current component's ``COMPONENT_ADD_INCLUDEDIRS`` and ``COMPONENT_PRIV_INCLUDEDIRS``.
- The ``COMPONENT_ADD_INCLUDEDIRS`` set by all components in the current component's ``COMPONENT_REQUIRES`` and ``COMPONENT_PRIV_REQUIRES`` variables (ie all the current component's public and private dependencies).
- All of the ``COMPONENT_REQUIRES`` of those components, evaluated recursively (ie all public dependencies of this component's dependencies, recursively expanded).
When writing a component
------------------------
- ``COMPONENT_REQUIRES`` should be set to all components whose header files are #included from the *public* header files of this component.
- ``COMPONENT_PRIV_REQUIRES`` should be set to all components whose header files are #included from *any source files* of this component, unless already listed in ``COMPONENT_REQUIRES``. Or any component which is required to be linked in order for this component to function correctly.
- ``COMPONENT_REQUIRES`` and/or ``COMPONENT_PRIV_REQUIRES`` should be set before calling ``register_component()``.
- The values of ``COMPONENT_REQUIRES`` and ``COMPONENT_PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices.
- Not setting either or both ``REQUIRES`` variables is fine. If the component has no requirements except for the "common" components needed for RTOS, libc, etc (``COMPONENT_REQUIRES_COMMON``) then both variables can be empty or unset.
When creating a project
-----------------------
- By default, every component is included in the build.
- If you set the ``COMPONENTS`` variable to a minimal list of components used directly by your project, then the build will include:
- Components mentioned explicitly in ``COMPONENTS``.
- Those components' requirements (evaluated recursively).
- The "common" components that every component depends on.
- Setting ``COMPONENTS`` to the minimal list of components you need can significantly reduce your project's compile time.
- When compiling the project's source files (``MAIN_SRCS``), the public header directories of all components included in the build are available.
Requirements in the build system implementation
------------------------------------------------------------------
- Very early in the cmake configuration process, the script ``expand_requirements.cmake`` is run. This script does a partial evaluation of all component CMakeLists.txt files and builds a graph of component requirements (this graph may have cycles). The graph is used to generate a file ``component_depends.cmake`` in the build directory.
- The main cmake process then includes this file and uses it to determine the list of components to include in the build (internal ``BUILD_COMPONENTS`` variable).
- Configuration is then evaluated for the components included in the build.
- Each component is included in the build normally and the CMakeLists.txt file is evaluated again to add the component libraries to the build.
Build Process Internals
=======================
@ -362,6 +399,7 @@ project function
The custom ``project()`` function performs the following steps:
- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see `above<requirements-in-the-build-system-implementation>`).
- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set).
- Loads the project configuration from the ``sdkconfig`` file and produces a ``cmake`` include file and a C header file, to set config macros. If the project configuration changes, cmake will automatically be re-run to reconfigure the project.
- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the ESP-IDF toolchain file with the Xtensa ESP32 toolchain.
@ -525,10 +563,8 @@ why it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property.
(Note: If generating files as part of the project CMakeLists, not a component CMakeLists, use ``${PROJECT_PATH}`` instead of ``${COMPONENT_PATH}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_NAME}``.)
If a a source file from another component included ``logo.h``, then this
component's name would have to be added to the other component's
``COMPONENT_DEPENDS`` list to ensure that the components were built
in-order.
If a a source file from another component included ``logo.h``, then ``add_dependencies`` would need to be called to add a dependency between
the two components, to ensure that the component source files were always compiled in the correct order.
Embedding Binary Data
---------------------

View File

@ -202,7 +202,7 @@ The following variables can be set inside ``component.mk`` to control build sett
the app executable. Defaults to ``-l$(COMPONENT_NAME)``. If
adding pre-compiled libraries to this directory, add them as
absolute paths - ie $(COMPONENT_PATH)/libwhatever.a
- ``COMPONENT_DEPENDS``: Optional list of component names that should
- ``COMPONENT_REQUIRES``: Optional list of component names that should
be compiled before this component. This is not necessary for
link-time dependencies, because all component include directories
are available at all times. It is necessary if one component
@ -544,7 +544,7 @@ generated before ``graphics_lib.c`` is compiled.
If a a source file in another component included ``logo.h``, then this
component's name would have to be added to the other component's
``COMPONENT_DEPENDS`` list to ensure that the components were built
``COMPONENT_REQUIRES`` list to ensure that the components were built
in-order.
Embedding Binary Data

View File

@ -2,4 +2,7 @@ set(COMPONENT_ADD_INCLUDEDIRS .)
set(COMPONENT_SRCDIRS .)
set(COMPONENT_REQUIRES nghttp)
set(COMPONENT_PRIV_REQUIRES lwip esp-tls)
register_component()

View File

@ -1,53 +1,16 @@
# Search 'component_dirs' for components and return them
# as a list of names in 'component_names' and a list of full paths in
# 'component_paths'
#
# component_paths contains only unique component names. Directories
# earlier in the component_dirs list take precedence.
function(components_find_all component_dirs filter_names component_paths component_names)
# component_dirs entries can be files or lists of files
set(paths "")
set(names "")
# start by expanding the component_dirs list with all subdirectories
foreach(dir ${component_dirs})
# Iterate any subdirectories for values
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
foreach(subdir ${subdirs})
set(component_dirs "${component_dirs};${subdir}")
endforeach()
endforeach()
# Look for a component in each component_dirs entry
foreach(dir ${component_dirs})
file(GLOB component "${dir}/CMakeLists.txt")
if(component)
get_filename_component(component "${component}" DIRECTORY)
get_filename_component(name "${component}" NAME)
if(NOT filter_names OR (name IN_LIST filter_names))
if(NOT name IN_LIST names)
set(names "${names};${name}")
set(paths "${paths};${component}")
endif()
endif()
else() # no CMakeLists.txt file
# test for legacy component.mk and warn
file(GLOB legacy_component "${dir}/component.mk")
if(legacy_component)
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. "
"Component will be skipped.")
endif()
# Given a list of components in 'component_paths', filter only paths to the components
# mentioned in 'components' and return as a list in 'result_paths'
function(components_get_paths component_paths components result_paths)
set(result "")
foreach(path ${component_paths})
get_filename_component(name "${path}" NAME)
if("${name}" IN_LIST components)
list(APPEND result "${name}")
endif()
endforeach()
set(${component_paths} ${paths} PARENT_SCOPE)
set(${component_names} ${names} PARENT_SCOPE)
set("${result_path}" "${result}" PARENT_SCOPE)
endfunction()
# Add a component to the build, using the COMPONENT variables defined
# in the parent
#
@ -76,7 +39,7 @@ function(register_component)
endforeach()
endif()
# add public includes from other components when building this component
# add as a PUBLIC library (if there are source files) or INTERFACE (if header only)
if(COMPONENT_SRCS OR embed_binaries)
add_library(${component} STATIC ${COMPONENT_SRCS})
set(include_type PUBLIC)
@ -97,7 +60,7 @@ function(register_component)
target_add_binary_data("${component}" "${embed_data}" "${embed_type}")
endforeach()
# add public includes
# add component public includes
foreach(include_dir ${COMPONENT_ADD_INCLUDEDIRS})
get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
if(NOT IS_DIRECTORY ${abs_dir})
@ -107,7 +70,7 @@ function(register_component)
target_include_directories(${component} ${include_type} ${abs_dir})
endforeach()
# add private includes
# add component private includes
foreach(include_dir ${COMPONENT_PRIV_INCLUDEDIRS})
if(${include_type} STREQUAL INTERFACE)
message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE} "
@ -121,7 +84,6 @@ function(register_component)
endif()
target_include_directories(${component} PRIVATE ${abs_dir})
endforeach()
endfunction()
function(register_config_only_component)
@ -131,30 +93,47 @@ function(register_config_only_component)
# No-op for now...
endfunction()
function(components_finish_registration)
# each component should see the include directories of each other
#
# (we can't do this until all components are registered, because if(TARGET ...) won't work
foreach(a ${COMPONENTS} ${CMAKE_PROJECT_NAME}.elf)
if(TARGET ${a})
get_target_property(a_imported ${a} IMPORTED)
get_target_property(a_type ${a} TYPE)
if(NOT a_imported)
if(${a_type} STREQUAL STATIC_LIBRARY OR ${a_type} STREQUAL EXECUTABLE)
foreach(b ${COMPONENTS})
if(TARGET ${b} AND NOT ${a} STREQUAL ${b})
# Add all public compile options from b in a
target_include_directories(${a} PRIVATE
$<TARGET_PROPERTY:${b},INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(${a} PRIVATE
$<TARGET_PROPERTY:${b},INTERFACE_COMPILE_DEFINITIONS>)
target_compile_options(${a} PRIVATE
$<TARGET_PROPERTY:${b},INTERFACE_COMPILE_OPTIONS>)
endif()
endforeach(b)
endif()
endif()
function(add_component_dependencies target dep dep_type)
get_target_property(target_type ${target} TYPE)
get_target_property(target_imported ${target} IMPORTED)
if(${target_type} STREQUAL STATIC_LIBRARY OR ${target_type} STREQUAL EXECUTABLE)
if(TARGET ${dep})
# Add all compile options exported by dep into target
target_include_directories(${target} ${dep_type}
$<TARGET_PROPERTY:${dep},INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(${target} ${dep_type}
$<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_DEFINITIONS>)
target_compile_options(${target} ${dep_type}
$<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_OPTIONS>)
endif()
endif()
endfunction()
function(components_finish_registration)
# have the executable target depend on all components in the build
set_target_properties(${CMAKE_PROJECT_NAME}.elf PROPERTIES INTERFACE_COMPONENT_REQUIRES "${BUILD_COMPONENTS}")
spaces2list(COMPONENT_REQUIRES_COMMON)
# each component should see the include directories of its requirements
#
# (we can't do this until all components are registered and targets exist in cmake, as we have
# a circular requirements graph...)
foreach(a ${BUILD_COMPONENTS})
if(TARGET ${a})
get_component_requirements("${a}" a_deps a_priv_deps)
list(APPEND a_priv_deps ${COMPONENT_REQUIRES_COMMON})
foreach(b ${a_deps})
add_component_dependencies(${a} ${b} PUBLIC)
endforeach()
foreach(b ${a_priv_deps})
add_component_dependencies(${a} ${b} PRIVATE)
endforeach()
get_target_property(a_type ${a} TYPE)
if(${a_type} MATCHES .+_LIBRARY)
set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES};${a}")
endif()
@ -164,7 +143,7 @@ function(components_finish_registration)
# Add each component library's link-time dependencies (which are otherwise ignored) to the executable
# LINK_DEPENDS in order to trigger a re-link when needed (on Ninja/Makefile generators at least).
# (maybe this should probably be something CMake does, but it doesn't do it...)
foreach(component ${COMPONENTS})
foreach(component ${BUILD_COMPONENTS})
if(TARGET ${component})
get_target_property(imported ${component} IMPORTED)
get_target_property(type ${component} TYPE)
@ -179,16 +158,6 @@ function(components_finish_registration)
endif()
endforeach()
# Embedded binary & text files
spaces2list(COMPONENT_EMBED_FILES)
foreach(embed_src ${COMPONENT_EMBED_FILES})
target_add_binary_data(${component} "${embed_src}" BINARY)
endforeach()
spaces2list(COMPONENT_EMBED_TXTFILES)
foreach(embed_src ${COMPONENT_EMBED_TXTFILES})
target_add_binary_data(${component} "${embed_src}" TEXT)
endforeach()
target_link_libraries(${CMAKE_PROJECT_NAME}.elf ${COMPONENT_LIBRARIES})
message(STATUS "Component libraries: ${COMPONENT_LIBRARIES}")

View File

@ -180,6 +180,11 @@ def convert_component(project_path, component_path):
with open(cmakelists_path, "w") as f:
f.write("set(COMPONENT_ADD_INCLUDEDIRS %s)\n\n" % component_add_includedirs)
f.write("# Edit following two lines to set component requirements (see docs)\n")
f.write("set(COMPONENT_REQUIRES "")\n")
f.write("set(COMPONENT_PRIV_REQUIRES "")\n\n")
if component_srcdirs is not None:
f.write("set(COMPONENT_SRCDIRS %s)\n\n" % component_srcdirs)
f.write("register_component()\n")

View File

@ -13,6 +13,10 @@ macro(idf_set_global_variables)
set_default(EXTRA_COMPONENT_DIRS "")
# Commmon components, required by every component in the build
#
set_default(COMPONENT_REQUIRES_COMMON "cxx esp32 newlib freertos heap log soc")
# PROJECT_PATH has the path to the IDF project (top-level cmake directory)
#
# (cmake calls this CMAKE_SOURCE_DIR, keeping old name for compatibility.)

View File

@ -35,7 +35,7 @@ function(kconfig_process_config)
# Find Kconfig and Kconfig.projbuild for each component as applicable
# if any of these change, cmake should rerun
foreach(dir ${COMPONENT_PATHS} "${CMAKE_SOURCE_DIR}/main")
foreach(dir ${BUILD_COMPONENT_PATHS} "${CMAKE_SOURCE_DIR}/main")
file(GLOB kconfig "${dir}/Kconfig")
if(kconfig)
set(kconfigs "${kconfigs} ${kconfig}")

View File

@ -46,16 +46,32 @@ macro(project name)
# Set global variables used by rest of the build
idf_set_global_variables()
# Search COMPONENT_DIRS for COMPONENTS, make a list of full paths to each
# component in COMPONENT_PATHS
components_find_all("${COMPONENT_DIRS}" "${COMPONENTS}"
COMPONENT_PATHS COMPONENTS)
# Establish dependencies for components in the build
# (this happens before we even generate config...)
if(COMPONENTS)
# Make sure if an explicit list of COMPONENTS is given, it contains the "common" component requirements
# (otherwise, if COMPONENTS is empty then all components will be included in the build.)
set(COMPONENTS "${COMPONENTS} ${COMPONENT_REQUIRES_COMMON}")
endif()
execute_process(COMMAND "${CMAKE_COMMAND}"
-D "COMPONENTS=${COMPONENTS}"
-D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake"
-D "COMPONENT_DIRS=${COMPONENT_DIRS}"
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
WORKING_DIRECTORY "${IDF_PATH}/tools/cmake")
include("${CMAKE_BINARY_DIR}/component_depends.cmake")
# We now have the following component-related variables:
# COMPONENTS is the list of initial components set by the user (or empty to include all components in the build).
# BUILD_COMPONENTS is the list of components to include in the build.
# BUILD_COMPONENT_PATHS is the paths to all of these components.
# Print list of components
string(REPLACE ";" " " COMPONENTS_SPACES "${COMPONENTS}")
message(STATUS "Component names: ${COMPONENTS_SPACES}")
unset(COMPONENTS_SPACES)
message(STATUS "Component paths: ${COMPONENT_PATHS}")
string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}")
message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}")
unset(BUILD_COMPONENTS_SPACES)
message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}")
kconfig_set_variables()
@ -88,14 +104,14 @@ macro(project name)
git_describe(PROJECT_VER "${CMAKE_CURRENT_SOURCE_DIR}")
# Include any top-level project_include.cmake files from components
foreach(component ${COMPONENT_PATHS})
foreach(component ${BUILD_COMPONENT_PATHS})
include_if_exists("${component}/project_include.cmake")
endforeach()
#
# Add each component to the build as a library
#
foreach(COMPONENT_PATH ${COMPONENT_PATHS})
foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME})
endforeach()

View File

@ -0,0 +1,216 @@
# expand_requires.cmake is a utility cmake script to expand component requirements early in the build,
# before the components are ready to be included.
#
# Parameters:
# - COMPONENTS = Space-separated list of initial components to include in the build.
# Can be empty, in which case all components are in the build.
# - DEPENDENCIES_FILE = Path of generated cmake file which will contain the expanded dependencies for these
# components.
# - COMPONENT_DIRS = List of paths to search for all components.
# - DEBUG = Set -DDEBUG=1 to debug component lists in the build.
#
# If successful, DEPENDENCIES_FILE can be expanded to set BUILD_COMPONENTS & BUILD_COMPONENT_PATHS with all
# components required for the build, and the get_component_requirements() function to return each component's
# recursively expanded requirements.
#
# TODO: Error out if a component requirement is missing
cmake_minimum_required(VERSION 3.5)
include("utilities.cmake")
if(NOT DEPENDENCIES_FILE)
message(FATAL_ERROR "DEPENDENCIES_FILE must be set.")
endif()
if(NOT COMPONENT_DIRS)
message(FATAL_ERROR "COMPONENT_DIRS variable must be set")
endif()
spaces2list(COMPONENT_DIRS)
function(debug message)
if(DEBUG)
message(STATUS "${message}")
endif()
endfunction()
# Dummy register_component used to save requirements variables as global properties, for later expansion
#
# (expand_component_requirements() includes the component CMakeLists.txt, which then sets its component variables,
# calls this dummy macro, and immediately exits again.)
macro(register_component)
spaces2list(COMPONENT_REQUIRES)
set_property(GLOBAL PROPERTY "${COMPONENT}_REQUIRES" "${COMPONENT_REQUIRES}")
spaces2list(COMPONENT_PRIV_REQUIRES)
set_property(GLOBAL PROPERTY "${COMPONENT}_PRIV_REQUIRES" "${COMPONENT_PRIV_REQUIRES}")
# This is tricky: we override register_component() so it returns out of the component CMakeLists.txt
# (as we're declaring it as a macro not a function, so it doesn't have its own scope.)
#
# This means no targets are defined, and the component expansion ends early.
return()
endmacro()
macro(register_config_only_component)
register_component()
endmacro()
# Given a component name (find_name) and a list of component paths (component_paths),
# return the path to the component in 'variable'
#
# Fatal error is printed if the component is not found.
function(find_component_path find_name component_paths variable)
foreach(path ${component_paths})
get_filename_component(name "${path}" NAME)
if("${name}" STREQUAL "${find_name}")
set("${variable}" "${path}" PARENT_SCOPE)
return()
endif()
endforeach()
# TODO: find a way to print the dependency chain that lead to this not-found component
message(WARNING "Required component ${find_name} is not found in any of the provided COMPONENT_DIRS")
endfunction()
# components_find_all: Search 'component_dirs' for components and return them
# as a list of names in 'component_names' and a list of full paths in
# 'component_paths'
#
# component_paths contains only unique component names. Directories
# earlier in the component_dirs list take precedence.
function(components_find_all component_dirs component_paths component_names)
# component_dirs entries can be files or lists of files
set(paths "")
set(names "")
# start by expanding the component_dirs list with all subdirectories
foreach(dir ${component_dirs})
# Iterate any subdirectories for values
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
foreach(subdir ${subdirs})
set(component_dirs "${component_dirs};${subdir}")
endforeach()
endforeach()
# Look for a component in each component_dirs entry
foreach(dir ${component_dirs})
file(GLOB component "${dir}/CMakeLists.txt")
if(component)
get_filename_component(component "${component}" DIRECTORY)
get_filename_component(name "${component}" NAME)
if(NOT name IN_LIST names)
set(names "${names};${name}")
set(paths "${paths};${component}")
endif()
else() # no CMakeLists.txt file
# test for legacy component.mk and warn
file(GLOB legacy_component "${dir}/component.mk")
if(legacy_component)
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. "
"Component will be skipped.")
endif()
endif()
endforeach()
set(${component_paths} ${paths} PARENT_SCOPE)
set(${component_names} ${names} PARENT_SCOPE)
endfunction()
# expand_component_requirements: Recursively expand a component's requirements,
# setting global properties BUILD_COMPONENTS & BUILD_COMPONENT_PATHS and
# also invoking the components to call register_component() above,
# which will add per-component global properties with dependencies, etc.
function(expand_component_requirements component)
get_property(build_components GLOBAL PROPERTY BUILD_COMPONENTS)
if(${component} IN_LIST build_components)
return() # already added this component
endif()
find_component_path("${component}" "${ALL_COMPONENT_PATHS}" component_path)
debug("Expanding dependencies of ${component} @ ${component_path}")
if(NOT component_path)
set_property(GLOBAL APPEND PROPERTY COMPONENTS_NOT_FOUND ${component})
return()
endif()
# include the component CMakeLists.txt to expand its properties
# into the global cache (via register_component(), above)
unset(COMPONENT_REQUIRES)
unset(COMPONENT_PRIV_REQUIRES)
set(COMPONENT ${component})
include(${component_path}/CMakeLists.txt)
set_property(GLOBAL APPEND PROPERTY BUILD_COMPONENT_PATHS ${component_path})
set_property(GLOBAL APPEND PROPERTY BUILD_COMPONENTS ${component})
get_property(requires GLOBAL PROPERTY "${component}_REQUIRES")
get_property(requires_priv GLOBAL PROPERTY "${component}_PRIV_REQUIRES")
foreach(req ${requires} ${requires_priv})
expand_component_requirements(${req})
endforeach()
endfunction()
# Main functionality goes here
# Find every available component in COMPONENT_DIRS, save as ALL_COMPONENT_PATHS and ALL_COMPONENTS
components_find_all("${COMPONENT_DIRS}" ALL_COMPONENT_PATHS ALL_COMPONENTS)
if(NOT COMPONENTS)
set(COMPONENTS "${ALL_COMPONENTS}")
endif()
spaces2list(COMPONENTS)
debug("ALL_COMPONENT_PATHS ${ALL_COMPONENT_PATHS}")
debug("ALL_COMPONENTS ${ALL_COMPONENTS}")
set_property(GLOBAL PROPERTY BUILD_COMPONENTS "")
set_property(GLOBAL PROPERTY BUILD_COMPONENT_PATHS "")
set_property(GLOBAL PROPERTY COMPONENTS_NOT_FOUND "")
foreach(component ${COMPONENTS})
debug("Expanding initial component ${component}")
expand_component_requirements(${component})
endforeach()
get_property(build_components GLOBAL PROPERTY BUILD_COMPONENTS)
get_property(build_component_paths GLOBAL PROPERTY BUILD_COMPONENT_PATHS)
get_property(not_found GLOBAL PROPERTY COMPONENTS_NOT_FOUND)
debug("components in build: ${build_components}")
debug("components in build: ${build_component_paths}")
debug("components not found: ${not_found}")
function(line contents)
file(APPEND "${DEPENDENCIES_FILE}" "${contents}\n")
endfunction()
file(WRITE "${DEPENDENCIES_FILE}" "# Component requirements generated by expand_requirements.cmake\n\n")
line("set(BUILD_COMPONENTS ${build_components})")
line("set(BUILD_COMPONENT_PATHS ${build_component_paths})")
line("")
line("# get_component_requirements: Generated function to read the dependencies of a given component.")
line("#")
line("# Parameters:")
line("# - component: Name of component")
line("# - var_requires: output variable name. Set to recursively expanded COMPONENT_REQUIRES ")
line("# for this component.")
line("# - var_private_requires: output variable name. Set to recursively expanded COMPONENT_PRIV_REQUIRES ")
line("# for this component.")
line("#")
line("# Throws a fatal error if 'componeont' is not found (indicates a build system problem).")
line("#")
line("function(get_component_requirements component var_requires var_private_requires)")
foreach(build_component ${build_components})
get_property(reqs GLOBAL PROPERTY "${build_component}_REQUIRES")
get_property(private_reqs GLOBAL PROPERTY "${build_component}_PRIV_REQUIRES")
line(" if(\"\$\{component}\" STREQUAL \"${build_component}\")")
line(" set(\${var_requires} \"${reqs}\" PARENT_SCOPE)")
line(" set(\${var_private_requires} \"${private_reqs}\" PARENT_SCOPE)")
line(" return()")
line(" endif()")
endforeach()
line(" message(FATAL_ERROR \"Component not found: \${component}\")")
line("endfunction()")