feat(bootloader): add the possibility to specify extra components directories

This commit is contained in:
Omar Chebib 2024-09-10 15:10:34 +08:00
parent a2f3585030
commit 775c65a6b7
13 changed files with 152 additions and 8 deletions

View File

@ -116,8 +116,12 @@ idf_build_get_property(sdkconfig SDKCONFIG)
idf_build_get_property(python PYTHON)
idf_build_get_property(extra_cmake_args EXTRA_CMAKE_ARGS)
# We cannot pass lists are a parameter to the external project without modifying the ';' separator
# BOOTLOADER_EXTRA_COMPONENT_DIRS may have been set by the `main` component, do not overwrite it
list(APPEND BOOTLOADER_EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}")
# We cannot pass lists as a parameter to the external project without modifying the ';' separator
string(REPLACE ";" "|" BOOTLOADER_IGNORE_EXTRA_COMPONENT "${BOOTLOADER_IGNORE_EXTRA_COMPONENT}")
string(REPLACE ";" "|" BOOTLOADER_EXTRA_COMPONENT_DIRS "${BOOTLOADER_EXTRA_COMPONENT_DIRS}")
externalproject_add(bootloader
SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject"
@ -127,7 +131,7 @@ externalproject_add(bootloader
LIST_SEPARATOR |
CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target}
-DPYTHON_DEPS_CHECKED=1 -DPYTHON=${python}
-DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR}
-DEXTRA_COMPONENT_DIRS=${BOOTLOADER_EXTRA_COMPONENT_DIRS}
-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
-DIGNORE_EXTRA_COMPONENT=${BOOTLOADER_IGNORE_EXTRA_COMPONENT}
${sign_key_arg} ${ver_key_arg}

View File

@ -34,8 +34,8 @@ set(COMPONENTS
esp_system
newlib)
# Make EXTRA_COMPONENT_DIRS variable to point to the bootloader_components directory
# of the project being compiled
# EXTRA_COMPONENT_DIRS can be populated with directories containing one or several components.
# Make sure this variable contains `bootloader_components` directory of the project being compiled.
set(PROJECT_EXTRA_COMPONENTS "${PROJECT_SOURCE_DIR}/bootloader_components")
if(EXISTS ${PROJECT_EXTRA_COMPONENTS})
list(APPEND EXTRA_COMPONENT_DIRS "${PROJECT_EXTRA_COMPONENTS}")

View File

@ -245,7 +245,9 @@ These variables all have default values that can be overridden for custom behavi
- ``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 the REQUIRES or PRIV_REQUIRES arguments on component registration will automatically have it added to this list, so the ``COMPONENTS`` list can be very short.
- ``BOOTLOADER_IGNORE_EXTRA_COMPONENT``: A list of components, placed in ``bootloader_components/``, that should be ignored by the bootloader compilation. Use this variable if a bootloader component needs to be included conditionally inside the project.
- ``BOOTLOADER_IGNORE_EXTRA_COMPONENT``: Optional list of components, placed in ``bootloader_components/``, that should be ignored by the bootloader compilation. Use this variable if a bootloader component needs to be included conditionally inside the project.
- ``BOOTLOADER_EXTRA_COMPONENT_DIRS``: Optional list of additional directories to search for components to be compiled as part of the bootloader. Paths can be relative to the project directory, or absolute.
Any paths in these variables can be absolute paths, or set relative to the project directory.
@ -751,7 +753,7 @@ This mechanism is shown in the example :example:`build_system/wrappers`. Check :
Override the Default Bootloader
-------------------------------
Thanks to the optional ``bootloader_components`` directory present in your ESP-IDf project, it is possible to override the default ESP-IDF bootloader. To do so, a new ``bootloader_components/main`` component should be defined, which will make the project directory tree look like the following:
Thanks to the optional ``bootloader_components`` directory present in your ESP-IDF project, it is possible to override the default ESP-IDF bootloader. To do so, a new ``bootloader_components/main`` component should be defined, which will make the project directory tree look like the following:
- myProject/
- CMakeLists.txt
@ -765,7 +767,7 @@ Thanks to the optional ``bootloader_components`` directory present in your ESP-I
- build/
Here the ``my_bootloader.c`` file becomes source code for the new bootloader, which means that it will need to perform all the required operations to set up and load the ``main`` application from flash.
Here, the ``my_bootloader.c`` file becomes source code for the new bootloader, which means that it will need to perform all the required operations to set up and load the ``main`` application from flash.
It is also possible to conditionally replace the bootloader depending on a certain condition, such as the target for example. This can be achieved thanks to the ``BOOTLOADER_IGNORE_EXTRA_COMPONENT`` CMake variable. This list can be used to tell the ESP-IDF bootloader project to ignore and not compile the given components present in ``bootloader_components``. For example, if one wants to use the default bootloader for ESP32 target, then ``myProject/CMakeLists.txt`` should look like the following::
@ -781,6 +783,15 @@ It is important to note that this can also be used for any other bootloader comp
See :example:`custom_bootloader/bootloader_override` for an example of overriding the default bootloader.
Similarly to regular applications, it is possible to include external components, not placed in `bootloader_component`, as part of the bootloader build thanks to the CMake variable ``BOOTLOADER_EXTRA_COMPONENT_DIRS``. It can either refer to a directory that contains several components, either refer to a single component. For example:
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(BOOTLOADER_EXTRA_COMPONENT_DIRS "/path/to/extra/component/")
project(main)
See :example:`custom_bootloader/bootloader_extra_dir` for an example of adding extra components the bootloader build.
.. _config_only_component:

View File

@ -0,0 +1,11 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(BOOTLOADER_EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/extra_bootloader_components/")
project(main)

View File

@ -0,0 +1,56 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
# Bootloader extra component
(See the README.md file in the upper level for more information about bootloader examples.)
The purpose of this example is to show how to add a custom directory that contains a component to the bootloader build.
Registering extra components for the bootloader can be done thanks to the CMake variable `BOOTLOADER_EXTRA_COMPONENT_DIRS`. It works the same way as the application's `EXTRA_COMPONENT_DIRS`, it can either refer to a directory that contains several components, either refer to a single component.
## Usage of this example:
Simply compile it:
```
idf.py build
```
Then flash it and open the monitor with the following command:
```
idf.py flash monitor
```
If everything went well, the bootloader should output the following message:
```
I (60) EXTRA: This function is called from an extra component
```
And finally the application will start and show the message:
```
User application is loaded and running.
```
## Organization of this example
This project contains an application, in the `main` directory that represents an application. It also contains a `bootloader_components` that contains a component compiled and linked with the bootloader. This `bootloader_components` can contain several components, each of them would be in a different directory.
The directory `extra_bootloader_components/extra_component/` contains a component that is meant to be included in the bootloader build. To do so, the variable `BOOTLOADER_EXTRA_COMPONENT_DIRS` is set from the `CMakeLists.txt` file.
Below is a short explanation of files in the project folder.
```
├── CMakeLists.txt Defines the `BOOTLOADER_EXTRA_COMPONENT_DIRS` variable
├── main
│   ├── CMakeLists.txt
│   └── main.c User application
├── bootloader_components
│   └── my_boot_hooks
│   ├── CMakeLists.txt
│   └── hooks.c Implementation of the hooks to execute on boot
├── extra_bootloader_components
│   └── extra_component
│   ├── CMakeLists.txt
│   └── extra_component.c Implementation of the extra component
└── README.md This is the file you are currently reading
```

View File

@ -0,0 +1,9 @@
idf_component_register(SRCS "hooks.c"
REQUIRES extra_component)
# We need to force GCC to integrate this static library into the
# bootloader link. Indeed, by default, as the hooks in the bootloader are weak,
# the linker would just ignore the symbols in the extra. (i.e. not strictly
# required)
# To do so, we need to define the symbol (function) `bootloader_hooks_include`
# within hooks.c source file.

View File

@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
extern void bootloader_extra_dir_function(void);
/* Function used to tell the linker to include this file
* with all its symbols.
*/
void bootloader_hooks_include(void){
}
void bootloader_after_init(void) {
bootloader_extra_dir_function();
}

View File

@ -0,0 +1 @@
idf_component_register(SRCS "extra_component.c")

View File

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "esp_log.h"
void bootloader_extra_dir_function(void)
{
ESP_LOGI("EXTRA", "This function is called from an extra component");
}

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "bootloader_hooks_example_main.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
void app_main(void)
{
printf("User application is loaded and running.\n");
}

View File

@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
def test_custom_bootloader_extra_component(dut: Dut) -> None:
dut.expect_exact('This function is called from an extra component')

View File

@ -5,7 +5,8 @@ set -uo pipefail
# Examples shouldn't use EXTRA_COMPONENT_DIRS, instead the dependencies should be specified in idf_component.yml files
output=$(find ${IDF_PATH}/examples -name "CMakeLists.txt" -not -path "**/managed_components/**" -not -path "**/build/**")
files=$(egrep "EXTRA_COMPONENT_DIRS" ${output} | cut -d ":" -f 1)
# Make sure the regex doesn't match the text `BOOTLOADER_EXTRA_COMPONENT_DIRS`
files=$(egrep "[^A-Za-Z0-9_]EXTRA_COMPONENT_DIRS" ${output} | cut -d ":" -f 1)
found_issues=0
for file in ${files}
do