refactor(esptool_py): Move binary generation to project level and add utility functions

This commit refactors the esptool_py component to provide utility
functions for binary file generation targets instead of creating the
targets. Binary generation targets are now moved to the respective
projects.

The following changes were done in this commit:
- Added __idf_build_binary() function to esptool_py to create the binary
  file generation target.
- Added __idf_build_secure_binary() as the secure boot equivalent of the
  above function.
- Top level project build now creates its own binary targets in
  idf_build_executable() in build.cmake.
- Bootloader and esp_tee subprojects create their binary file generation
  targets in their respective CMakeLists.txt files.
- All post-build targets such as the app_size_check target are now
  created by the respective projects and not esptool_py.
- General clean-up of the esptool_py cmake files.
This commit is contained in:
Sudeep Mohanty
2025-07-02 10:25:48 +02:00
parent ef4d6462e2
commit 7c75795a0b
5 changed files with 322 additions and 180 deletions

View File

@@ -75,16 +75,36 @@ 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_DEFINITIONS "NON_OS_BUILD=1" APPEND)
idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND) idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND)
# Set up the bootloader binary generation targets
set(PROJECT_BIN "bootloader.bin")
if(CONFIG_SECURE_BOOT_V2_ENABLED AND CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
set(bootloader_unsigned_bin "bootloader-unsigned.bin")
else()
set(bootloader_unsigned_bin "${PROJECT_BIN}")
endif()
# Set the final binary name as a project property
idf_build_set_property(PROJECT_BIN "${PROJECT_BIN}")
# Generate the unsigned binary from the ELF file.
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
set(target_name "gen_bootloader_binary")
__idf_build_binary("${bootloader_unsigned_bin}" "${target_name}")
endif()
idf_component_get_property(main_args esptool_py FLASH_ARGS) 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(sub_args esptool_py FLASH_SUB_ARGS)
idf_component_get_property(esptool_py_cmd esptool_py ESPTOOLPY_CMD)
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 for printing flash command
string(REPLACE ";" " " esptoolpy_write_flash string(REPLACE ";" " " esptoolpy_write_flash
"${ESPTOOLPY} --port=(PORT) --baud=(BAUD) ${main_args} " "${esptool_py_cmd} --port=(PORT) --baud=(BAUD) ${main_args} "
"write_flash ${sub_args}") "write_flash ${sub_args}")
string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") string(REPLACE ";" " " espsecurepy "${espsecure_py_cmd}")
string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}") string(REPLACE ";" " " espefusepy "${espefuse_py_cmd}")
# Suppress warning: "Manually-specified variables were not used by the project: SECURE_BOOT_SIGNING_KEY" # Suppress warning: "Manually-specified variables were not used by the project: SECURE_BOOT_SIGNING_KEY"
set(ignore_signing_key "${SECURE_BOOT_SIGNING_KEY}") set(ignore_signing_key "${SECURE_BOOT_SIGNING_KEY}")
@@ -105,7 +125,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
add_custom_command(OUTPUT "${secure_bootloader_key}" add_custom_command(OUTPUT "${secure_bootloader_key}"
COMMAND ${ESPSECUREPY} digest_private_key COMMAND ${espsecure_py_cmd} digest_private_key
--keylen "${key_digest_len}" --keylen "${key_digest_len}"
--keyfile "${SECURE_BOOT_SIGNING_KEY}" --keyfile "${SECURE_BOOT_SIGNING_KEY}"
"${secure_bootloader_key}" "${secure_bootloader_key}"
@@ -130,7 +150,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
add_custom_command(OUTPUT "${bootloader_digest_bin}" add_custom_command(OUTPUT "${bootloader_digest_bin}"
COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}" COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}"
COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}" COMMAND ${espsecure_py_cmd} digest_secure_bootloader --keyfile "${secure_bootloader_key}"
-o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin" -o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin"
MAIN_DEPENDENCY "${CMAKE_BINARY_DIR}/.bin_timestamp" MAIN_DEPENDENCY "${CMAKE_BINARY_DIR}/.bin_timestamp"
DEPENDS gen_secure_bootloader_key gen_project_binary DEPENDS gen_secure_bootloader_key gen_project_binary
@@ -139,39 +159,34 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
add_custom_target(gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}") add_custom_target(gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}")
endif() endif()
# If secure boot is enabled, generate the signed binary from the unsigned one.
if(CONFIG_SECURE_BOOT_V2_ENABLED) if(CONFIG_SECURE_BOOT_V2_ENABLED)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) set(target_name "gen_signed_bootloader")
get_filename_component(secure_boot_signing_key
"${SECURE_BOOT_SIGNING_KEY}" ABSOLUTE BASE_DIR "${project_dir}")
if(NOT EXISTS "${secure_boot_signing_key}") if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
message(FATAL_ERROR # The SECURE_BOOT_SIGNING_KEY is passed in from the parent build and
"Secure Boot Signing Key Not found." # is already an absolute path.
"\nGenerate the Secure Boot V2 RSA-PSS 3072 Key." if(NOT EXISTS "${SECURE_BOOT_SIGNING_KEY}")
"\nTo generate one, you can use this command:" message(FATAL_ERROR
"\n\t${espsecurepy} generate_signing_key --version 2 ${SECURE_BOOT_SIGNING_KEY}") "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() endif()
set(bootloader_unsigned_bin "bootloader-unsigned.bin") set(comment "Generated the signed Bootloader")
add_custom_command(OUTPUT ".signed_bin_timestamp" set(key_arg KEYFILE "${SECURE_BOOT_SIGNING_KEY}")
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/${PROJECT_BIN}"
"${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
COMMAND ${ESPSECUREPY} sign_data --version 2 --keyfile "${secure_boot_signing_key}"
-o "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" "${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}"
"from ${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${CMAKE_BINARY_DIR}/${PROJECT_BIN}"
> "${CMAKE_BINARY_DIR}/.signed_bin_timestamp"
DEPENDS "${build_dir}/.bin_timestamp"
VERBATIM
COMMENT "Generated the signed Bootloader")
else() else()
add_custom_command(OUTPUT ".signed_bin_timestamp" # If we are not building signed binaries, we don't pass a key.
VERBATIM set(comment "Bootloader generated but not signed")
COMMENT "Bootloader generated but not signed") set(key_arg "")
endif() endif()
add_custom_target(gen_signed_bootloader ALL DEPENDS "${build_dir}/.signed_bin_timestamp") __idf_build_secure_binary("${bootloader_unsigned_bin}" "${PROJECT_BIN}" "${target_name}"
COMMENT "${comment}"
${key_arg}
)
endif() endif()
if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
@@ -255,3 +270,19 @@ elseif(CONFIG_SECURE_BOOT_V2_ENABLED AND NOT CONFIG_SECURE_BOOT_FLASH_BOOTLOADER
DEPENDS gen_signed_bootloader DEPENDS gen_signed_bootloader
VERBATIM) VERBATIM)
endif() endif()
# Generate bootloader post-build check of the bootloader size against the offset
partition_table_add_check_bootloader_size_target(bootloader_check_size
DEPENDS gen_project_binary
BOOTLOADER_BINARY_PATH "${CMAKE_BINARY_DIR}/${PROJECT_BIN}"
RESULT bootloader_check_size_command)
add_dependencies(app bootloader_check_size)
if(CONFIG_SECURE_BOOT_V2_ENABLED AND CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# Check the size of the bootloader + signature block.
partition_table_add_check_bootloader_size_target(bootloader_check_size_signed
DEPENDS gen_signed_bootloader
BOOTLOADER_BINARY_PATH "${CMAKE_BINARY_DIR}/${PROJECT_BIN}"
RESULT bootloader_check_size_signed_command)
add_dependencies(app bootloader_check_size_signed)
endif()

View File

@@ -51,37 +51,51 @@ idf_build_set_property(COMPILE_DEFINITIONS "ESP_TEE_BUILD=1" APPEND)
idf_build_set_property(COMPILE_DEFINITIONS "NON_OS_BUILD=1" APPEND) idf_build_set_property(COMPILE_DEFINITIONS "NON_OS_BUILD=1" APPEND)
idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND) idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND)
if(CONFIG_SECURE_BOOT_V2_ENABLED) # Set up the TEE binary generation targets
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) set(project_bin "esp_tee.bin")
get_filename_component(secure_boot_signing_key if(CONFIG_SECURE_BOOT_V2_ENABLED AND CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
"${SECURE_BOOT_SIGNING_KEY}" ABSOLUTE BASE_DIR "${project_dir}") set(esp_tee_unsigned_bin "esp_tee-unsigned.bin")
else()
set(esp_tee_unsigned_bin "${project_bin}")
endif()
if(NOT EXISTS "${secure_boot_signing_key}") # Set the final binary name as a project property.
message(FATAL_ERROR idf_build_set_property(PROJECT_BIN "${project_bin}")
"Secure Boot Signing Key Not found."
"\nGenerate the Secure Boot V2 RSA-PSS 3072 Key." # Generate the unsigned binary from the ELF file.
"\nTo generate one, you can use this command:" if(CONFIG_APP_BUILD_GENERATE_BINARIES)
"\n\t${espsecurepy} generate_signing_key --version 2 ${SECURE_BOOT_SIGNING_KEY}") set(target_name "gen_esp_tee_binary")
__idf_build_binary("${esp_tee_unsigned_bin}" "${target_name}")
endif()
idf_component_get_property(espsecure_py_cmd esptool_py ESPSECUREPY_CMD)
# If secure boot is enabled, generate the signed binary from the unsigned one.
if(CONFIG_SECURE_BOOT_V2_ENABLED)
set(target_name "gen_signed_esp_tee_binary")
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# The SECURE_BOOT_SIGNING_KEY is passed in from the parent build and
# is already an absolute path.
if(NOT EXISTS "${SECURE_BOOT_SIGNING_KEY}")
message(FATAL_ERROR
"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${espsecure_py_cmd} generate_signing_key --version 2 your_key.pem"
)
endif() endif()
set(esp_tee_unsigned_bin "esp_tee-unsigned.bin") set(comment "Generated the signed TEE")
add_custom_command(OUTPUT ".signed_bin_timestamp" set(key_arg KEYFILE "${SECURE_BOOT_SIGNING_KEY}")
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/${PROJECT_BIN}"
"${CMAKE_BINARY_DIR}/${esp_tee_unsigned_bin}"
COMMAND ${ESPSECUREPY} sign_data --version 2 --keyfile "${secure_boot_signing_key}"
-o "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" "${CMAKE_BINARY_DIR}/${esp_tee_unsigned_bin}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}"
"from ${CMAKE_BINARY_DIR}/${esp_tee_unsigned_bin}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${CMAKE_BINARY_DIR}/${PROJECT_BIN}"
> "${CMAKE_BINARY_DIR}/.signed_bin_timestamp"
DEPENDS "${build_dir}/.bin_timestamp"
VERBATIM
COMMENT "Generated the signed TEE")
else() else()
add_custom_command(OUTPUT ".signed_bin_timestamp" # If we are not building signed binaries, we don't pass a key.
VERBATIM set(comment "TEE generated but not signed")
COMMENT "TEE generated but not signed") set(key_arg "")
endif() endif()
add_custom_target(gen_signed_esp_tee ALL DEPENDS "${build_dir}/.signed_bin_timestamp") __idf_build_secure_binary("${esp_tee_unsigned_bin}" "${project_bin}" "${target_name}"
COMMENT "${comment}"
${key_arg}
)
endif() endif()

View File

@@ -17,16 +17,6 @@ if(NOT BOOTLOADER_BUILD)
# If anti-rollback option is set then factory partition should not be in Partition Table.
# In this case, should be used the partition table with two ota app without the factory.
partition_table_get_partition_info(factory_offset "--partition-type app --partition-subtype factory" "offset")
partition_table_get_partition_info(test_offset "--partition-type app --partition-subtype test" "offset")
if(CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK AND (factory_offset OR test_offset))
fail_at_build_time(check_table_contents "\
ERROR: Anti-rollback option is enabled. Partition table should \
consist of two ota app without factory or test partitions.")
add_dependencies(app check_table_contents)
endif()
# Generate flasher_args.json for tools that need it. The variables below are used # Generate flasher_args.json for tools that need it. The variables below are used
# in configuring the template flasher_args.json.in. # in configuring the template flasher_args.json.in.
@@ -54,31 +44,5 @@ consist of two ota app without factory or test partitions.")
CONTENT "${flasher_args_content}") CONTENT "${flasher_args_content}")
file_generate("${CMAKE_BINARY_DIR}/flasher_args.json" file_generate("${CMAKE_BINARY_DIR}/flasher_args.json"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in") INPUT "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in")
if(CONFIG_APP_BUILD_TYPE_APP_2NDBOOT)
# Generate app_check_size_command target to check the app size against the partition table parameters
partition_table_add_check_size_target(app_check_size
DEPENDS gen_project_binary
BINARY_PATH "${build_dir}/${PROJECT_BIN}"
PARTITION_TYPE app)
add_dependencies(app app_check_size)
endif()
endif() endif()
endif() # NOT BOOTLOADER_BUILD endif() # NOT BOOTLOADER_BUILD
if(BOOTLOADER_BUILD)
# Generate bootloader post-build check of the bootloader size against the offset
partition_table_add_check_bootloader_size_target(bootloader_check_size
DEPENDS gen_project_binary
BOOTLOADER_BINARY_PATH "${build_dir}/${PROJECT_BIN}"
RESULT bootloader_check_size_command)
add_dependencies(app bootloader_check_size) # note: in the subproject, so the target is 'app'...
if(CONFIG_SECURE_BOOT_V2_ENABLED AND CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# Check the size of the bootloader + signature block.
partition_table_add_check_bootloader_size_target(bootloader_check_size_signed
DEPENDS gen_signed_bootloader
BOOTLOADER_BINARY_PATH "${build_dir}/${PROJECT_BIN}"
RESULT bootloader_check_size_signed_command)
add_dependencies(app bootloader_check_size_signed) # note: in the subproject, so the target is 'app'...
endif()
endif()

View File

@@ -112,79 +112,6 @@ idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(elf_name EXECUTABLE_NAME GENERATOR_EXPRESSION) idf_build_get_property(elf_name EXECUTABLE_NAME GENERATOR_EXPRESSION)
idf_build_get_property(elf EXECUTABLE GENERATOR_EXPRESSION) idf_build_get_property(elf EXECUTABLE GENERATOR_EXPRESSION)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND NOT non_os_build)
set(unsigned_project_binary "${elf_name}-unsigned.bin")
else()
set(unsigned_project_binary "${elf_name}.bin")
endif()
set(PROJECT_BIN "${elf_name}.bin")
#
# Add 'app.bin' target - generates with elf2image
#
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
COMMAND ${ESPTOOLPY} elf2image ${esptool_elf2image_args}
-o "${build_dir}/${unsigned_project_binary}" "$<TARGET_FILE:$<GENEX_EVAL:${elf}>>"
COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp"
DEPENDS "$<TARGET_FILE:$<GENEX_EVAL:${elf}>>"
VERBATIM
WORKING_DIRECTORY ${build_dir}
COMMENT "Generating binary image from built executable"
)
add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
endif()
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_CLEAN_FILES
"${build_dir}/${unsigned_project_binary}"
)
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_target(app ALL DEPENDS gen_project_binary)
endif()
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
set(secure_boot_version "1")
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
set(secure_boot_version "2")
endif()
if(NOT non_os_build AND CONFIG_SECURE_SIGNED_APPS)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# for locally signed secure boot image, add a signing step to get from unsigned app to signed app
get_filename_component(secure_boot_signing_key "${CONFIG_SECURE_BOOT_SIGNING_KEY}"
ABSOLUTE BASE_DIR "${project_dir}")
add_custom_command(OUTPUT "${build_dir}/.signed_bin_timestamp"
COMMAND ${ESPSECUREPY} sign_data --version ${secure_boot_version} --keyfile ${secure_boot_signing_key}
-o "${build_dir}/${PROJECT_BIN}" "${build_dir}/${unsigned_project_binary}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}"
"from ${build_dir}/${unsigned_project_binary}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_bin_timestamp"
DEPENDS "${build_dir}/.bin_timestamp"
VERBATIM
COMMENT "Generating signed binary image"
)
add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_bin_timestamp")
add_dependencies(gen_project_binary gen_signed_project_binary)
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_CLEAN_FILES
"${build_dir}/${PROJECT_BIN}"
)
else()
string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}")
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo
"App built but not signed. Sign app before flashing"
COMMAND ${CMAKE_COMMAND} -E echo
"\t${espsecurepy} sign_data --keyfile KEYFILE --version ${secure_boot_version} \
${build_dir}/${PROJECT_BIN}"
VERBATIM)
endif()
endif()
add_custom_target(erase_flash add_custom_target(erase_flash
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
@@ -781,6 +708,147 @@ function(__ensure_esptool_py_setup)
endfunction() endfunction()
# __idf_build_binary
#
# @brief Sets up the primary target for generating a .bin file from an .elf file.
#
# This function creates the custom command and target required to generate a
# project binary (`.bin`) file from the final `.elf` executable. It uses `esptool.py
# elf2image` to perform the conversion and manages dependencies to ensure the
# binary is regenerated whenever the ELF file changes.
#
# @param[in] OUTPUT_BIN_FILENAME The name of the output binary file to generate.
# @param[in] TARGET_NAME The unique name for the custom target that
# generates the binary.
function(__idf_build_binary OUTPUT_BIN_FILENAME TARGET_NAME)
__ensure_esptool_py_setup()
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(elf EXECUTABLE GENERATOR_EXPRESSION)
idf_component_get_property(esptool_py_cmd esptool_py ESPTOOLPY_CMD)
# Get esptool.py arguments for elf2image target
idf_component_get_property(esptool_elf2image_args esptool_py ESPTOOL_PY_ELF2IMAGE_ARGS)
# Create a custom command and target to generate binary from elf file
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
COMMAND ${esptool_py_cmd} elf2image ${esptool_elf2image_args}
-o "${build_dir}/${OUTPUT_BIN_FILENAME}" "$<TARGET_FILE:$<GENEX_EVAL:${elf}>>"
COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${OUTPUT_BIN_FILENAME}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${OUTPUT_BIN_FILENAME}" > "${build_dir}/.bin_timestamp"
DEPENDS "$<TARGET_FILE:$<GENEX_EVAL:${elf}>>"
VERBATIM
WORKING_DIRECTORY ${build_dir}
COMMENT "Generating binary image from built executable"
)
# Create a custom target to generate the binary file
add_custom_target(${TARGET_NAME} DEPENDS "${build_dir}/.bin_timestamp")
# We need to create a gen_project_binary target for backward compatibility
# since many other components depend on it. Add the new target as a dependency
# to the gen_project_binary target.
if(NOT TARGET gen_project_binary)
add_custom_target(gen_project_binary DEPENDS ${TARGET_NAME})
else()
add_dependencies(gen_project_binary ${TARGET_NAME})
endif()
# Add an 'app' alias that is part of the default build
if(NOT TARGET app)
add_custom_target(app ALL DEPENDS gen_project_binary)
else()
add_dependencies(app gen_project_binary)
endif()
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_CLEAN_FILES
"${build_dir}/${OUTPUT_BIN_FILENAME}"
)
endfunction()
# __idf_build_secure_binary
#
# @brief Sets up targets for generating a signed binary for Secure Boot.
#
# If Secure Boot is enabled, this function adds a custom command to sign the
# previously generated application binary using `espsecure.py`. It creates a
# target that depends on the unsigned binary and produces a signed one, which
# is required for the bootloader to authenticate the application.
#
# @param[in] UNSIGNED_BIN_FILENAME The name of the unsigned input binary file.
# @param[in] SIGNED_BIN_FILENAME The name of the signed output binary file.
# @param[in] TARGET_NAME The unique name for the custom target that
# generates the signed binary.
# @param[in, optional] KEYFILE Path to the keyfile for signing.
# @param[in, optional] COMMENT Custom message to display during build.
function(__idf_build_secure_binary UNSIGNED_BIN_FILENAME SIGNED_BIN_FILENAME TARGET_NAME)
cmake_parse_arguments(arg "" "KEYFILE;COMMENT" "" ${ARGN})
__ensure_esptool_py_setup()
idf_build_get_property(build_dir BUILD_DIR)
idf_component_get_property(espsecure_py_cmd esptool_py ESPSECUREPY_CMD)
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
set(secure_boot_version "1")
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
set(secure_boot_version "2")
endif()
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
if(arg_KEYFILE)
# If a keyfile is provided, use it for signing.
set(secure_boot_signing_key "${arg_KEYFILE}")
else()
# for locally signed secure boot image, add a signing step to get from unsigned app to signed app
idf_build_get_property(project_dir PROJECT_DIR)
get_filename_component(secure_boot_signing_key "${CONFIG_SECURE_BOOT_SIGNING_KEY}"
ABSOLUTE BASE_DIR "${project_dir}")
endif()
if(arg_COMMENT)
set(comment_text "${arg_COMMENT}")
else()
set(comment_text "Generating signed binary image")
endif()
add_custom_command(OUTPUT "${build_dir}/.signed_bin_timestamp"
COMMAND ${espsecure_py_cmd} sign_data
--version ${secure_boot_version} --keyfile "${secure_boot_signing_key}"
-o "${build_dir}/${SIGNED_BIN_FILENAME}" "${build_dir}/${UNSIGNED_BIN_FILENAME}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${SIGNED_BIN_FILENAME}"
"from ${build_dir}/${UNSIGNED_BIN_FILENAME}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${SIGNED_BIN_FILENAME}"
> "${build_dir}/.signed_bin_timestamp"
DEPENDS "${build_dir}/.bin_timestamp"
VERBATIM
COMMENT "${comment_text}"
)
add_custom_target(${TARGET_NAME} DEPENDS "${build_dir}/.signed_bin_timestamp")
# Add the new target as a dependency to the gen_project_binary target.
if(NOT TARGET gen_project_binary)
add_custom_target(gen_project_binary DEPENDS ${TARGET_NAME})
else()
add_dependencies(gen_project_binary ${TARGET_NAME})
endif()
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_CLEAN_FILES
"${build_dir}/${SIGNED_BIN_FILENAME}"
)
else()
string(REPLACE ";" " " espsecurepy "${espsecure_py_cmd}")
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo
"App built but not signed. Sign app before flashing"
COMMAND ${CMAKE_COMMAND} -E echo
"\t${espsecurepy} sign_data --keyfile KEYFILE --version ${secure_boot_version} \
${build_dir}/${UNSIGNED_BIN_FILENAME}"
VERBATIM)
endif()
endfunction()
# __esptool_py_setup_main_flash_target # __esptool_py_setup_main_flash_target
# #
# @brief Sets up the main `flash` target and its dependencies. # @brief Sets up the main `flash` target and its dependencies.

View File

@@ -783,9 +783,51 @@ function(idf_build_executable elf)
idf_build_get_property(esp_tee_build ESP_TEE_BUILD) idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
idf_build_get_property(target IDF_TARGET) idf_build_get_property(target IDF_TARGET)
if(NOT bootloader_build AND NOT esp_tee_build AND NOT "${target}" STREQUAL "linux") # This is the main orchestrator for generating binaries and flash targets
# Check if esptool_py component is available before calling its functions # It is responsible for -
if(TARGET idf::esptool_py) # - Setting up the binary generation targets
# - Setting up the signed binary generation targets
# - Setting up the main 'flash' target
# - Setting up the app-flash and flash targets
# - Setting up the app_check_size target
#
# Note: We need to wrap this code in a if(NOT BOOTLOADER_BUILD AND NOT ESP_TEE_BUILD) block
# because the bootloader and esp_tee subprojects also call our overridden project()
# macro.
#
# Note: We need to have this block here instead of in project.cmake because
# idf_build_executable() is called directly when ESP-IDF is compiled
# as a library (idf_as_lib).
if(NOT bootloader_build AND NOT esp_tee_build)
# All of the following logic for generating binaries and flash targets
# depends on the esptool_py component. For some builds (such as those
# that are built for the linux target), this component may not be included.
# We must guard these calls to ensure they only run when esptool_py is part
# of the build. We also only do this if CONFIG_APP_BUILD_GENERATE_BINARIES is set.
if(TARGET idf::esptool_py AND CONFIG_APP_BUILD_GENERATE_BINARIES)
# Determine the output filename for the binary.
idf_build_get_property(elf_name EXECUTABLE_NAME GENERATOR_EXPRESSION)
idf_build_get_property(non_os_build NON_OS_BUILD)
set(project_bin "${elf_name}.bin")
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND NOT non_os_build)
set(project_bin_unsigned "${elf_name}-unsigned.bin")
else()
set(project_bin_unsigned "${project_bin}")
endif()
idf_build_set_property(PROJECT_BIN "${project_bin}")
# Create the binary file generation target for the main project
set(target_name "gen_${CMAKE_PROJECT_NAME}_binary")
__idf_build_binary("${project_bin_unsigned}" "${target_name}")
# Generate the signed binary file generation target for the main project
if(NOT non_os_build AND CONFIG_SECURE_SIGNED_APPS)
set(signed_target_name "gen_signed_${CMAKE_PROJECT_NAME}_binary")
__idf_build_secure_binary("${project_bin_unsigned}" "${project_bin}" "${signed_target_name}")
endif()
# The following block is placed here to ensure that the application binary is added to the 'flash' # The following block is placed here to ensure that the application binary is added to the 'flash'
# target's properties *before* __esptool_py_setup_main_flash_target is called. # target's properties *before* __esptool_py_setup_main_flash_target is called.
# This is because __esptool_py_setup_main_flash_target copies properties from the 'flash' # This is because __esptool_py_setup_main_flash_target copies properties from the 'flash'
@@ -795,19 +837,42 @@ function(idf_build_executable elf)
# #
# Set up app-flash and flash targets. The app-flash target is specifically for flashing # Set up app-flash and flash targets. The app-flash target is specifically for flashing
# just the application, while the flash target is for flashing the entire system. # just the application, while the flash target is for flashing the entire system.
if(CONFIG_APP_BUILD_GENERATE_BINARIES) idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(build_dir BUILD_DIR) idf_build_get_property(project_bin PROJECT_BIN)
idf_build_get_property(project_bin PROJECT_BIN) partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset")
partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") esptool_py_custom_target(app-flash app "app")
esptool_py_custom_target(app-flash app "app")
esptool_py_flash_target_image(app-flash app "${app_partition_offset}" "${build_dir}/${project_bin}") esptool_py_flash_target_image(app-flash app "${app_partition_offset}" "${build_dir}/${project_bin}")
esptool_py_flash_target_image(flash app "${app_partition_offset}" "${build_dir}/${project_bin}") esptool_py_flash_target_image(flash app "${app_partition_offset}" "${build_dir}/${project_bin}")
# Setup the main flash target and dependencies
__esptool_py_setup_main_flash_target()
# Create the following post-build targets after __idf_build_binary() is called to ensure that the
# app target is available.
# If anti-rollback option is set then factory partition should not be in Partition Table.
# In this case, should be used the partition table with two ota app without the factory.
partition_table_get_partition_info(factory_offset
"--partition-type app --partition-subtype factory" "offset")
partition_table_get_partition_info(test_offset "--partition-type app --partition-subtype test" "offset")
if(CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK AND (factory_offset OR test_offset))
fail_at_build_time(check_table_contents "\
ERROR: Anti-rollback option is enabled. Partition table should \
consist of two ota app without factory or test partitions.")
add_dependencies(app check_table_contents)
endif() endif()
__esptool_py_setup_main_flash_target() if(CONFIG_APP_BUILD_TYPE_APP_2NDBOOT)
endif() # Generate app_check_size_command target to check the app size against the partition table parameters
endif() partition_table_add_check_size_target(app_check_size
DEPENDS gen_project_binary
BINARY_PATH "${build_dir}/${project_bin}"
PARTITION_TYPE app)
add_dependencies(app app_check_size)
endif()
endif() # if(TARGET idf::esptool_py AND CONFIG_APP_BUILD_GENERATE_BINARIES)
endif() # if(NOT bootloader_build AND NOT esp_tee_build)
endfunction() endfunction()
# idf_build_get_config # idf_build_get_config