mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
refactor(ulp): provide a ulp_project.cmake subproject wrapper API
Build ULP full subprojects through a dedicated entry file,
components/ulp/cmake/ulp_project.cmake, that wraps tools/cmakev2/idf.cmake
and layers a small ULP API on top, mirroring the cmakev2 layering:
ulp_project_init like idf_project_init (init, detect the ULP type,
reset the compile/link options inherited from the app)
ulp_build_executable like idf_build_executable, plus the embeddable
.bin/.h/.ld artifacts
ulp_project_default like idf_project_default (single-executable case)
A child project now includes this one file instead of idf.cmake and calls
these helpers directly, so idf_build_executable is used as-is for the
multi-binary case and the module-path indirection (include(IDFULPProject)
resolved via -DCMAKE_MODULE_PATH) is gone.
As a result:
- IDFULPProjectv2.cmake is removed; its setup moves into the wrapper.
- IDFULPProject.cmake becomes the CMake v1-only entry point.
- The ULP component no longer registers a POST_ELF callback; the binary
artifacts are produced by ulp_build_executable.
- The v2 full-subproject examples (lp_core, riscv, fsm, multi_binary,
combined) are updated to the new API.
- The ULP subproject API is documented in build-system-v2.rst.
Also fix a latent bug this exercises: idf_build_library emitted linker
scripts as "-T <name>" relying on a following "-L" search directory. GNU
ld only searches -L directories that precede -T, so the direct
esp32ulp-elf-ld link used for ULP FSM failed to open the script. Emit the
absolute path instead, matching what the CMake v1 ULP build already does.
Finally, replace the parent-argument bypass loop that used to live in
IDFULPProjectv2.cmake with --no-warn-unused-cli on the child configure,
and stop passing the unused IDF_PARENT_BUILD_DIR.
Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
This commit is contained in:
committed by
Renz Bagaporo
parent
ceaa0b7a3d
commit
a9ea4f1105
@@ -181,19 +181,3 @@ elseif(ULP_TYPE STREQUAL "fsm")
|
||||
FLAGS "${ulp_ld_flags}")
|
||||
target_link_options(${COMPONENT_LIB} INTERFACE "SHELL:-u entry")
|
||||
endif()
|
||||
|
||||
function(__ulp_configure_executable ulp_app_name)
|
||||
# Generate the files consumed by the parent app: .bin payload plus symbol
|
||||
# header/linker exports produced from the ULP ELF.
|
||||
set(binary_target_args)
|
||||
if(DEFINED ULP_VAR_PREFIX)
|
||||
set(ulp_var_prefix "${ULP_VAR_PREFIX}")
|
||||
if(ULP_PREFIX_APPEND_BIN_NAME)
|
||||
string(MAKE_C_IDENTIFIER "${ulp_var_prefix}${ulp_app_name}_" ulp_var_prefix)
|
||||
endif()
|
||||
list(APPEND binary_target_args PREFIX ${ulp_var_prefix})
|
||||
endif()
|
||||
ulp_add_build_binary_targets(${ulp_app_name} ${binary_target_args})
|
||||
endfunction()
|
||||
|
||||
idf_component_register_build_event_callback(EVENT POST_ELF CALLBACK __ulp_configure_executable)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
if(IDF_BUILD_V2 AND COMMAND idf_project_init)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/IDFULPProjectv2.cmake)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# This is the CMake v1 (legacy) ULP child entry point, used by ulp_embed_binary.
|
||||
# CMake v2 full-subproject builds include components/ulp/cmake/ulp_project.cmake
|
||||
# instead.
|
||||
#
|
||||
# Legacy ULP child projects are plain CMake projects, so the parent-provided
|
||||
# sdkconfig.cmake has to be loaded here before the common ULP helpers inspect
|
||||
# CONFIG_* values. CMake v1 callers pass this path explicitly.
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/IDFULPProjectCommon.cmake)
|
||||
|
||||
if(NOT COMMAND idf_project_init)
|
||||
message(FATAL_ERROR "CMake v2 ULP projects must include tools/cmakev2/idf.cmake "
|
||||
"before including IDFULPProject.")
|
||||
endif()
|
||||
|
||||
# Full IDF-style ULP projects include sdkconfig.cmake again during
|
||||
# idf_project_init(). Re-including it is harmless because the generated file
|
||||
# only assigns CONFIG_* variables, and this early include keeps lower-level ULP
|
||||
# helper APIs working before idf_project_init().
|
||||
include(${SDKCONFIG_CMAKE})
|
||||
|
||||
ulp_detect_build_type()
|
||||
|
||||
get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
if(NOT ASM IN_LIST enabled_languages)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
ulp_apply_build_type_options()
|
||||
|
||||
function(ulp_prepare_build)
|
||||
idf_build_get_property(ulp_build_prepared __ULP_BUILD_PREPARED)
|
||||
if(ulp_build_prepared)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(BUILD_FSM)
|
||||
check_expected_tool_version("esp32ulp-elf" ${CMAKE_ASM_COMPILER})
|
||||
# FSM links with esp32ulp-elf-ld directly, not through GCC, so avoid
|
||||
# GCC-driver link grouping flags from the generic IDF executable helper.
|
||||
idf_build_set_property(LINKER_TYPE ULP_FSM)
|
||||
endif()
|
||||
|
||||
# ULP projects use their own toolchain files and component-provided options,
|
||||
# so discard compile/link options added for normal app builds.
|
||||
foreach(property IN ITEMS
|
||||
COMPILE_OPTIONS
|
||||
C_COMPILE_OPTIONS
|
||||
CXX_COMPILE_OPTIONS
|
||||
ASM_COMPILE_OPTIONS
|
||||
COMPILE_DEFINITIONS
|
||||
LINK_OPTIONS)
|
||||
idf_build_set_property(${property} "")
|
||||
endforeach()
|
||||
|
||||
# Do not apply the default app component closure to ULP child projects.
|
||||
# ULP components should contribute dependencies explicitly.
|
||||
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "")
|
||||
idf_build_set_property(__COMMON_COMPONENT_INTERFACES "")
|
||||
idf_build_set_property(__COMMON_COMPONENTS_INITIALIZED YES)
|
||||
|
||||
# Some helpers can be called in sequence by custom ULP projects; keep this
|
||||
# setup idempotent within a child configure.
|
||||
idf_build_set_property(__ULP_BUILD_PREPARED YES)
|
||||
endfunction()
|
||||
|
||||
function(__ulp_project_default)
|
||||
set(ulp_app_name "${PROJECT_NAME}")
|
||||
|
||||
set(executable_args COMPONENTS main)
|
||||
if(NOT BUILD_FSM)
|
||||
list(APPEND executable_args MAPFILE_TARGET ${ulp_app_name}_mapfile)
|
||||
endif()
|
||||
|
||||
idf_build_executable(${ulp_app_name} ${executable_args})
|
||||
|
||||
idf_build_generate_metadata(EXECUTABLE ${ulp_app_name})
|
||||
|
||||
if(TARGET "${ulp_app_name}_mapfile")
|
||||
idf_create_size_report("${ulp_app_name}_mapfile"
|
||||
TARGET size)
|
||||
endif()
|
||||
|
||||
idf_build_generate_depgraph("${ulp_app_name}")
|
||||
endfunction()
|
||||
|
||||
macro(ulp_project_default)
|
||||
idf_project_init()
|
||||
ulp_prepare_build()
|
||||
|
||||
# Use DEFERRED optional-requires resolution only when this will be the sole
|
||||
# library being built.
|
||||
idf_build_set_property(IDF_COMPONENT_OPTIONAL_REQUIRES_MODE DEFERRED)
|
||||
|
||||
__ulp_project_default()
|
||||
endmacro()
|
||||
@@ -0,0 +1,188 @@
|
||||
# ULP subproject entry point for CMake v2 full-subproject builds.
|
||||
#
|
||||
# A ULP child project includes this file instead of tools/cmakev2/idf.cmake
|
||||
# directly. It pulls in the cmakev2 build system and layers the ULP subproject
|
||||
# API on top: ulp_project_init, ulp_build_executable, ulp_build_binary and
|
||||
# ulp_project_default, the ULP analogs of idf_project_init,
|
||||
# idf_build_executable, idf_build_binary and idf_project_default.
|
||||
|
||||
include(${IDF_PATH}/tools/cmakev2/idf.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/IDFULPProjectCommon.cmake)
|
||||
|
||||
# Reset the compile/link state inherited from the parent app build and select
|
||||
# ULP-specific build behavior. Idempotent within a child configure.
|
||||
function(__ulp_prepare_build)
|
||||
idf_build_get_property(ulp_build_prepared __ULP_BUILD_PREPARED)
|
||||
if(ulp_build_prepared)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(BUILD_FSM)
|
||||
check_expected_tool_version("esp32ulp-elf" ${CMAKE_ASM_COMPILER})
|
||||
# FSM links with esp32ulp-elf-ld directly, not through GCC, so avoid
|
||||
# GCC-driver link grouping flags from the generic executable helper.
|
||||
idf_build_set_property(LINKER_TYPE ULP_FSM)
|
||||
endif()
|
||||
|
||||
# ULP projects use their own toolchain files and component-provided options,
|
||||
# so discard compile/link options added for normal app builds.
|
||||
foreach(property IN ITEMS
|
||||
COMPILE_OPTIONS
|
||||
C_COMPILE_OPTIONS
|
||||
CXX_COMPILE_OPTIONS
|
||||
ASM_COMPILE_OPTIONS
|
||||
COMPILE_DEFINITIONS
|
||||
LINK_OPTIONS)
|
||||
idf_build_set_property(${property} "")
|
||||
endforeach()
|
||||
|
||||
# Do not apply the default app component closure to ULP child projects.
|
||||
# ULP components should contribute dependencies explicitly.
|
||||
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "")
|
||||
idf_build_set_property(__COMMON_COMPONENT_INTERFACES "")
|
||||
idf_build_set_property(__COMMON_COMPONENTS_INITIALIZED YES)
|
||||
|
||||
idf_build_set_property(__ULP_BUILD_PREPARED YES)
|
||||
endfunction()
|
||||
|
||||
#[[api
|
||||
.. cmakev2:macro:: ulp_project_init
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
ulp_project_init()
|
||||
|
||||
Initialize a ULP full-subproject build. Calls :cmakev2:ref:`idf_project_init`
|
||||
and then applies the ULP-specific setup: it detects the ULP type (RISC-V, LP
|
||||
core or FSM) from the ``ULP_TYPE`` variable or the project configuration and
|
||||
resets the compile and link options inherited from the parent application
|
||||
build, so the ULP executable uses only its own toolchain and
|
||||
component-provided options.
|
||||
|
||||
This is the ULP analog of :cmakev2:ref:`idf_project_init` and is the entry
|
||||
point for projects that build more than one ULP executable, followed by
|
||||
:cmakev2:ref:`ulp_build_executable` and :cmakev2:ref:`ulp_build_binary`
|
||||
calls. For the common single-executable case use
|
||||
:cmakev2:ref:`ulp_project_default` instead.
|
||||
#]]
|
||||
macro(ulp_project_init)
|
||||
idf_project_init()
|
||||
ulp_detect_build_type()
|
||||
ulp_apply_build_type_options()
|
||||
__ulp_prepare_build()
|
||||
endmacro()
|
||||
|
||||
#[[api
|
||||
.. cmakev2:function:: ulp_build_executable
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
ulp_build_executable(<executable>
|
||||
[COMPONENTS <component>...]
|
||||
[MAPFILE_TARGET <target>])
|
||||
|
||||
*executable[in]*
|
||||
|
||||
Name of the ULP executable target to create.
|
||||
|
||||
Build a ULP executable. This is the ULP analog of
|
||||
:cmakev2:ref:`idf_build_executable` and forwards its arguments to
|
||||
:cmakev2:ref:`idf_build_executable`. Call :cmakev2:ref:`ulp_build_binary`
|
||||
for each executable that should produce embeddable ULP artifacts.
|
||||
#]]
|
||||
function(ulp_build_executable executable)
|
||||
if("PREFIX" IN_LIST ARGN)
|
||||
message(FATAL_ERROR "Use ulp_build_binary(${executable} PREFIX ...) to set ULP symbol prefixes.")
|
||||
endif()
|
||||
|
||||
idf_build_executable(${executable} ${ARGN})
|
||||
endfunction()
|
||||
|
||||
#[[api
|
||||
.. cmakev2:function:: ulp_build_binary
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
ulp_build_binary(<executable>
|
||||
[PREFIX <prefix>])
|
||||
|
||||
*executable[in]*
|
||||
|
||||
ULP executable target for which to generate embeddable artifacts.
|
||||
|
||||
*PREFIX[in,opt]*
|
||||
|
||||
Symbol name prefix for the generated symbol header and linker export
|
||||
files. Defaults to ``ulp_``. Use a distinct prefix per executable when a
|
||||
project builds several ULP binaries.
|
||||
|
||||
Generate the ``.bin`` payload and symbol header/linker export files for a
|
||||
ULP executable. This is the ULP analog of :cmakev2:ref:`idf_build_binary`.
|
||||
#]]
|
||||
function(ulp_build_binary executable)
|
||||
cmake_parse_arguments(_ULP "" "PREFIX" "" ${ARGN})
|
||||
if(_ULP_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unexpected arguments to ulp_build_binary(): ${_ULP_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
|
||||
if(DEFINED _ULP_PREFIX)
|
||||
ulp_add_build_binary_targets(${executable} PREFIX "${_ULP_PREFIX}")
|
||||
elseif(ULP_PREFIX_APPEND_BIN_NAME)
|
||||
set(prefix "ulp_")
|
||||
if(DEFINED ULP_VAR_PREFIX)
|
||||
set(prefix "${ULP_VAR_PREFIX}")
|
||||
endif()
|
||||
string(MAKE_C_IDENTIFIER "${prefix}${executable}_" prefix)
|
||||
ulp_add_build_binary_targets(${executable} PREFIX "${prefix}")
|
||||
else()
|
||||
ulp_add_build_binary_targets("${executable}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Build the single default ULP executable from the main component.
|
||||
function(__ulp_project_default)
|
||||
set(ulp_app_name "${PROJECT_NAME}")
|
||||
|
||||
set(executable_args COMPONENTS main)
|
||||
set(binary_args)
|
||||
if(NOT BUILD_FSM)
|
||||
list(APPEND executable_args MAPFILE_TARGET ${ulp_app_name}_mapfile)
|
||||
endif()
|
||||
if(DEFINED ULP_VAR_PREFIX AND NOT "${ULP_VAR_PREFIX}" STREQUAL "")
|
||||
list(APPEND binary_args PREFIX ${ULP_VAR_PREFIX})
|
||||
endif()
|
||||
|
||||
ulp_build_executable(${ulp_app_name} ${executable_args})
|
||||
ulp_build_binary(${ulp_app_name} ${binary_args})
|
||||
|
||||
idf_build_generate_metadata(EXECUTABLE ${ulp_app_name})
|
||||
|
||||
if(TARGET "${ulp_app_name}_mapfile")
|
||||
idf_create_size_report("${ulp_app_name}_mapfile" TARGET size)
|
||||
endif()
|
||||
|
||||
idf_build_generate_depgraph("${ulp_app_name}")
|
||||
endfunction()
|
||||
|
||||
#[[api
|
||||
.. cmakev2:macro:: ulp_project_default
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
ulp_project_default()
|
||||
|
||||
Build a single ULP executable from the ``main`` component and its transitive
|
||||
dependencies, the ULP analog of :cmakev2:ref:`idf_project_default`. Calls
|
||||
:cmakev2:ref:`ulp_project_init`, then builds the executable (named after
|
||||
``PROJECT_NAME``) with :cmakev2:ref:`ulp_build_executable` and generates its
|
||||
embeddable artifacts with :cmakev2:ref:`ulp_build_binary`.
|
||||
#]]
|
||||
macro(ulp_project_default)
|
||||
ulp_project_init()
|
||||
|
||||
# A single executable is built, so DEFERRED optional-requires resolution is
|
||||
# safe and keeps the linked component set minimal.
|
||||
idf_build_set_property(IDF_COMPONENT_OPTIONAL_REQUIRES_MODE DEFERRED)
|
||||
|
||||
__ulp_project_default()
|
||||
endmacro()
|
||||
@@ -125,6 +125,10 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
|
||||
set(ulp_project_args)
|
||||
if(IDF_BUILD_V2)
|
||||
set(ulp_project_args
|
||||
# The parent passes a superset of variables that different ULP
|
||||
# subproject styles consume (e.g. ULP_VAR_PREFIX only by
|
||||
# ulp_project_default, COMPONENT_INCLUDES only by hand-written
|
||||
# subprojects). Do not warn about the ones a given child ignores.
|
||||
--no-warn-unused-cli
|
||||
-DIDF_DEFAULT_PROJECT_NAME=${app_name}
|
||||
-DIDF_BUILD_V2=y
|
||||
@@ -166,7 +170,9 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
|
||||
-DCOMPONENT_DIR=${COMPONENT_DIR}
|
||||
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>
|
||||
-DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
|
||||
-DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE})
|
||||
-DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE}
|
||||
# The v1 ULP child resolves include(IDFULPProject) via the module path.
|
||||
-DCMAKE_MODULE_PATH=${ulp_cmake_dir})
|
||||
endif()
|
||||
|
||||
externalproject_add(${app_name}
|
||||
@@ -183,7 +189,6 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
|
||||
-DIDF_TARGET=${idf_target}
|
||||
-DIDF_PATH=${idf_path}
|
||||
-DPYTHON=${python}
|
||||
-DCMAKE_MODULE_PATH=${ulp_cmake_dir}
|
||||
${extra_cmake_args}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build ${ulp_binary_dir} --target build
|
||||
BUILD_BYPRODUCTS ${ulp_artifacts} ${ulp_artifacts_extras} ${ulp_ps_sources}
|
||||
|
||||
Reference in New Issue
Block a user