Merge branch 'feat/cmakev2_bootloader' into 'master'

feat(cmakev2): build bootloader using the cmakev2 build system

Closes IDF-15433

See merge request espressif/esp-idf!46465
This commit is contained in:
Frantisek Hrbata
2026-04-01 10:29:05 +02:00
13 changed files with 530 additions and 44 deletions
+1 -1
View File
@@ -122,7 +122,6 @@ idf_build_get_property(extra_cmake_args EXTRA_CMAKE_ARGS)
# BOOTLOADER_EXTRA_COMPONENT_DIRS may have been set by the `main` component, do not overwrite it
idf_build_get_property(bootloader_extra_component_dirs BOOTLOADER_EXTRA_COMPONENT_DIRS)
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}")
@@ -139,6 +138,7 @@ externalproject_add(bootloader
-DEXTRA_COMPONENT_DIRS=${bootloader_extra_component_dirs}
-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
-DIGNORE_EXTRA_COMPONENT=${BOOTLOADER_IGNORE_EXTRA_COMPONENT}
-DIDF_BUILD_V2=${IDF_BUILD_V2}
${sign_key_arg} ${ver_key_arg}
${extra_cmake_args}
INSTALL_COMMAND ""
@@ -15,6 +15,11 @@ if(NOT IDF_TARGET)
"in by the parent build process.")
endif()
if(IDF_BUILD_V2)
include(CMakeLists_v2.txt)
return()
endif()
# A number of these components are implemented as config-only when built in the bootloader
set(COMPONENTS
bootloader
@@ -0,0 +1,366 @@
cmake_minimum_required(VERSION 3.22)
# ---------------------------------------------------------------------------
# Bootloader subproject CMakeLists (cmakev2 build system)
#
# This file drives the build of the ESP-IDF second-stage bootloader as a
# standalone CMake sub-project that is invoked by the top-level build when
# the project links against the `bootloader` component.
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# Extra component directories
#
# Users may supply custom bootloader components by placing them inside a
# `bootloader_components/` directory at the root of their application
# project. If the directory exists it is appended to EXTRA_COMPONENT_DIRS
# so that the IDF component discovery logic can find them.
#
# IGNORE_EXTRA_COMPONENT (list) optional variable that names individual
# sub-directories of `bootloader_components/` to *exclude* from the build.
# Each entry is turned into an absolute path and collected in
# EXTRA_COMPONENT_EXCLUDE_DIRS which is consumed by the component resolver.
# ---------------------------------------------------------------------------
set(PROJECT_EXTRA_COMPONENTS "${PROJECT_SOURCE_DIR}/bootloader_components")
if(EXISTS ${PROJECT_EXTRA_COMPONENTS})
list(APPEND EXTRA_COMPONENT_DIRS "${PROJECT_EXTRA_COMPONENTS}")
endif()
if(IGNORE_EXTRA_COMPONENT)
# Prefix all entries of the list with ${PROJECT_EXTRA_COMPONENTS} absolute path
list(TRANSFORM IGNORE_EXTRA_COMPONENT
PREPEND "${PROJECT_EXTRA_COMPONENTS}/"
OUTPUT_VARIABLE EXTRA_COMPONENT_EXCLUDE_DIRS)
endif()
# ---------------------------------------------------------------------------
# Include the cmakev2 IDF build framework
# ---------------------------------------------------------------------------
include("${IDF_PATH}/tools/cmakev2/idf.cmake")
project(bootloader C CXX ASM)
# ---------------------------------------------------------------------------
# Bootloader-specific build properties set before project initialization
# ---------------------------------------------------------------------------
set(BOOTLOADER_BUILD 1)
set(NON_OS_BUILD 1)
idf_build_set_property(BOOTLOADER_BUILD "${BOOTLOADER_BUILD}")
idf_build_set_property(NON_OS_BUILD "${NON_OS_BUILD}")
# The bootloader subproject has a different set of components and hence
# different Kconfig files. Do not regenerate the main project's sdkconfig.
idf_build_set_property(GENERATE_SDKCONFIG 0)
# Treat the bootloader subproject's own components (main/, components/) as
# IDF components (priority 0) instead of the default project components
# (priority 3). The bootloader's built-in components are provided by ESP-IDF
# and should be overridable by user-supplied components placed in the
# application's bootloader_components/ directory, which are discovered through
# EXTRA_COMPONENT_DIRS (priority 2). The cmakev1 build system allowed this
# override because it used a last-one-wins strategy. In cmakev2 with strict
# priority-based resolution, project_components would always win and prevent
# the override, so we downgrade them to idf_components priority.
idf_build_set_property(PROJECT_COMPONENTS_SOURCE "idf_components")
# Allow lazy optional component requirements evaluation for
# `idf_component_optional_requires`. The bootloader uses a single ESP-IDF
# library, and since it includes `esp_common`, this ensures that not all
# components listed in `esp_common` as optional requirements are pulled into
# the build.
idf_build_set_property(IDF_COMPONENT_OPTIONAL_REQUIRES_MODE DEFERRED)
# The bootloader uses its own compiler optimization flags
# (CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_*) set below, not the app-level
# CONFIG_COMPILER_OPTIMIZATION_* defaults.
idf_build_set_property(SET_COMPILER_OPTIMIZATION NO)
# Perform internal IDF project initialisation
idf_project_init()
# ---------------------------------------------------------------------------
# Common component requirements
# ---------------------------------------------------------------------------
idf_build_get_property(idf_target_arch IDF_TARGET_ARCH)
set(common_req log esp_rom esp_common esp_hw_support esp_libc ${idf_target_arch})
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${common_req}")
# ---------------------------------------------------------------------------
# Compiler options and defines specific for bootloader
# ---------------------------------------------------------------------------
if(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
idf_build_set_property(COMPILE_OPTIONS "-Oz" APPEND)
else()
idf_build_set_property(COMPILE_OPTIONS "-Os" APPEND)
endif()
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
idf_build_set_property(COMPILE_OPTIONS "-freorder-blocks" APPEND)
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
idf_build_set_property(COMPILE_OPTIONS "-mno-target-align" APPEND)
endif()
endif()
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG)
idf_build_set_property(COMPILE_OPTIONS "-Og" APPEND)
if(CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT CONFIG_IDF_TARGET_LINUX)
# Disable shrink-wrapping to reduce binary size
idf_build_set_property(COMPILE_OPTIONS "-fno-shrink-wrap" APPEND)
endif()
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF)
idf_build_set_property(COMPILE_OPTIONS "-O2" APPEND)
endif()
idf_build_set_property(COMPILE_DEFINITIONS "BOOTLOADER_BUILD=1" APPEND)
idf_build_set_property(COMPILE_DEFINITIONS "NON_OS_BUILD=1" APPEND)
idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND)
# ---------------------------------------------------------------------------
# Bootloader Linker script
# ---------------------------------------------------------------------------
set(LD_DEFAULT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/main/ld/${IDF_TARGET}")
if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
idf_build_set_property(BOOTLOADER_LINKER_SCRIPT "${LD_DEFAULT_PATH}/bootloader.rev0_2.ld.in" APPEND)
else()
idf_build_set_property(BOOTLOADER_LINKER_SCRIPT "${LD_DEFAULT_PATH}/bootloader.ld.in" APPEND)
endif()
# ---------------------------------------------------------------------------
# Build the bootloader ELF
# ---------------------------------------------------------------------------
idf_build_executable(bootloader_elf
NAME bootloader
COMPONENTS main
MAPFILE_TARGET bootloader_mapfile)
# ---------------------------------------------------------------------------
# Binary generation and post-build messages
#
# Collect tool command lists from the esptool_py component so that we can
# assemble human-readable flash / key-management commands for the developer.
# ---------------------------------------------------------------------------
# Build display strings for the post-build message
idf_component_get_property(esptool_py_cmd esptool_py ESPTOOLPY_CMD)
idf_component_get_property(main_args esptool_py FLASH_ARGS)
idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS)
idf_component_get_property(espsecure_py_cmd esptool_py ESPSECUREPY_CMD)
idf_component_get_property(espefuse_py_cmd esptool_py ESPEFUSEPY_CMD)
# String for printing flash command
string(REPLACE ";" " " esptoolpy_write_flash
"${esptool_py_cmd} --port=(PORT) --baud=(BAUD) ${main_args} write-flash ${sub_args}")
string(REPLACE ";" " " espsecurepy "${espsecure_py_cmd}")
string(REPLACE ";" " " espefusepy "${espefuse_py_cmd}")
# ---------------------------------------------------------------------------
# Guard: if binary generation is disabled or esptool_py is not part of the
# build, there is no binary to produce and no flash commands to print, so we
# stop here.
# ---------------------------------------------------------------------------
if(NOT CONFIG_APP_BUILD_GENERATE_BINARIES OR NOT TARGET idf::esptool_py)
# Binaries should not be generated; there's nothing else to do.
return()
# ---------------------------------------------------------------------------
# No secure boot
#
# Convert the ELF directly to a flat binary. The size check target
# (idf_check_bootloader_size) verifies that the binary fits within the
# region reserved for the bootloader in the partition table / flash layout.
# idf_build_generate_metadata emits a JSON metadata file consumed by the
# top-level build and flash tooling.
# ---------------------------------------------------------------------------
elseif(NOT CONFIG_SECURE_BOOT)
# No bootloader signing is required
idf_build_binary(bootloader_elf
OUTPUT_FILE "${CMAKE_BINARY_DIR}/bootloader.bin"
TARGET bootloader_bin
ALL)
idf_check_bootloader_size(bootloader_bin)
idf_build_generate_metadata(EXECUTABLE bootloader_elf)
# ---------------------------------------------------------------------------
# Secure Boot V1
#
# Secure Boot V1 uses a symmetric HMAC-SHA256 key burned into eFuse. Two
# sub-modes are supported:
#
# ONE_TIME_FLASH the bootloader is flashed once and can never be
# replaced on the same device. The developer is shown the exact
# esptool.py command to use for the initial flash.
#
# REFLASHABLE a symmetric key is derived from the private signing key
# and burned into eFuse. Later reflashes are accepted only if the
# bootloader image is bundled with a digest computed using the same
# derived key. This mode requires generating the derived key file
# (secure-bootloader-key-<N>.bin) from the project signing key, and a
# bootloader digest image (bootloader-reflash-digest.bin) that prepends
# the bootloader binary with the matching digest.
# ---------------------------------------------------------------------------
elseif(CONFIG_SECURE_BOOT_V1_ENABLED)
idf_build_binary(bootloader_elf
OUTPUT_FILE "${CMAKE_BINARY_DIR}/bootloader.bin"
TARGET bootloader_bin
ALL)
idf_check_bootloader_size(bootloader_bin)
idf_build_generate_metadata(EXECUTABLE bootloader_elf)
if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
idf_target_post_build_msg(bootloader_bin
"=============================================================================="
"Bootloader built. Secure boot enabled, so bootloader not flashed automatically."
"One-time flash command is:"
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
"* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
)
elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
# Derived key length depends on encoding: 192-bit or 256-bit (default).
if(CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT)
set(key_digest_len 192)
else()
set(key_digest_len 256)
endif()
set(bootloader_digest_bin "${CMAKE_BINARY_DIR}/bootloader-reflash-digest.bin")
set(secure_bootloader_key "${CMAKE_BINARY_DIR}/secure-bootloader-key-${key_digest_len}.bin")
# Derive the symmetric eFuse key from the ECDSA signing key.
# The resulting binary is burned into the SECURE_BOOT_V1 eFuse block.
add_custom_command(OUTPUT "${secure_bootloader_key}"
COMMAND ${espsecure_py_cmd} digest-private-key
--keylen "${key_digest_len}"
--keyfile "${SECURE_BOOT_SIGNING_KEY}"
"${secure_bootloader_key}"
DEPENDS "${SECURE_BOOT_SIGNING_KEY}"
VERBATIM)
if(NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND NOT EXISTS "${secure_bootloader_key}")
idf_die(
"No pre-generated key for a reflashable secure bootloader is available, "
"due to signing configuration."
"\nTo generate one, you can use this command:"
"\n\t${espsecurepy} generate-flash-encryption-key ${secure_bootloader_key}"
"\nIf a signing key is present, then instead use:"
"\n\t${espsecurepy} digest-private-key "
"--keylen (192/256) --keyfile KEYFILE "
"${secure_bootloader_key}")
endif()
# Produce the reflash-digest image: the bootloader binary prefixed
# with a digest computed using the derived symmetric key.
add_custom_command(OUTPUT "${bootloader_digest_bin}"
COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}"
COMMAND ${espsecure_py_cmd} digest-secure-bootloader --keyfile "${secure_bootloader_key}"
-o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin"
DEPENDS "${secure_bootloader_key}" bootloader_bin
VERBATIM)
add_custom_target(bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}")
idf_target_post_build_msg(bootloader_bin
"=============================================================================="
"Bootloader built and secure digest generated."
"Secure boot enabled, so bootloader not flashed automatically."
"Burn secure boot key to efuse using:"
"\t${espefusepy} burn-key secure_boot_v1 ${secure_bootloader_key}"
"First time flash command is:"
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
"=============================================================================="
"To reflash the bootloader after initial flash:"
"\t${esptoolpy_write_flash} 0x0 ${bootloader_digest_bin}"
"=============================================================================="
"* After first boot, only re-flashes of this kind (with same key) will be accepted."
"* Not recommended to reuse the same secure boot keyfile on multiple production devices."
)
endif()
# ---------------------------------------------------------------------------
# Secure Boot V2
#
# Secure Boot V2 uses asymmetric signing. The bootloader ELF is first created
# as an *unsigned* flat binary; then, depending on
# CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES, it is either signed in-place
# (producing bootloader.bin) or left unsigned for the developer to sign
# externally.
#
# Multiple signing keys devices with more than one eFuse key digest slot
# (CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1) may have additional keys
# appended to the signature block after the build; instructions for doing so
# are printed in the post-build message.
#
# CONFIG_SECURE_BOOT_FLASH_BOOTLOADER_DEFAULT when set, the bootloader is
# flashed automatically by the normal flash target and no extra instructions
# are needed, so the post-build message block is skipped.
# ---------------------------------------------------------------------------
elseif(CONFIG_SECURE_BOOT_V2_ENABLED)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# When signing during build, produce the raw binary as
# bootloader-unsigned.bin and then sign it into bootloader.bin.
set(bootloader_unsigned_bin "bootloader-unsigned.bin")
else()
# Without build-time signing, produce the binary directly as
# bootloader.bin (matching v1 behavior). The user is expected
# to sign it externally before flashing.
set(bootloader_unsigned_bin "bootloader.bin")
endif()
idf_build_binary(bootloader_elf
OUTPUT_FILE "${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
TARGET bootloader_unsigned_bin
ALL)
idf_check_bootloader_size(bootloader_unsigned_bin)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
if(NOT EXISTS "${SECURE_BOOT_SIGNING_KEY}")
idf_die(
"Secure Boot Signing Key Not found."
"\nGenerate the Secure Boot V2 RSA-PSS 3072 Key."
"\nTo generate one, you can use this command:"
"\n\t${espsecurepy} generate-signing-key --version 2 your_key.pem"
)
endif()
# Sign the unsigned binary with the configured signing key and
# write the signed image to bootloader.bin.
idf_sign_binary(bootloader_unsigned_bin
OUTPUT_FILE "${CMAKE_BINARY_DIR}/bootloader.bin"
TARGET bootloader_signed_bin
KEYFILE "${SECURE_BOOT_SIGNING_KEY}"
ALL)
idf_check_bootloader_size(bootloader_signed_bin)
set(post_build_target bootloader_signed_bin)
else()
# Signing will be performed externally; communicate this to the user.
set(post_build_target bootloader_unsigned_bin)
idf_target_post_build_msg(bootloader_unsigned_bin
"Bootloader generated but not signed"
)
endif()
# Emit post-build flash instructions. The message varies depending on
# whether the device has multiple eFuse key digest slots and whether the
# bootloader is flashed by default.
if(CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS GREATER 1
AND NOT CONFIG_SECURE_BOOT_FLASH_BOOTLOADER_DEFAULT)
idf_target_post_build_msg(${post_build_target}
"=============================================================================="
"Bootloader built. Secure boot enabled, so bootloader not flashed automatically."
"To sign the bootloader with additional private keys."
"\t${espsecurepy} sign-data -k secure_boot_signing_key2.pem -v 2 \
--append-signatures -o signed_bootloader.bin build/bootloader/bootloader.bin"
"Secure boot enabled, so bootloader not flashed automatically."
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
"=============================================================================="
)
elseif(NOT CONFIG_SECURE_BOOT_FLASH_BOOTLOADER_DEFAULT)
idf_target_post_build_msg(${post_build_target}
"=============================================================================="
"Bootloader built. Secure boot enabled, so bootloader not flashed automatically."
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
"=============================================================================="
)
endif()
idf_build_generate_metadata(EXECUTABLE bootloader_elf)
endif()
@@ -70,6 +70,7 @@ if(CONFIG_ESP_ROM_REV0_HAS_NO_ECDSA_INTERFACE)
endif()
if(BOOTLOADER_BUILD OR CONFIG_APP_BUILD_TYPE_RAM)
set(priv_include_dirs)
set(include_dirs "include" "bootloader_flash/include"
"private_include")
# micro-ecc is only needed for secure boot sources built under BOOTLOADER_BUILD.
-2
View File
@@ -10,7 +10,6 @@ if(BOOTLOADER_BUILD)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS ${private_include_dirs}
REQUIRES ${reqs}
PRIV_REQUIRES ${priv_reqs})
@@ -22,7 +21,6 @@ elseif(esp_tee_build)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS ${private_include_dirs}
REQUIRES ${reqs}
PRIV_REQUIRES ${priv_reqs})
+9 -7
View File
@@ -24,14 +24,16 @@ else()
"patches/esp_rom_efuse.c"
"patches/esp_rom_gpio.c")
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_TLSF_CHECK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_tlsf.c")
endif()
if(NOT BOOTLOADER_BUILD)
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_TLSF_CHECK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_tlsf.c")
endif()
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_multi_heap.c")
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_multi_heap.c")
endif()
endif()
list(APPEND private_required_comp soc hal esp_hal_uart)
+58 -8
View File
@@ -913,7 +913,8 @@ endfunction()
idf_build_binary(<executable>
TARGET <target>
OUTPUT_FILE <file>)
OUTPUT_FILE <file>
[ALL])
*executable[in]*
@@ -928,6 +929,10 @@ endfunction()
Output file path for storing the binary image file.
*ALL[in,opt]*
If specified, the target will be added to the default build target.
Create a binary image for the specified ``executable`` target and save it
in the file specified with the ``OUTPUT_FILE`` option. A custom target
named ``TARGET`` will be created for the generated binary image. The path
@@ -936,7 +941,7 @@ endfunction()
the ``TARGET``.
#]]
function(idf_build_binary executable)
set(options)
set(options ALL)
set(one_value OUTPUT_FILE TARGET)
set(multi_value)
cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN})
@@ -990,8 +995,13 @@ function(idf_build_binary executable)
COMMENT "Generating binary image '${binary_name}' from executable '${executable_name}'"
)
# Create a custom target to generate the binary file
add_custom_target(${ARG_TARGET} DEPENDS "${ARG_OUTPUT_FILE}")
# Create a custom target to generate the binary file.
# If ALL is specified, include the target in the default build.
set(all_arg)
if(ARG_ALL)
set(all_arg ALL)
endif()
add_custom_target(${ARG_TARGET} ${all_arg} DEPENDS "${ARG_OUTPUT_FILE}")
# Store the path of the binary file in the BINARY_PATH property of the
# custom binary target, which is used by the idf_flash_binary.
@@ -1010,7 +1020,8 @@ endfunction()
idf_sign_binary(<binary>
TARGET <target>
OUTPUT_FILE <file>
[KEYFILE <file>])
[KEYFILE <file>]
[ALL])
*binary[in]*
@@ -1033,6 +1044,10 @@ endfunction()
provided, the key file specified by the
``CONFIG_SECURE_BOOT_SIGNING_KEY`` configuration option will be used.
*ALL[in,opt]*
If specified, the target will be added to the default build target.
Sign binary image specified by ``binary`` target with ``KEYFILE`` and save
it in the file specified with the `OUTPUT_FILE` option. A custom target
named ``TARGET`` will be created for the signed binary image. The path of
@@ -1041,7 +1056,7 @@ endfunction()
``TARGET``.
#]]
function(idf_sign_binary binary)
set(options)
set(options ALL)
set(one_value OUTPUT_FILE TARGET KEYFILE)
set(multi_value)
cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN})
@@ -1067,7 +1082,7 @@ function(idf_sign_binary binary)
endif()
if(ARG_KEYFILE)
set(keyfle "${ARG_KEYFILE}")
set(keyfile "${ARG_KEYFILE}")
else()
idf_build_get_property(project_dir PROJECT_DIR)
get_filename_component(keyfile "${CONFIG_SECURE_BOOT_SIGNING_KEY}" ABSOLUTE BASE_DIR "${project_dir}")
@@ -1097,7 +1112,13 @@ function(idf_sign_binary binary)
VERBATIM
COMMENT "Signing '${binary_name}' with key '${key_name}' into '${signed_binary_name}'"
)
add_custom_target(${ARG_TARGET} DEPENDS "${ARG_OUTPUT_FILE}")
# Create a custom target for the signed binary file.
# If ALL is specified, include the target in the default build.
set(all_arg)
if(ARG_ALL)
set(all_arg ALL)
endif()
add_custom_target(${ARG_TARGET} ${all_arg} DEPENDS "${ARG_OUTPUT_FILE}")
# Store the path of the binary file in the BINARY_PATH property of the
# custom signed binary target, which is used by the idf_flash_binary.
@@ -1227,6 +1248,35 @@ function(idf_check_binary_size binary)
add_dependencies("${binary}" "${binary}_check_size")
endfunction()
#[[
.. cmakev2:function:: idf_check_bootloader_size
.. code-block:: cmake
idf_check_bootloader_size(<binary>)
*binary[in]*
Binary image target to which to add a bootloader size check. The
``binary`` target is created by the :cmakev2:ref:`idf_build_binary` or
:cmakev2:ref:`idf_sign_binary` function.
Ensure that the bootloader binary image does not overlap the partition
table. The file path of the binary image should be stored in the
``BINARY_PATH`` property of the ``binary`` target.
#]]
function(idf_check_bootloader_size binary)
get_target_property(binary_path ${binary} BINARY_PATH)
if(NOT binary_path)
idf_die("Binary target '${binary}' is missing 'BINARY_PATH' property.")
endif()
partition_table_add_check_bootloader_size_target("${binary}_check_size"
DEPENDS "${binary_path}"
BOOTLOADER_BINARY_PATH "${binary_path}")
add_dependencies("${binary}" "${binary}_check_size")
endfunction()
#[[
.. cmakev2:function:: idf_check_binary_signed
+5 -1
View File
@@ -419,10 +419,14 @@ function(__init_common_components)
idf_build_get_property(idf_target IDF_TARGET)
idf_build_get_property(idf_target_arch IDF_TARGET_ARCH)
idf_build_get_property(explicit_requires_common __COMPONENT_REQUIRES_COMMON)
# Define common components that are included as dependencies for each
# component.
if("${idf_target}" STREQUAL "linux")
if(explicit_requires_common)
set(requires_common "${explicit_requires_common}")
elseif("${idf_target}" STREQUAL "linux")
set(requires_common freertos esp_hw_support heap log soc hal esp_rom esp_common esp_system linux
esp_stdio)
else()
+4
View File
@@ -963,13 +963,17 @@ function(idf_component_include name)
idf_die("Unsupported target type '${component_real_target_type}' in component '${component_name}'")
endif()
idf_component_get_property(component_dir "${component_name}" COMPONENT_DIR)
idf_component_get_property(embed_files "${component_name}" EMBED_FILES)
foreach(file IN LISTS embed_files)
get_filename_component(file "${file}" ABSOLUTE BASE_DIR "${component_dir}")
target_add_binary_data(${COMPONENT_TARGET} "${file}" "BINARY")
endforeach()
idf_component_get_property(embed_txtfiles "${component_name}" EMBED_TXTFILES)
foreach(file IN LISTS embed_txtfiles)
get_filename_component(file "${file}" ABSOLUTE BASE_DIR "${component_dir}")
target_add_binary_data(${COMPONENT_TARGET} "${file}" "TEXT")
endforeach()
+23 -1
View File
@@ -362,12 +362,34 @@ endfunction()
EXTRA_COMPONENT_EXCLUDE_DIRS
List of paths to exclude from searching the component directories.
The ``PROJECT_COMPONENTS_SOURCE`` build property controls how the
project's own components are categorised -- i.e. those discovered
under ``CMAKE_CURRENT_SOURCE_DIR/main``,
``CMAKE_CURRENT_SOURCE_DIR/components``, or the paths listed in
``COMPONENT_DIRS``. It defaults to ``project_components``
(priority 3 -- highest). Setting it to ``idf_components``
(priority 0) makes them overridable by components supplied through
``EXTRA_COMPONENT_DIRS`` (priority 2). This is useful for
sub-projects whose built-in components are provided by ESP-IDF and
should be overridable by user-supplied components.
Each component is initialized for every component directory found.
#]]
function(__init_components)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(prefix PREFIX)
idf_build_get_property(project_components_source PROJECT_COMPONENTS_SOURCE)
if(NOT project_components_source)
set(project_components_source "project_components")
endif()
set(valid_sources "project_components" "idf_components")
if(NOT project_components_source IN_LIST valid_sources)
idf_die("Invalid PROJECT_COMPONENTS_SOURCE '${project_components_source}'."
" Must be one of: ${valid_sources}")
endif()
__get_component_paths(PATHS "${idf_path}/components"
OUTPUT idf_components)
if(COMPONENT_DIRS)
@@ -404,7 +426,7 @@ function(__init_components)
foreach(path IN LISTS project_components)
__init_component(DIRECTORY "${path}"
PREFIX "${prefix}"
SOURCE "project_components")
SOURCE "${project_components_source}")
endforeach()
foreach(path IN LISTS project_extra_components)
+6 -1
View File
@@ -57,6 +57,7 @@ function(__init_kconfig)
idf_build_set_property(SDKCONFIG "${sdkconfig}")
idf_build_set_property(__SDKCONFIG_ORIG "${sdkconfig}")
idf_build_set_property(SDKCONFIG_DEFAULTS "${sdkconfig_defaults_checked}")
idf_build_set_property(GENERATE_SDKCONFIG 1)
# Setup ESP-IDF root Kconfig and sdkconfig.rename files.
idf_build_set_property(__ROOT_KCONFIG "${idf_path}/Kconfig")
@@ -643,9 +644,13 @@ function(__generate_kconfig_outputs)
--output header "${sdkconfig_header}"
--output cmake "${sdkconfig_cmake}"
--output json "${sdkconfig_json}"
--output config "${sdkconfig}"
)
idf_build_get_property(generate_sdkconfig GENERATE_SDKCONFIG)
if(generate_sdkconfig)
list(APPEND kconfgen_outputs_cmd --output config "${sdkconfig}")
endif()
idf_build_set_property(__KCONFGEN_OUTPUTS_CMD "${kconfgen_outputs_cmd}")
# Generate Kconfig outputs using kconfgen
+26 -17
View File
@@ -84,6 +84,7 @@ function(__init_project_configuration)
set(link_options)
idf_build_get_property(idf_ver IDF_VER)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(idf_target IDF_TARGET)
idf_build_get_property(component_interfaces COMPONENT_INTERFACES)
idf_build_get_property(build_dir BUILD_DIR)
@@ -186,24 +187,32 @@ function(__init_project_configuration)
list(APPEND cxx_compile_options "-std=gnu++26")
endif()
if(CONFIG_COMPILER_OPTIMIZATION_SIZE)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
list(APPEND compile_options "-Oz")
else()
list(APPEND compile_options "-Os")
# Subprojects that handle their own compiler optimization flags can set the
# SET_COMPILER_OPTIMIZATION build property to NO before idf_project_init().
idf_build_get_property(set_compiler_optimization SET_COMPILER_OPTIMIZATION)
if(NOT set_compiler_optimization)
set(set_compiler_optimization YES)
endif()
if(set_compiler_optimization)
if(CONFIG_COMPILER_OPTIMIZATION_SIZE)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
list(APPEND compile_options "-Oz")
else()
list(APPEND compile_options "-Os")
endif()
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
list(APPEND compile_options "-freorder-blocks")
endif()
elseif(CONFIG_COMPILER_OPTIMIZATION_DEBUG)
list(APPEND compile_options "-Og")
if(CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT CONFIG_IDF_TARGET_LINUX)
list(APPEND compile_options "-fno-shrink-wrap") # Disable shrink-wrapping to reduce binary size
endif()
elseif(CONFIG_COMPILER_OPTIMIZATION_NONE)
list(APPEND compile_options "-O0")
elseif(CONFIG_COMPILER_OPTIMIZATION_PERF)
list(APPEND compile_options "-O2")
endif()
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
list(APPEND compile_options "-freorder-blocks")
endif()
elseif(CONFIG_COMPILER_OPTIMIZATION_DEBUG)
list(APPEND compile_options "-Og")
if(CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT CONFIG_IDF_TARGET_LINUX)
list(APPEND compile_options "-fno-shrink-wrap") # Disable shrink-wrapping to reduce binary size
endif()
elseif(CONFIG_COMPILER_OPTIMIZATION_NONE)
list(APPEND compile_options "-O0")
elseif(CONFIG_COMPILER_OPTIMIZATION_PERF)
list(APPEND compile_options "-O2")
endif()
if(CONFIG_COMPILER_CXX_EXCEPTIONS)
+26 -6
View File
@@ -683,6 +683,31 @@ function(add_prefix var prefix)
set(${var} "${newlist}" PARENT_SCOPE)
endfunction()
#[[
idf_target_post_build_msg(<target> <line>...)
*target[in]*
Target to attach the post-build message to.
*line[in]*
Message lines to print after the target is built.
Add a post-build step to ``<target>`` that prints the given message lines.
The lines are joined with newlines, written to a file at configure time,
and printed at build time using a single ``cmake -E cat`` command.
#]]
function(idf_target_post_build_msg target)
string(MD5 hash "${ARGN}")
set(msg_file "${CMAKE_CURRENT_BINARY_DIR}/_post_build_msg_${target}_${hash}.txt")
list(JOIN ARGN "\n" msg)
file(WRITE "${msg_file}" "${msg}\n")
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E cat "${msg_file}"
VERBATIM)
endfunction()
#[[
fail_target(<target> <line0> [<line>...])
@@ -812,12 +837,7 @@ function(target_add_binary_data target embed_file embed_type)
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(idf_path IDF_PATH)
# The target_add_binary_data function is also called within the
# idf_component_include function, which is not executed in the component
# directory context. Therefore, ensure that the absolute path of the
# embedded file is resolved relative to the component directory.
idf_component_get_property(component_directory "${target}" COMPONENT_DIR)
get_filename_component(embed_file "${embed_file}" ABSOLUTE BASE_DIR "${component_directory}")
get_filename_component(embed_file "${embed_file}" ABSOLUTE)
get_filename_component(name "${embed_file}" NAME)
set(embed_srcfile "${build_dir}/${name}.S")