mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
feat(ulp): build ULP full subprojects as CMake v2 children
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
# TODO(IDF-15945): potentially remove __ULP_BUILD handling from esp_common
|
||||
if(${target} STREQUAL "linux" OR __ULP_BUILD)
|
||||
# ULP sources include esp_err.h from components/ulp public and shared headers.
|
||||
set(ldfragments)
|
||||
else()
|
||||
set(ldfragments common.lf soc.lf linker.lf)
|
||||
endif()
|
||||
|
||||
set(srcs "src/esp_err_to_name.c")
|
||||
set(srcs)
|
||||
|
||||
if(NOT __ULP_BUILD)
|
||||
set(srcs "src/esp_err_to_name.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
|
||||
@@ -2,6 +2,24 @@ idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
set(srcs)
|
||||
set(public_include "include")
|
||||
|
||||
# TODO(IDF-15946): potentially remove __ULP_BUILD handling from esp_driver_uart
|
||||
if(__ULP_BUILD)
|
||||
# LP-core UART wakeup shared code includes driver/uart_wakeup.h from
|
||||
# ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h.
|
||||
set(ulp_srcs)
|
||||
if(ULP_TYPE STREQUAL "lp_core" AND
|
||||
CONFIG_SOC_UART_SUPPORTED AND
|
||||
(CONFIG_SOC_DEEP_SLEEP_SUPPORTED OR CONFIG_SOC_LIGHT_SLEEP_SUPPORTED))
|
||||
list(APPEND ulp_srcs "src/uart_wakeup.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${ulp_srcs}
|
||||
INCLUDE_DIRS ${public_include}
|
||||
REQUIRES esp_common esp_hal_uart esp_hw_support log soc)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_UART_SUPPORTED)
|
||||
list(APPEND srcs "src/uart.c")
|
||||
|
||||
|
||||
@@ -5,14 +5,27 @@ endif()
|
||||
|
||||
set(srcs)
|
||||
set(includes "include")
|
||||
# Public clock HAL headers include soc/ and hal/ headers directly, and some
|
||||
# target clk_tree_ll.h headers include hal/regi2c_ctrl.h.
|
||||
set(requires soc hal esp_hal_regi2c)
|
||||
|
||||
# Target-specific include directory if present
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/include")
|
||||
list(APPEND includes "${target}/include")
|
||||
endif()
|
||||
|
||||
# TODO(IDF-15947): potentially remove __ULP_BUILD handling from esp_hal_clock
|
||||
if(__ULP_BUILD)
|
||||
# LP-core timer shared code includes hal/clk_tree_ll.h from
|
||||
# ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c. Some target
|
||||
# clk_tree_ll.h headers include hal/regi2c_ctrl.h.
|
||||
idf_component_register(INCLUDE_DIRS ${includes}
|
||||
REQUIRES ${requires})
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND srcs "${target}/clk_tree_hal.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
REQUIRES soc hal)
|
||||
REQUIRES ${requires})
|
||||
|
||||
@@ -7,19 +7,23 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/include")
|
||||
list(APPEND includes "${target}/include")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_GPIO_PORT GREATER 0)
|
||||
# ULP GPIO helpers include GPIO/RTC IO HAL headers from
|
||||
# ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h and
|
||||
# ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h.
|
||||
# TODO(IDF-15948): potentially remove __ULP_BUILD source exclusions from esp_hal_gpio
|
||||
if(CONFIG_SOC_GPIO_PORT GREATER 0 AND NOT __ULP_BUILD)
|
||||
list(APPEND srcs "gpio_hal.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_RTCIO_PIN_COUNT GREATER 0)
|
||||
if(CONFIG_SOC_RTCIO_PIN_COUNT GREATER 0 AND NOT __ULP_BUILD)
|
||||
list(APPEND srcs "rtc_io_hal.c" "${target}/rtc_io_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED)
|
||||
if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED AND NOT __ULP_BUILD)
|
||||
list(APPEND srcs "${target}/dedic_gpio_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SDM_SUPPORTED)
|
||||
if(CONFIG_SOC_SDM_SUPPORTED AND NOT __ULP_BUILD)
|
||||
list(APPEND srcs "sdm_hal.c" "${target}/sdm_periph.c")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -5,6 +5,19 @@ endif()
|
||||
|
||||
set(srcs)
|
||||
set(public_include "include" "${target}/include")
|
||||
# Public PMU/RTC control HAL headers include hal/regi2c_ctrl.h on several
|
||||
# targets, so CMake v2 builds need esp_hal_regi2c explicitly.
|
||||
set(requires soc hal esp_rom esp_hal_regi2c)
|
||||
|
||||
# TODO(IDF-15949): potentially remove __ULP_BUILD handling from esp_hal_pmu
|
||||
if(__ULP_BUILD)
|
||||
# LP-core runtime code includes hal/pmu_ll.h from
|
||||
# ulp/lp_core/lp_core/lp_core_utils.c. Some target brownout/VBAT headers
|
||||
# include hal/regi2c_ctrl.h.
|
||||
idf_component_register(INCLUDE_DIRS ${public_include}
|
||||
REQUIRES ${requires})
|
||||
return()
|
||||
endif()
|
||||
|
||||
# New chips with PMU peripheral
|
||||
if(CONFIG_SOC_PMU_SUPPORTED)
|
||||
@@ -31,5 +44,5 @@ endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${public_include}
|
||||
REQUIRES soc hal esp_rom
|
||||
REQUIRES ${requires}
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
@@ -11,6 +11,15 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/include")
|
||||
list(APPEND includes "${target}/include")
|
||||
endif()
|
||||
|
||||
# TODO(IDF-15950): potentially remove __ULP_BUILD handling from esp_hal_regi2c
|
||||
if(__ULP_BUILD)
|
||||
# ULP ADC support reaches REGI2C headers through ADC HAL includes used by
|
||||
# ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c.
|
||||
idf_component_register(INCLUDE_DIRS ${includes}
|
||||
REQUIRES soc hal esp_rom)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Per-target regi2c implementation sources (replaces ROM implementation when needed)
|
||||
if(NOT CONFIG_ESP_ROM_HAS_REGI2C_IMPL)
|
||||
list(APPEND srcs "${target}/regi2c_impl.c")
|
||||
|
||||
@@ -12,6 +12,34 @@ if(${target} STREQUAL "linux")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(public_include_dirs "include" "include/soc"
|
||||
"ldo/include" "debug_probe/include" "etm/include"
|
||||
"mspi/mspi_timing_tuning/include" "mspi/mspi_timing_tuning/tuning_scheme_impl/include"
|
||||
"mspi/mspi_intr/include"
|
||||
"power_supply/include" "modem/include")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/soc/${target}")
|
||||
list(APPEND public_include_dirs
|
||||
"include/soc/${target}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/port/${target}/include")
|
||||
list(APPEND public_include_dirs
|
||||
"port/${target}/include"
|
||||
)
|
||||
endif()
|
||||
|
||||
# TODO(IDF-15951): potentially remove __ULP_BUILD handling from esp_hw_support
|
||||
if(__ULP_BUILD)
|
||||
# ULP headers and LP-core runtime include esp_intr_alloc.h and esp_cpu.h from
|
||||
# ulp/ulp_riscv/include/ulp_riscv.h and
|
||||
# ulp/lp_core/lp_core/lp_core_ubsan.c.
|
||||
idf_component_register(INCLUDE_DIRS ${public_include_dirs}
|
||||
REQUIRES esp_common esp_hal_gpio hal soc)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(requires esp_hal_gpio esp_hal_usb esp_hal_pmu esp_hal_regi2c esp_hal_uart)
|
||||
set(priv_requires efuse # only esp_hw_support/adc_share_hw_ctrl.c requires efuse component
|
||||
spi_flash
|
||||
@@ -177,18 +205,6 @@ else()
|
||||
list(APPEND priv_requires "esp_system")
|
||||
endif()
|
||||
|
||||
set(public_include_dirs "include" "include/soc"
|
||||
"ldo/include" "debug_probe/include" "etm/include"
|
||||
"mspi/mspi_timing_tuning/include" "mspi/mspi_timing_tuning/tuning_scheme_impl/include"
|
||||
"mspi/mspi_intr/include"
|
||||
"power_supply/include" "modem/include")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/soc/${target}")
|
||||
list(APPEND public_include_dirs
|
||||
"include/soc/${target}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "esp32p4")
|
||||
# for mipi_csi_share_hw_ctrl.c
|
||||
list(APPEND priv_requires esp_hal_cam)
|
||||
|
||||
@@ -7,6 +7,22 @@ set(include_dirs "include"
|
||||
"${target_folder}/include/${target_folder}"
|
||||
"${target_folder}")
|
||||
|
||||
# TODO(IDF-15952): potentially remove __ULP_BUILD handling from esp_rom
|
||||
if(__ULP_BUILD)
|
||||
# LP-core runtime and print code include ROM headers from
|
||||
# ulp/lp_core/lp_core/lp_core_startup.c and
|
||||
# ulp/lp_core/lp_core/lp_core_print.c.
|
||||
idf_component_register(INCLUDE_DIRS ${include_dirs})
|
||||
if(ULP_TYPE STREQUAL "lp_core" AND CONFIG_ESP_ROM_HAS_LP_ROM)
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE
|
||||
"${target_folder}/ld/${target}lp.rom.ld"
|
||||
"${target_folder}/ld/${target}lp.rom.newlib.ld"
|
||||
"${target_folder}/ld/${target}lp.rom.version.ld"
|
||||
"${target_folder}/ld/${target}lp.rom.api.ld")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(private_required_comp "")
|
||||
|
||||
set(sources "patches/esp_rom_sys.c"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
|
||||
|
||||
set(srcs "hal_utils.c")
|
||||
set(srcs)
|
||||
set(includes "platform_port/include")
|
||||
set(priv_include)
|
||||
set(requires)
|
||||
@@ -12,6 +12,18 @@ list(APPEND includes "${target}/include")
|
||||
|
||||
list(APPEND includes "include")
|
||||
|
||||
# ULP runtime code includes generic HAL headers, for example hal/lp_core_ll.h
|
||||
# from ulp/lp_core/lp_core/lp_core_interrupt.c.
|
||||
# TODO(IDF-15953): potentially remove __ULP_BUILD handling from hal
|
||||
if(__ULP_BUILD)
|
||||
idf_component_register(INCLUDE_DIRS ${includes}
|
||||
PRIV_INCLUDE_DIRS ${priv_include}
|
||||
REQUIRES esp_common ${requires})
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND srcs "hal_utils.c")
|
||||
|
||||
if(CONFIG_SOC_EFUSE_SUPPORTED)
|
||||
list(APPEND srcs "efuse_hal.c" "${target}/efuse_hal.c")
|
||||
endif()
|
||||
@@ -46,11 +58,13 @@ if(NOT esp_tee_build AND NOT BOOTLOADER_BUILD)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ldfragments linker.lf)
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
PRIV_INCLUDE_DIRS ${priv_include}
|
||||
REQUIRES ${requires}
|
||||
LDFRAGMENTS linker.lf)
|
||||
LDFRAGMENTS ${ldfragments})
|
||||
|
||||
if(CONFIG_HAL_DEFAULT_ASSERTION_LEVEL EQUAL 1)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u abort")
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
idf_build_get_property(non_os_build NON_OS_BUILD)
|
||||
|
||||
# TODO(IDF-15954): potentially remove __ULP_BUILD handling from log
|
||||
if(__ULP_BUILD)
|
||||
# LP-core UART wakeup support builds components/esp_driver_uart/src/uart_wakeup.c,
|
||||
# which includes ESP log headers.
|
||||
idf_component_register(INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "include/esp_private"
|
||||
REQUIRES esp_rom)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(non_os_build)
|
||||
set(system_target "noos")
|
||||
else()
|
||||
|
||||
@@ -2,10 +2,20 @@ idf_build_get_property(target IDF_TARGET)
|
||||
idf_build_get_property(arch IDF_TARGET_ARCH)
|
||||
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
|
||||
|
||||
if(NOT "${arch}" STREQUAL "riscv")
|
||||
# TODO(IDF-15955): potentially remove __ULP_BUILD handling from riscv
|
||||
if(NOT "${arch}" STREQUAL "riscv" AND NOT (__ULP_BUILD AND "${ULP_TYPE}" STREQUAL "riscv"))
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(__ULP_BUILD AND "${ULP_TYPE}" STREQUAL "riscv")
|
||||
# RISC-V ULP interrupt support includes riscv/interrupt.h from
|
||||
# ulp/ulp_riscv/ulp_core/include/ulp_riscv_interrupt.h.
|
||||
idf_component_register(INCLUDE_DIRS "include")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# When __ULP_BUILD and ULP_TYPE is lp_core, keep the normal RISC-V helper sources for headers
|
||||
# used by ulp/lp_core/lp_core/lp_core_pmp.c and vector.S.
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
set(priv_requires soc hal)
|
||||
|
||||
@@ -4,14 +4,6 @@ set(target_folder "${target}")
|
||||
|
||||
set(srcs)
|
||||
|
||||
# On Linux the soc component is a simple wrapper, without much functionality
|
||||
if(NOT ${target} STREQUAL "linux")
|
||||
set(srcs "lldesc.c"
|
||||
"dport_access_common.c"
|
||||
"${target_folder}/interrupts.c"
|
||||
"${target_folder}/gpio_periph.c")
|
||||
endif()
|
||||
|
||||
set(includes "include" "${target_folder}")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target_folder}/include")
|
||||
@@ -39,6 +31,33 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TODO(IDF-15956): potentially remove __ULP_BUILD handling from soc
|
||||
if(__ULP_BUILD)
|
||||
idf_component_register(INCLUDE_DIRS ${includes}
|
||||
REQUIRES esp_common)
|
||||
|
||||
# For an embedded system, the MMU page size should always be defined statically
|
||||
# For IDF, we define it according to the Flash size that user selects
|
||||
# Replace this value in an adaptive way, if Kconfig isn't available on your platform
|
||||
target_compile_definitions(${COMPONENT_LIB} INTERFACE SOC_MMU_PAGE_SIZE=CONFIG_MMU_PAGE_SIZE)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} INTERFACE SOC_XTAL_FREQ_MHZ=CONFIG_XTAL_FREQ)
|
||||
|
||||
if(ULP_TYPE STREQUAL "lp_core")
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE "${target_folder}/ld/${target}.peripherals.ld")
|
||||
endif()
|
||||
|
||||
return()
|
||||
endif()
|
||||
|
||||
# On Linux the soc component is a simple wrapper, without much functionality.
|
||||
if(NOT ${target} STREQUAL "linux")
|
||||
set(srcs "lldesc.c"
|
||||
"dport_access_common.c"
|
||||
"${target_folder}/interrupts.c"
|
||||
"${target_folder}/gpio_periph.c")
|
||||
endif()
|
||||
|
||||
if(target STREQUAL "esp32")
|
||||
list(APPEND srcs "${target_folder}/dport_access.c")
|
||||
endif()
|
||||
@@ -55,9 +74,11 @@ if(CONFIG_SOC_BOD_SUPPORTED)
|
||||
list(APPEND srcs "${target_folder}/power_supply_periph.c")
|
||||
endif()
|
||||
|
||||
set(ldfragments "linker.lf")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
LDFRAGMENTS "linker.lf")
|
||||
LDFRAGMENTS ${ldfragments})
|
||||
|
||||
# For an embedded system, the MMU page size should always be defined statically
|
||||
# For IDF, we define it according to the Flash size that user selects
|
||||
|
||||
@@ -4,6 +4,11 @@ if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
if(IDF_BUILD_V2)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakeLists_v2.txt)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(srcs "")
|
||||
set(includes "")
|
||||
|
||||
|
||||
247
components/ulp/CMakeLists_v2.txt
Normal file
247
components/ulp/CMakeLists_v2.txt
Normal file
@@ -0,0 +1,247 @@
|
||||
set(srcs "")
|
||||
set(includes "")
|
||||
set(requires "")
|
||||
set(priv_requires "")
|
||||
|
||||
if(__ULP_BUILD)
|
||||
if(ULP_TYPE STREQUAL "riscv")
|
||||
list(APPEND includes
|
||||
ulp_riscv/shared/include
|
||||
ulp_riscv/ulp_core/include)
|
||||
list(APPEND srcs
|
||||
"ulp_riscv/ulp_core/ulp_riscv_vectors.S"
|
||||
"ulp_riscv/ulp_core/start.S"
|
||||
"ulp_riscv/ulp_core/ulp_riscv_utils.c")
|
||||
list(APPEND requires
|
||||
riscv
|
||||
soc)
|
||||
elseif(ULP_TYPE STREQUAL "lp_core")
|
||||
list(APPEND includes
|
||||
lp_core/lp_core/include
|
||||
lp_core/shared/include)
|
||||
list(APPEND srcs
|
||||
"lp_core/lp_core/start.S"
|
||||
"lp_core/lp_core/vector.S"
|
||||
"lp_core/lp_core/port/${target}/vector_table.S"
|
||||
"lp_core/shared/ulp_lp_core_memory_shared.c"
|
||||
"lp_core/lp_core/lp_core_startup.c"
|
||||
"lp_core/lp_core/lp_core_pmp.c"
|
||||
"lp_core/lp_core/lp_core_utils.c"
|
||||
"lp_core/lp_core/lp_core_panic.c"
|
||||
"lp_core/lp_core/lp_core_interrupt.c"
|
||||
"lp_core/shared/ulp_lp_core_lp_uart_shared.c"
|
||||
"lp_core/lp_core/lp_core_uart.c"
|
||||
"lp_core/shared/ulp_lp_core_lp_timer_shared.c"
|
||||
"lp_core/shared/ulp_lp_core_critical_section_shared.c")
|
||||
|
||||
list(APPEND requires
|
||||
esp_common
|
||||
esp_driver_uart
|
||||
esp_hal_gpio
|
||||
esp_hal_uart
|
||||
esp_rom
|
||||
hal
|
||||
riscv
|
||||
soc)
|
||||
list(APPEND priv_requires
|
||||
esp_hal_clock
|
||||
esp_hal_i2s
|
||||
esp_hal_rtc_timer
|
||||
esp_hal_pmu
|
||||
esp_hw_support)
|
||||
|
||||
elseif(ULP_TYPE STREQUAL "fsm")
|
||||
list(APPEND includes
|
||||
ulp_common/include
|
||||
ulp_fsm/include
|
||||
ulp_fsm/include/${target})
|
||||
list(APPEND requires soc)
|
||||
else()
|
||||
message(FATAL_ERROR "__ULP_BUILD requires ULP_TYPE to be one of: riscv, lp_core, fsm.")
|
||||
endif()
|
||||
else()
|
||||
if(CONFIG_ULP_COPROC_ENABLED)
|
||||
list(APPEND includes
|
||||
ulp_common/include)
|
||||
list(APPEND requires
|
||||
esp_common
|
||||
soc)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ULP_COPROC_TYPE_FSM)
|
||||
list(APPEND includes
|
||||
ulp_fsm/include
|
||||
ulp_fsm/include/${target})
|
||||
list(APPEND srcs
|
||||
"ulp_common/ulp_common.c"
|
||||
"ulp_fsm/ulp.c"
|
||||
"ulp_fsm/ulp_macro.c")
|
||||
list(APPEND requires esp_hw_support)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ULP_COPROC_TYPE_RISCV)
|
||||
list(APPEND includes
|
||||
ulp_riscv/include
|
||||
ulp_riscv/shared/include
|
||||
ulp_riscv/ulp_core/include)
|
||||
list(APPEND srcs
|
||||
"ulp_common/ulp_common.c"
|
||||
"ulp_riscv/ulp_riscv.c")
|
||||
list(APPEND requires
|
||||
esp_hw_support
|
||||
esp_hal_pmu)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
|
||||
list(APPEND includes
|
||||
lp_core/include
|
||||
lp_core/lp_core/include
|
||||
lp_core/shared/include)
|
||||
list(APPEND srcs
|
||||
"lp_core/lp_core.c"
|
||||
"lp_core/shared/ulp_lp_core_memory_shared.c"
|
||||
"lp_core/shared/ulp_lp_core_lp_timer_shared.c"
|
||||
"lp_core/shared/ulp_lp_core_critical_section_shared.c")
|
||||
list(APPEND requires
|
||||
esp_hw_support
|
||||
esp_hal_clock
|
||||
esp_hal_pmu
|
||||
esp_hal_rtc_timer
|
||||
esp_rom
|
||||
hal
|
||||
riscv
|
||||
soc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(requires)
|
||||
list(REMOVE_DUPLICATES requires)
|
||||
endif()
|
||||
|
||||
if(priv_requires)
|
||||
list(REMOVE_DUPLICATES priv_requires)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
REQUIRES ${requires}
|
||||
PRIV_REQUIRES ${priv_requires})
|
||||
|
||||
# In the parent app build, the ulp component only provides the host-side API.
|
||||
# The executable/linker setup below is for native ULP child projects.
|
||||
if(NOT __ULP_BUILD)
|
||||
idf_define_esp_err_codes(HEADERS ulp_fsm/include/ulp_fsm_common.h)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Linker scripts are preprocessed by the C compiler, so this list is later
|
||||
# converted into -I arguments for resolving #include lines in the templates.
|
||||
set(ulp_linker_script_include_dirs "${CMAKE_CURRENT_SOURCE_DIR}/ld")
|
||||
|
||||
# Select the linker template and target-specific link options used by the ULP
|
||||
# executable created in the child project.
|
||||
if(ULP_TYPE STREQUAL "riscv")
|
||||
set(ulp_ld_template "${CMAKE_CURRENT_SOURCE_DIR}/ld/ulp_riscv.ld")
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/${target}.peripherals.ld")
|
||||
target_link_options(${COMPONENT_LIB} INTERFACE
|
||||
-nostartfiles
|
||||
-Wl,--gc-sections
|
||||
-Wl,--no-warn-rwx-segments
|
||||
LINKER:-u,main)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC
|
||||
IS_ULP_COCPU
|
||||
ULP_RISCV_REGISTER_OPS)
|
||||
elseif(ULP_TYPE STREQUAL "lp_core")
|
||||
set(ulp_ld_template "${CMAKE_CURRENT_SOURCE_DIR}/ld/lp_core_riscv.ld")
|
||||
# lp_core_riscv.ld includes common ESP system linker snippets and SoC
|
||||
# headers for target memory constants.
|
||||
idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR)
|
||||
list(APPEND ulp_linker_script_include_dirs
|
||||
"${esp_system_dir}/ld"
|
||||
"${esp_system_dir}/ld/${target}")
|
||||
|
||||
idf_component_get_property(linker_dep_lib soc COMPONENT_LIB)
|
||||
get_target_property(linker_dep_include_dirs "${linker_dep_lib}" INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if(linker_dep_include_dirs)
|
||||
list(APPEND ulp_linker_script_include_dirs ${linker_dep_include_dirs})
|
||||
endif()
|
||||
|
||||
target_link_options(${COMPONENT_LIB} INTERFACE
|
||||
-nostartfiles
|
||||
-Wl,--gc-sections
|
||||
-Wl,--no-warn-rwx-segments
|
||||
LINKER:-u,main)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC IS_ULP_COCPU)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough)
|
||||
elseif(ULP_TYPE STREQUAL "fsm")
|
||||
set(ulp_ld_template "${CMAKE_CURRENT_SOURCE_DIR}/ld/ulp_fsm.ld")
|
||||
target_link_options(${COMPONENT_LIB} INTERFACE "SHELL:-u entry")
|
||||
endif()
|
||||
|
||||
# Store the selected ULP build metadata on the component. The POST_ELF callback
|
||||
# reads these properties when it attaches the generated linker script.
|
||||
idf_component_set_property(ulp ULP_LD_TEMPLATE "${ulp_ld_template}")
|
||||
idf_component_set_property(ulp ULP_LINKER_SCRIPT_INCLUDE_DIRS
|
||||
"${ulp_linker_script_include_dirs}")
|
||||
|
||||
function(__ulp_configure_executable ulp_app_name)
|
||||
set(include_arg_separator "\n")
|
||||
macro(__ulp_add_target_include_args target)
|
||||
foreach(property INTERFACE_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES)
|
||||
set(include_args "$<$<BOOL:$<TARGET_PROPERTY:${target},${property}>>:-I$<JOIN:$<TARGET_PROPERTY:${target},${property}>,${include_arg_separator}-I>>")
|
||||
list(APPEND linker_script_include_args "$<TARGET_GENEX_EVAL:${target},${include_args}>")
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Generate and attach the ULP linker script after the executable exists so
|
||||
# library/component include directories are available.
|
||||
set(linker_script_include_args)
|
||||
|
||||
# CMake v2 stores the component closure and build-wide include directories
|
||||
# on the executable's library interface after idf_build_executable().
|
||||
get_target_property(library_interface "${ulp_app_name}" LIBRARY_INTERFACE)
|
||||
__ulp_add_target_include_args("${library_interface}")
|
||||
|
||||
idf_library_get_property(component_interfaces "${library_interface}"
|
||||
LIBRARY_COMPONENT_INTERFACES_LINKED)
|
||||
foreach(component_interface IN LISTS component_interfaces)
|
||||
__ulp_add_target_include_args("${component_interface}")
|
||||
|
||||
# Some component include directories live on the real library target
|
||||
# rather than the interface target, so collect both.
|
||||
idf_component_get_property(component_target "${component_interface}" COMPONENT_REAL_TARGET)
|
||||
if(TARGET "${component_target}")
|
||||
__ulp_add_target_include_args("${component_target}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
idf_component_get_property(linker_include_dirs ulp ULP_LINKER_SCRIPT_INCLUDE_DIRS)
|
||||
set(linker_script_includes ${linker_include_dirs})
|
||||
list(REMOVE_DUPLICATES linker_script_includes)
|
||||
list(TRANSFORM linker_script_includes PREPEND "-I")
|
||||
list(APPEND linker_script_include_args ${linker_script_includes})
|
||||
|
||||
idf_component_get_property(ULP_LD_TEMPLATE ulp ULP_LD_TEMPLATE)
|
||||
get_filename_component(ld_script_name ${ULP_LD_TEMPLATE} NAME)
|
||||
set(ld_script "${ulp_app_name}_${ld_script_name}")
|
||||
|
||||
# Make the generated script an explicit prerequisite of the executable and
|
||||
# then pass it to the linker.
|
||||
string(MAKE_C_IDENTIFIER "${ulp_app_name}_ld_script" ld_script_target)
|
||||
__ulp_add_preprocessed_linker_script(${ulp_app_name} ${ULP_LD_TEMPLATE} ${ld_script}
|
||||
${ld_script_target} ${linker_script_include_args})
|
||||
|
||||
# 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,10 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
if(IDF_BUILD_V2)
|
||||
include(CMakeLists_v2.txt)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(${IDF_PATH}/tools/cmake/idf.cmake)
|
||||
project(${ULP_APP_NAME})
|
||||
add_executable(${ULP_APP_NAME})
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
include(${IDF_PATH}/tools/cmakev2/idf.cmake)
|
||||
|
||||
project(${ULP_APP_NAME} C CXX ASM)
|
||||
|
||||
idf_project_init()
|
||||
|
||||
add_executable(${ULP_APP_NAME})
|
||||
|
||||
include(IDFULPProject)
|
||||
|
||||
ulp_apply_default_options(${ULP_APP_NAME})
|
||||
ulp_apply_default_sources(${ULP_APP_NAME})
|
||||
ulp_add_build_binary_targets(${ULP_APP_NAME} PREFIX ${ULP_VAR_PREFIX})
|
||||
@@ -1,31 +1,18 @@
|
||||
if(NOT IDF_BUILD_V2)
|
||||
include(${SDKCONFIG_CMAKE})
|
||||
if(IDF_BUILD_V2 AND COMMAND idf_project_init)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/IDFULPProjectv2.cmake)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# 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.
|
||||
include(${SDKCONFIG_CMAKE})
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/IDFULPProjectCommon.cmake)
|
||||
enable_language(C ASM)
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".elf")
|
||||
|
||||
# Logic to determine ULP type and set reusable flags
|
||||
set(BUILD_RISCV OFF)
|
||||
set(BUILD_FSM OFF)
|
||||
set(BUILD_LP_CORE OFF)
|
||||
|
||||
# If ULP_TYPE is explicitly set, use it; otherwise fall back to CONFIG checks
|
||||
if(ULP_TYPE)
|
||||
string(TOLOWER "${ULP_TYPE}" ulp_type_lower)
|
||||
if(ulp_type_lower STREQUAL "riscv")
|
||||
set(BUILD_RISCV ON)
|
||||
elseif(ulp_type_lower STREQUAL "fsm")
|
||||
set(BUILD_FSM ON)
|
||||
elseif(ulp_type_lower STREQUAL "lp_core")
|
||||
set(BUILD_LP_CORE ON)
|
||||
endif()
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_RISCV)
|
||||
set(BUILD_RISCV ON)
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE)
|
||||
set(BUILD_LP_CORE ON)
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_FSM)
|
||||
set(BUILD_FSM ON)
|
||||
endif()
|
||||
ulp_detect_build_type()
|
||||
ulp_apply_build_type_options()
|
||||
|
||||
# Check the supported assembler version
|
||||
if(BUILD_FSM)
|
||||
@@ -49,16 +36,6 @@ function(ulp_apply_default_options ulp_app_name)
|
||||
endfunction()
|
||||
|
||||
function(ulp_apply_default_sources ulp_app_name)
|
||||
|
||||
function(create_arg_file arguments output_file)
|
||||
# Escape all spaces
|
||||
list(TRANSFORM arguments REPLACE " " "\\\\ ")
|
||||
# Create a single string with all args separated by space
|
||||
list(JOIN arguments " " arguments)
|
||||
# Write it into the response file
|
||||
file(WRITE ${output_file} ${arguments})
|
||||
endfunction()
|
||||
|
||||
message(STATUS "Building ULP app ${ulp_app_name}")
|
||||
|
||||
get_filename_component(sdkconfig_dir ${SDKCONFIG_HEADER} DIRECTORY)
|
||||
@@ -88,22 +65,8 @@ function(ulp_apply_default_sources ulp_app_name)
|
||||
endif()
|
||||
|
||||
get_filename_component(ULP_LD_SCRIPT ${ULP_LD_TEMPLATE} NAME)
|
||||
|
||||
# Put all arguments to the list
|
||||
set(preprocessor_args -D__ASSEMBLER__ -E -P -xc -o ${ULP_LD_SCRIPT} ${ULP_PREPRO_ARGS} ${ULP_LD_TEMPLATE})
|
||||
set(compiler_arguments_file ${CMAKE_CURRENT_BINARY_DIR}/${ULP_LD_SCRIPT}_args.txt)
|
||||
create_arg_file("${preprocessor_args}" "${compiler_arguments_file}")
|
||||
|
||||
add_custom_command(OUTPUT ${ULP_LD_SCRIPT}
|
||||
COMMAND ${CMAKE_C_COMPILER} @${compiler_arguments_file}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
MAIN_DEPENDENCY ${ULP_LD_TEMPLATE}
|
||||
DEPENDS ${SDKCONFIG_HEADER}
|
||||
COMMENT "Generating ${ULP_LD_SCRIPT} linker script..."
|
||||
VERBATIM)
|
||||
add_custom_target(ld_script DEPENDS ${ULP_LD_SCRIPT})
|
||||
add_dependencies(${ulp_app_name} ld_script)
|
||||
target_link_options(${ulp_app_name} PRIVATE SHELL:-T ${CMAKE_CURRENT_BINARY_DIR}/${ULP_LD_SCRIPT})
|
||||
__ulp_add_preprocessed_linker_script(${ulp_app_name} ${ULP_LD_TEMPLATE} ${ULP_LD_SCRIPT}
|
||||
ld_script ${ULP_PREPRO_ARGS})
|
||||
|
||||
# To avoid warning "Manually-specified variables were not used by the project"
|
||||
set(bypassWarning "${IDF_TARGET}")
|
||||
@@ -148,7 +111,7 @@ function(ulp_apply_default_sources ulp_app_name)
|
||||
set(preprocessor_args -D__ASSEMBLER__ -E -P -xc -o ${ulp_ps_output} ${ULP_PREPRO_ARGS} ${ulp_s_source})
|
||||
|
||||
set(compiler_arguments_file ${CMAKE_CURRENT_BINARY_DIR}/${ulp_ps_source}_args.txt)
|
||||
create_arg_file("${preprocessor_args}" "${compiler_arguments_file}")
|
||||
__ulp_create_arg_file("${preprocessor_args}" "${compiler_arguments_file}")
|
||||
|
||||
# Generate preprocessed assembly files.
|
||||
add_custom_command(OUTPUT ${ulp_ps_output}
|
||||
@@ -239,59 +202,3 @@ function(ulp_apply_default_sources ulp_app_name)
|
||||
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ulp_add_build_binary_targets ulp_app_name)
|
||||
cmake_parse_arguments(ULP "" "PREFIX" "" ${ARGN})
|
||||
if(NOT ULP_PREFIX)
|
||||
set(ULP_PREFIX "ulp_")
|
||||
endif()
|
||||
|
||||
if(ADD_PICOLIBC_SPECS)
|
||||
target_compile_options(${ulp_app_name} PRIVATE $<$<COMPILE_LANG_AND_ID:C,GNU>:-specs=picolibc.specs>)
|
||||
target_compile_options(${ulp_app_name} PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-specs=picolibcpp.specs>)
|
||||
endif()
|
||||
|
||||
if(BUILD_LP_CORE)
|
||||
set(ULP_BASE_ADDR "0x0")
|
||||
else()
|
||||
set(ULP_BASE_ADDR "0x50000000")
|
||||
endif()
|
||||
|
||||
set(ULP_MAP_GEN ${PYTHON} ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
|
||||
|
||||
# Dump the list of global symbols in a convenient format
|
||||
add_custom_command(OUTPUT ${ULP_APP_NAME}.sym
|
||||
COMMAND ${CMAKE_READELF} -sW $<TARGET_FILE:${ulp_app_name}> > ${ulp_app_name}.sym
|
||||
DEPENDS ${ulp_app_name}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Dump the binary for inclusion into the project
|
||||
if(BUILD_LP_CORE AND CONFIG_ULP_COPROC_RUN_FROM_HP_MEM)
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.bin
|
||||
COMMAND ${PYTHON} -m esptool --chip ${IDF_TARGET} elf2image
|
||||
--output ${ulp_app_name}.bin $<TARGET_FILE:${ulp_app_name}>
|
||||
DEPENDS ${ulp_app_name}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
else()
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.bin
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${ulp_app_name}> ${ulp_app_name}.bin
|
||||
DEPENDS ${ulp_app_name}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.ld ${ulp_app_name}.h
|
||||
COMMAND ${ULP_MAP_GEN} -s ${ulp_app_name}.sym -o ${ulp_app_name}
|
||||
--base ${ULP_BASE_ADDR} --prefix ${ULP_PREFIX}
|
||||
--target ${IDF_TARGET}
|
||||
DEPENDS ${ulp_app_name}.sym
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Building the component separately from the project should result in
|
||||
# ULP files being built.
|
||||
add_custom_target(build
|
||||
DEPENDS ${ulp_app_name} ${ulp_app_name}.bin ${ulp_app_name}.sym
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${ulp_app_name}.ld
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${ulp_app_name}.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
endfunction()
|
||||
|
||||
126
components/ulp/cmake/IDFULPProjectCommon.cmake
Normal file
126
components/ulp/cmake/IDFULPProjectCommon.cmake
Normal file
@@ -0,0 +1,126 @@
|
||||
macro(ulp_detect_build_type)
|
||||
# Logic to determine ULP type and set reusable flags
|
||||
set(BUILD_RISCV OFF)
|
||||
set(BUILD_FSM OFF)
|
||||
set(BUILD_LP_CORE OFF)
|
||||
|
||||
# If ULP_TYPE is explicitly set, use it; otherwise fall back to CONFIG checks
|
||||
if(ULP_TYPE)
|
||||
string(TOLOWER "${ULP_TYPE}" ulp_type_lower)
|
||||
if(ulp_type_lower STREQUAL "riscv")
|
||||
set(BUILD_RISCV ON)
|
||||
elseif(ulp_type_lower STREQUAL "fsm")
|
||||
set(BUILD_FSM ON)
|
||||
elseif(ulp_type_lower STREQUAL "lp_core")
|
||||
set(BUILD_LP_CORE ON)
|
||||
endif()
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_RISCV)
|
||||
set(BUILD_RISCV ON)
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE)
|
||||
set(BUILD_LP_CORE ON)
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_FSM)
|
||||
set(BUILD_FSM ON)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(ulp_apply_build_type_options)
|
||||
# CMake initializes GNU ASM definitions as --defsym during enable_language().
|
||||
# Native full-subproject FSM sources are preprocessed by the toolchain rule,
|
||||
# so use C preprocessor definitions for generated ASM rules.
|
||||
if(BUILD_FSM AND ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN)
|
||||
set(CMAKE_ASM_DEFINE_FLAG "-D")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(__ulp_create_arg_file arguments output_file)
|
||||
# Escape all spaces
|
||||
list(TRANSFORM arguments REPLACE " " "\\\\ ")
|
||||
# Create a single string with all args separated by space
|
||||
list(JOIN arguments " " arguments)
|
||||
# Generate the response file late enough for target generator expressions
|
||||
# in include directories to resolve to their final build-system values.
|
||||
file(GENERATE OUTPUT "${output_file}" CONTENT "${arguments}")
|
||||
endfunction()
|
||||
|
||||
function(__ulp_add_preprocessed_linker_script ulp_app_name ld_template ld_script ld_script_target)
|
||||
# Use the C preprocessor so sdkconfig and SoC constants can shape the
|
||||
# linker template before the ULP executable is linked.
|
||||
set(preprocessor_args -D__ASSEMBLER__ -E -P -xc -o ${ld_script} ${ARGN} ${ld_template})
|
||||
set(compiler_arguments_file ${CMAKE_CURRENT_BINARY_DIR}/${ld_script}_args.txt)
|
||||
__ulp_create_arg_file("${preprocessor_args}" "${compiler_arguments_file}")
|
||||
|
||||
add_custom_command(OUTPUT ${ld_script}
|
||||
COMMAND ${CMAKE_C_COMPILER} @${compiler_arguments_file}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
MAIN_DEPENDENCY ${ld_template}
|
||||
DEPENDS ${SDKCONFIG_HEADER}
|
||||
COMMENT "Generating ${ld_script} linker script..."
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(${ld_script_target} DEPENDS ${ld_script})
|
||||
add_dependencies(${ulp_app_name} ${ld_script_target})
|
||||
target_link_options(${ulp_app_name} PRIVATE SHELL:-T ${CMAKE_CURRENT_BINARY_DIR}/${ld_script})
|
||||
endfunction()
|
||||
|
||||
function(ulp_add_build_binary_targets ulp_app_name)
|
||||
cmake_parse_arguments(ULP "" "PREFIX" "" ${ARGN})
|
||||
if(NOT ULP_PREFIX)
|
||||
set(ULP_PREFIX "ulp_")
|
||||
endif()
|
||||
|
||||
if(ADD_PICOLIBC_SPECS)
|
||||
target_compile_options(${ulp_app_name} PRIVATE $<$<COMPILE_LANG_AND_ID:C,GNU>:-specs=picolibc.specs>)
|
||||
target_compile_options(${ulp_app_name} PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-specs=picolibcpp.specs>)
|
||||
endif()
|
||||
|
||||
if(BUILD_LP_CORE)
|
||||
set(ULP_BASE_ADDR "0x0")
|
||||
else()
|
||||
set(ULP_BASE_ADDR "0x50000000")
|
||||
endif()
|
||||
|
||||
set(ULP_MAP_GEN ${PYTHON} ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
|
||||
|
||||
# Dump the list of global symbols in a convenient format
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.sym
|
||||
COMMAND ${CMAKE_READELF} -sW $<TARGET_FILE:${ulp_app_name}> > ${ulp_app_name}.sym
|
||||
DEPENDS ${ulp_app_name}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Dump the binary for inclusion into the project
|
||||
if(BUILD_LP_CORE AND CONFIG_ULP_COPROC_RUN_FROM_HP_MEM)
|
||||
# LP-core images running from HP memory use the normal ESP image format;
|
||||
# RTC-memory ULP binaries are raw object-copy output.
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.bin
|
||||
COMMAND ${PYTHON} -m esptool --chip ${IDF_TARGET} elf2image
|
||||
--output ${ulp_app_name}.bin $<TARGET_FILE:${ulp_app_name}>
|
||||
DEPENDS ${ulp_app_name}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
else()
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.bin
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${ulp_app_name}> ${ulp_app_name}.bin
|
||||
DEPENDS ${ulp_app_name}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${ulp_app_name}.ld ${ulp_app_name}.h
|
||||
COMMAND ${ULP_MAP_GEN} -s ${ulp_app_name}.sym -o ${ulp_app_name}
|
||||
--base ${ULP_BASE_ADDR} --prefix ${ULP_PREFIX}
|
||||
--target ${IDF_TARGET}
|
||||
DEPENDS ${ulp_app_name}.sym
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_custom_target(${ulp_app_name}_binary_artifacts
|
||||
DEPENDS ${ulp_app_name} ${ulp_app_name}.bin ${ulp_app_name}.sym
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${ulp_app_name}.ld
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${ulp_app_name}.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Building the component separately from the project should result in all
|
||||
# ULP files being built. Multiple ULP executables in one child project all
|
||||
# contribute their artifact targets here.
|
||||
if(NOT TARGET build)
|
||||
add_custom_target(build)
|
||||
endif()
|
||||
add_dependencies(build ${ulp_app_name}_binary_artifacts)
|
||||
endfunction()
|
||||
87
components/ulp/cmake/IDFULPProjectv2.cmake
Normal file
87
components/ulp/cmake/IDFULPProjectv2.cmake
Normal file
@@ -0,0 +1,87 @@
|
||||
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()
|
||||
49
components/ulp/cmake/preprocess_fsm_asm.cmake
Normal file
49
components/ulp/cmake/preprocess_fsm_asm.cmake
Normal file
@@ -0,0 +1,49 @@
|
||||
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
foreach(required_var ULP_FSM_PREPROCESSOR ULP_FSM_ASSEMBLER ULP_FSM_TARGET ULP_FSM_SOURCE ULP_FSM_OBJECT)
|
||||
if(NOT DEFINED ${required_var} OR "${${required_var}}" STREQUAL "")
|
||||
message(FATAL_ERROR "${required_var} is required")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(extra_args)
|
||||
set(extra_args_started OFF)
|
||||
math(EXPR last_arg_index "${CMAKE_ARGC} - 1")
|
||||
foreach(arg_index RANGE 0 ${last_arg_index})
|
||||
if("${CMAKE_ARGV${arg_index}}" STREQUAL "--")
|
||||
set(extra_args_started ON)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if(extra_args_started)
|
||||
list(APPEND extra_args "${CMAKE_ARGV${arg_index}}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(preprocessed_source "${ULP_FSM_OBJECT}.ulp.S")
|
||||
set(listing_file "${ULP_FSM_OBJECT}.lst")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${ULP_FSM_PREPROCESSOR}"
|
||||
-D__ASSEMBLER__ -E -P -x c
|
||||
${extra_args}
|
||||
-o "${preprocessed_source}"
|
||||
"${ULP_FSM_SOURCE}"
|
||||
RESULT_VARIABLE preprocess_result
|
||||
)
|
||||
if(NOT preprocess_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to preprocess ${ULP_FSM_SOURCE}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND "${ULP_FSM_ASSEMBLER}"
|
||||
"--mcpu=${ULP_FSM_TARGET}"
|
||||
"-al=${listing_file}"
|
||||
-o "${ULP_FSM_OBJECT}"
|
||||
-c "${preprocessed_source}"
|
||||
RESULT_VARIABLE assemble_result
|
||||
)
|
||||
if(NOT assemble_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to assemble ${preprocessed_source}")
|
||||
endif()
|
||||
@@ -9,9 +9,28 @@ set(CMAKE_ASM_COMPILER "esp32ulp-elf-as")
|
||||
set(CMAKE_OBJCOPY "esp32ulp-elf-objcopy")
|
||||
set(CMAKE_LINKER "esp32ulp-elf-ld")
|
||||
|
||||
# Native CMake v2 ULP projects include cmakev2/idf.cmake before project(),
|
||||
# making idf_project_init visible when this toolchain is loaded. Legacy child
|
||||
# projects, even when launched by a CMake v2 parent, include the old IDF CMake
|
||||
# entrypoint and keep the historical explicit preprocessing path.
|
||||
set(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN OFF)
|
||||
if(IDF_BUILD_V2 AND COMMAND idf_project_init)
|
||||
set(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
--mcpu=esp32 <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
|
||||
if(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN)
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT
|
||||
"${CMAKE_COMMAND} \
|
||||
-DULP_FSM_PREPROCESSOR=${CMAKE_C_COMPILER} \
|
||||
-DULP_FSM_ASSEMBLER=${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
-DULP_FSM_TARGET=esp32 \
|
||||
-DULP_FSM_SOURCE=<SOURCE> \
|
||||
-DULP_FSM_OBJECT=<OBJECT> \
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/preprocess_fsm_asm.cmake -- <DEFINES> <INCLUDES>")
|
||||
else()
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
--mcpu=esp32 <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
|
||||
endif()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-A elf32-esp32ulp -nostdlib" CACHE STRING "ULP Linker Base Flags")
|
||||
set(CMAKE_ASM_LINK_EXECUTABLE "${CMAKE_LINKER} <FLAGS> <CMAKE_ASM_LINK_FLAGS> \
|
||||
<LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||
|
||||
@@ -9,8 +9,28 @@ set(CMAKE_ASM_COMPILER "esp32ulp-elf-as")
|
||||
set(CMAKE_OBJCOPY "esp32ulp-elf-objcopy")
|
||||
set(CMAKE_LINKER "esp32ulp-elf-ld")
|
||||
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
--mcpu=esp32s2 <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
|
||||
# Native CMake v2 ULP projects include cmakev2/idf.cmake before project(),
|
||||
# making idf_project_init visible when this toolchain is loaded. Legacy child
|
||||
# projects, even when launched by a CMake v2 parent, include the old IDF CMake
|
||||
# entrypoint and keep the historical explicit preprocessing path.
|
||||
set(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN OFF)
|
||||
if(IDF_BUILD_V2 AND COMMAND idf_project_init)
|
||||
set(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN ON)
|
||||
endif()
|
||||
|
||||
if(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN)
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT
|
||||
"${CMAKE_COMMAND} \
|
||||
-DULP_FSM_PREPROCESSOR=${CMAKE_C_COMPILER} \
|
||||
-DULP_FSM_ASSEMBLER=${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
-DULP_FSM_TARGET=esp32s2 \
|
||||
-DULP_FSM_SOURCE=<SOURCE> \
|
||||
-DULP_FSM_OBJECT=<OBJECT> \
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/preprocess_fsm_asm.cmake -- <DEFINES> <INCLUDES>")
|
||||
else()
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
--mcpu=esp32s2 <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
|
||||
endif()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-A elf32-esp32s2ulp -nostdlib" CACHE STRING "ULP Linker Base Flags")
|
||||
set(CMAKE_ASM_LINK_EXECUTABLE "${CMAKE_LINKER} <FLAGS> <CMAKE_ASM_LINK_FLAGS> \
|
||||
<LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||
|
||||
@@ -9,8 +9,28 @@ set(CMAKE_ASM_COMPILER "esp32ulp-elf-as")
|
||||
set(CMAKE_OBJCOPY "esp32ulp-elf-objcopy")
|
||||
set(CMAKE_LINKER "esp32ulp-elf-ld")
|
||||
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
--mcpu=esp32s3 <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
|
||||
# Native CMake v2 ULP projects include cmakev2/idf.cmake before project(),
|
||||
# making idf_project_init visible when this toolchain is loaded. Legacy child
|
||||
# projects, even when launched by a CMake v2 parent, include the old IDF CMake
|
||||
# entrypoint and keep the historical explicit preprocessing path.
|
||||
set(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN OFF)
|
||||
if(IDF_BUILD_V2 AND COMMAND idf_project_init)
|
||||
set(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN ON)
|
||||
endif()
|
||||
|
||||
if(ULP_PREPROCESS_FSM_ASM_IN_TOOLCHAIN)
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT
|
||||
"${CMAKE_COMMAND} \
|
||||
-DULP_FSM_PREPROCESSOR=${CMAKE_C_COMPILER} \
|
||||
-DULP_FSM_ASSEMBLER=${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
-DULP_FSM_TARGET=esp32s3 \
|
||||
-DULP_FSM_SOURCE=<SOURCE> \
|
||||
-DULP_FSM_OBJECT=<OBJECT> \
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/preprocess_fsm_asm.cmake -- <DEFINES> <INCLUDES>")
|
||||
else()
|
||||
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
|
||||
--mcpu=esp32s3 <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
|
||||
endif()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-A elf32-esp32s3ulp -nostdlib" CACHE STRING "ULP Linker Base Flags")
|
||||
set(CMAKE_ASM_LINK_EXECUTABLE "${CMAKE_LINKER} <FLAGS> <CMAKE_ASM_LINK_FLAGS> \
|
||||
<LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
if(IDF_BUILD_V2 AND __ULP_BUILD)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# ulp_embed_binary
|
||||
#
|
||||
# Create ULP binary and embed into the application.
|
||||
|
||||
function(__setup_ulp_project app_name project_path prefix type s_sources exp_dep_srcs)
|
||||
function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name type binary_names
|
||||
s_sources exp_dep_srcs)
|
||||
|
||||
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
set(ulp_cmake_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/cmake")
|
||||
set(sources "")
|
||||
spaces2list(s_sources)
|
||||
foreach(source ${s_sources})
|
||||
@@ -15,7 +21,7 @@ function(__setup_ulp_project app_name project_path prefix type s_sources exp_dep
|
||||
# In cmakev2, anchor the ULP sub-project's binary dir to the parent's
|
||||
# BUILD_DIR so it is not nested under the component that happened to
|
||||
# register it, and so that wiping the parent build dir removes the ULP
|
||||
# artifacts together with its editable sdkconfig (see -DSDKCONFIG below).
|
||||
# artifacts together with any child-owned sdkconfig.
|
||||
if(IDF_BUILD_V2)
|
||||
idf_build_get_property(build_dir BUILD_DIR)
|
||||
set(ulp_binary_dir "${build_dir}/subprojects/${app_name}")
|
||||
@@ -49,23 +55,32 @@ function(__setup_ulp_project app_name project_path prefix type s_sources exp_dep
|
||||
list(APPEND ps_sources ${ps_output})
|
||||
endforeach()
|
||||
|
||||
set(ulp_artifacts_prefix ${ulp_binary_dir}/${app_name})
|
||||
if(NOT binary_names)
|
||||
set(binary_names "${app_name}")
|
||||
endif()
|
||||
|
||||
set(ulp_artifacts ${ulp_artifacts_prefix}.bin
|
||||
${ulp_artifacts_prefix}.ld
|
||||
${ulp_artifacts_prefix}.h)
|
||||
# Full ULP subprojects may emit multiple binaries. Embed each declared
|
||||
# output in the main app so runtime code can choose which ULP program
|
||||
# to load.
|
||||
foreach(binary_name IN LISTS binary_names)
|
||||
set(ulp_artifacts_prefix ${ulp_binary_dir}/${binary_name})
|
||||
|
||||
set(ulp_artifacts_extras ${ulp_artifacts_prefix}.map
|
||||
${ulp_artifacts_prefix}.sym
|
||||
${ulp_binary_dir}/esp32.ulp.ld)
|
||||
list(APPEND ulp_artifacts
|
||||
${ulp_artifacts_prefix}.bin
|
||||
${ulp_artifacts_prefix}.ld
|
||||
${ulp_artifacts_prefix}.h)
|
||||
|
||||
list(APPEND ulp_artifacts_extras
|
||||
${ulp_artifacts_prefix}.map
|
||||
${ulp_artifacts_prefix}.sym
|
||||
${ulp_binary_dir}/${binary_name}.elf)
|
||||
endforeach()
|
||||
|
||||
# Replace the separator for the list of ULP source files that will be passed to
|
||||
# the external ULP project. This is a workaround to the bug https://public.kitware.com/Bug/view.php?id=16137.
|
||||
string(REPLACE ";" "|" ulp_s_sources "${ulp_s_sources}")
|
||||
|
||||
idf_build_get_property(sdkconfig SDKCONFIG)
|
||||
idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER)
|
||||
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
|
||||
idf_build_get_property(idf_path IDF_PATH)
|
||||
idf_build_get_property(idf_target IDF_TARGET)
|
||||
idf_build_get_property(python PYTHON)
|
||||
@@ -80,7 +95,7 @@ function(__setup_ulp_project app_name project_path prefix type s_sources exp_dep
|
||||
"Only FSM type is available for ULP on this target.")
|
||||
endif()
|
||||
endif()
|
||||
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-${idf_target}-ulp.cmake)
|
||||
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-${idf_target}-ulp.cmake)
|
||||
set(ULP_IS_RISCV OFF)
|
||||
elseif(IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3")
|
||||
# If both FSM and RISC-V are enabled in sdkconfig and a TYPE was
|
||||
@@ -90,95 +105,102 @@ function(__setup_ulp_project app_name project_path prefix type s_sources exp_dep
|
||||
message(STATUS "Both RISCV and FSM are enabled, using '${type}' toolchain for ${app_name} ULP project.")
|
||||
string(TOLOWER "${type}" type_lower)
|
||||
if(type_lower STREQUAL "riscv")
|
||||
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-ulp-riscv.cmake)
|
||||
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-ulp-riscv.cmake)
|
||||
elseif(type_lower STREQUAL "fsm")
|
||||
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-${idf_target}-ulp.cmake)
|
||||
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-${idf_target}-ulp.cmake)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid ULP_TYPE '${type}'; expected 'fsm' or 'riscv'.")
|
||||
endif()
|
||||
else()
|
||||
if(CONFIG_ULP_COPROC_TYPE_RISCV STREQUAL "y")
|
||||
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-ulp-riscv.cmake)
|
||||
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-ulp-riscv.cmake)
|
||||
else()
|
||||
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-${idf_target}-ulp.cmake)
|
||||
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-${idf_target}-ulp.cmake)
|
||||
endif()
|
||||
endif()
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE)
|
||||
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-lp-core-riscv.cmake)
|
||||
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-lp-core-riscv.cmake)
|
||||
endif()
|
||||
|
||||
set(ulp_project_args)
|
||||
if(IDF_BUILD_V2)
|
||||
externalproject_add(${app_name}
|
||||
SOURCE_DIR ${project_path}
|
||||
BINARY_DIR ${ulp_binary_dir}
|
||||
INSTALL_COMMAND ""
|
||||
CMAKE_ARGS -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
-DCMAKE_GENERATOR=${CMAKE_GENERATOR}
|
||||
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FLAG}
|
||||
-DULP_S_SOURCES=$<TARGET_PROPERTY:${app_name},ULP_SOURCES>
|
||||
-DULP_APP_NAME=${app_name}
|
||||
-DADD_PICOLIBC_SPECS=${CONFIG_LIBC_PICOLIBC}
|
||||
-DULP_VAR_PREFIX=${prefix}
|
||||
-DULP_TYPE=${type}
|
||||
-DCOMPONENT_DIR=${COMPONENT_DIR}
|
||||
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>
|
||||
-DIDF_TARGET=${idf_target}
|
||||
-DIDF_PATH=${idf_path}
|
||||
-DSDKCONFIG=${ulp_binary_dir}/sdkconfig
|
||||
-DSDKCONFIG_DEFAULTS=${sdkconfig}
|
||||
-DDEPENDENCIES_LOCK=${ulp_binary_dir}/dependencies.lock
|
||||
-DPYTHON=${python}
|
||||
-DPYTHON_DEPS_CHECKED=1
|
||||
-DCMAKE_MODULE_PATH=${idf_path}/components/ulp/cmake/
|
||||
-DIDF_CUSTOM_TOOLCHAIN=1
|
||||
${extra_cmake_args}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build ${ulp_binary_dir} --target build
|
||||
BUILD_BYPRODUCTS ${ulp_artifacts} ${ulp_artifacts_extras} ${ulp_ps_sources}
|
||||
${ulp_binary_dir}/${app_name}
|
||||
BUILD_ALWAYS 1
|
||||
)
|
||||
|
||||
externalproject_get_property(${app_name} BINARY_DIR)
|
||||
add_custom_target(menuconfig-${app_name}
|
||||
COMMAND ${CMAKE_COMMAND} --build ${BINARY_DIR} --target menuconfig
|
||||
DEPENDS ${app_name}-prefix/src/${app_name}-stamp/${app_name}-configure
|
||||
USES_TERMINAL
|
||||
)
|
||||
idf_register_menuconfig(NAME "ULP (${app_name})"
|
||||
TARGET menuconfig-${app_name})
|
||||
set(ulp_project_args
|
||||
--no-warn-unused-cli
|
||||
-DIDF_DEFAULT_PROJECT_NAME=${app_name}
|
||||
-DIDF_BUILD_V2=y
|
||||
# Internal marker for the ULP child project component graph.
|
||||
-D__ULP_BUILD=1
|
||||
-DIDF_PARENT_BUILD_DIR=${build_dir}
|
||||
-DULP_PREFIX_APPEND_BIN_NAME=${prefix_append_bin_name}
|
||||
-DSDKCONFIG=${sdkconfig}
|
||||
-DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
|
||||
-DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE}
|
||||
-DSDKCONFIG_DEFAULTS=
|
||||
-DGENERATE_SDKCONFIG=0
|
||||
-DDEPENDENCIES_LOCK=${ulp_binary_dir}/dependencies.lock
|
||||
# All ULP child builds use ULP-specific toolchain files today.
|
||||
# LP core and ULP RISC-V are GCC-based and could eventually
|
||||
# share more of the normal IDF app toolchain response-file
|
||||
# setup, but keep them under IDF_CUSTOM_TOOLCHAIN for now.
|
||||
-DIDF_CUSTOM_TOOLCHAIN=1)
|
||||
if(s_sources)
|
||||
list(APPEND ulp_project_args
|
||||
-DULP_S_SOURCES=$<TARGET_PROPERTY:${app_name},ULP_SOURCES>)
|
||||
endif()
|
||||
if(DEFINED COMPONENT_TARGET AND TARGET ${COMPONENT_TARGET})
|
||||
# Backward compatibility for existing ULP subprojects that
|
||||
# include headers from the parent component. New full
|
||||
# subprojects should declare their own component include
|
||||
# directories and dependencies instead.
|
||||
list(APPEND ulp_project_args
|
||||
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
endif()
|
||||
if(COMPONENT_DIR)
|
||||
list(APPEND ulp_project_args
|
||||
-DCOMPONENT_DIR=${COMPONENT_DIR})
|
||||
endif()
|
||||
else()
|
||||
externalproject_add(${app_name}
|
||||
SOURCE_DIR ${project_path}
|
||||
BINARY_DIR ${ulp_binary_dir}
|
||||
INSTALL_COMMAND ""
|
||||
CMAKE_ARGS -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
-DCMAKE_GENERATOR=${CMAKE_GENERATOR}
|
||||
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FLAG}
|
||||
-DULP_S_SOURCES=$<TARGET_PROPERTY:${app_name},ULP_SOURCES>
|
||||
-DULP_APP_NAME=${app_name}
|
||||
-DADD_PICOLIBC_SPECS=${CONFIG_LIBC_PICOLIBC}
|
||||
-DULP_VAR_PREFIX=${prefix}
|
||||
-DULP_TYPE=${type}
|
||||
-DCOMPONENT_DIR=${COMPONENT_DIR}
|
||||
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>
|
||||
-DIDF_TARGET=${idf_target}
|
||||
-DIDF_PATH=${idf_path}
|
||||
-DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
|
||||
-DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE}
|
||||
-DPYTHON=${python}
|
||||
-DCMAKE_MODULE_PATH=${idf_path}/components/ulp/cmake/
|
||||
${extra_cmake_args}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build ${ulp_binary_dir} --target build
|
||||
BUILD_BYPRODUCTS ${ulp_artifacts} ${ulp_artifacts_extras} ${ulp_ps_sources}
|
||||
${ulp_binary_dir}/${app_name}
|
||||
BUILD_ALWAYS 1
|
||||
)
|
||||
list(APPEND ulp_project_args
|
||||
-DULP_S_SOURCES=$<TARGET_PROPERTY:${app_name},ULP_SOURCES>
|
||||
-DULP_APP_NAME=${app_name}
|
||||
-DCOMPONENT_DIR=${COMPONENT_DIR}
|
||||
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>
|
||||
-DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
|
||||
-DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE})
|
||||
endif()
|
||||
|
||||
externalproject_add(${app_name}
|
||||
SOURCE_DIR ${project_path}
|
||||
BINARY_DIR ${ulp_binary_dir}
|
||||
INSTALL_COMMAND ""
|
||||
CMAKE_ARGS -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
-DCMAKE_GENERATOR=${CMAKE_GENERATOR}
|
||||
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FLAG}
|
||||
-DADD_PICOLIBC_SPECS=${CONFIG_LIBC_PICOLIBC}
|
||||
-DULP_VAR_PREFIX=${prefix}
|
||||
-DULP_TYPE=${type}
|
||||
${ulp_project_args}
|
||||
-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}
|
||||
${ulp_binary_dir}/${app_name}
|
||||
BUILD_ALWAYS 1
|
||||
)
|
||||
|
||||
# Only the CMake v1 path reads this property when passing ULP_S_SOURCES
|
||||
# to the child project. Leaving it set for v2 is harmless and keeps the
|
||||
# post-ExternalProject artifact wiring common. Can be dropped when
|
||||
# v1 support is dropped.
|
||||
set_property(TARGET ${app_name} PROPERTY ULP_SOURCES "${sources}")
|
||||
|
||||
spaces2list(exp_dep_srcs)
|
||||
set_source_files_properties(${exp_dep_srcs} PROPERTIES OBJECT_DEPENDS ${ulp_artifacts})
|
||||
if(exp_dep_srcs)
|
||||
set_source_files_properties(${exp_dep_srcs} PROPERTIES OBJECT_DEPENDS ${ulp_artifacts})
|
||||
endif()
|
||||
|
||||
include_directories(${ulp_binary_dir})
|
||||
|
||||
@@ -186,8 +208,10 @@ function(__setup_ulp_project app_name project_path prefix type s_sources exp_dep
|
||||
|
||||
add_dependencies(${COMPONENT_LIB} ${app_name}_artifacts)
|
||||
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE ${ulp_binary_dir}/${app_name}.ld)
|
||||
target_add_binary_data(${COMPONENT_LIB} ${ulp_binary_dir}/${app_name}.bin BINARY)
|
||||
foreach(binary_name IN LISTS binary_names)
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE ${ulp_binary_dir}/${binary_name}.ld)
|
||||
target_add_binary_data(${COMPONENT_LIB} ${ulp_binary_dir}/${binary_name}.bin BINARY)
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -212,6 +236,23 @@ function(validate_ulp_type ULP_TYPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(__ulp_resolve_type out_var type)
|
||||
# CMake v2 ULP subprojects receive an explicit ULP_TYPE argument because the
|
||||
# child project uses it to choose the component graph. CMake v1 legacy builds
|
||||
# keep the historical empty/uppercase TYPE handling in __setup_ulp_project.
|
||||
if(type)
|
||||
string(TOLOWER "${type}" resolved_type)
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_RISCV)
|
||||
set(resolved_type "riscv")
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE)
|
||||
set(resolved_type "lp_core")
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_FSM)
|
||||
set(resolved_type "fsm")
|
||||
endif()
|
||||
|
||||
set(${out_var} "${resolved_type}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(ulp_embed_binary app_name s_sources exp_dep_srcs)
|
||||
cmake_parse_arguments(ULP "" "PREFIX;TYPE" "" ${ARGN})
|
||||
if(NOT ULP_PREFIX)
|
||||
@@ -219,18 +260,38 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs)
|
||||
endif()
|
||||
|
||||
validate_ulp_type("${ULP_TYPE}")
|
||||
if(IDF_BUILD_V2)
|
||||
__ulp_resolve_type(ULP_TYPE "${ULP_TYPE}")
|
||||
endif()
|
||||
set(ulp_cmake_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/cmake")
|
||||
|
||||
__setup_ulp_project("${app_name}" "${idf_path}/components/ulp/cmake"
|
||||
"${ULP_PREFIX}" "${ULP_TYPE}" "${s_sources}" "${exp_dep_srcs}")
|
||||
__setup_ulp_project("${app_name}" "${ulp_cmake_dir}"
|
||||
"${ULP_PREFIX}" FALSE "${ULP_TYPE}"
|
||||
"${app_name}"
|
||||
"${s_sources}" "${exp_dep_srcs}")
|
||||
endfunction()
|
||||
|
||||
function(ulp_add_project app_name project_path)
|
||||
cmake_parse_arguments(ULP "" "PREFIX;TYPE" "" ${ARGN})
|
||||
cmake_parse_arguments(ULP "" "PREFIX;TYPE" "BINARIES" ${ARGN})
|
||||
if(NOT ULP_BINARIES)
|
||||
set(ULP_BINARIES "${app_name}")
|
||||
endif()
|
||||
|
||||
list(LENGTH ULP_BINARIES ULP_BINARY_COUNT)
|
||||
set(ULP_PREFIX_APPEND_BIN_NAME FALSE)
|
||||
if(IDF_BUILD_V2 AND ULP_BINARY_COUNT GREATER 1)
|
||||
set(ULP_PREFIX_APPEND_BIN_NAME TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT ULP_PREFIX)
|
||||
set(ULP_PREFIX "ulp_")
|
||||
endif()
|
||||
|
||||
validate_ulp_type("${ULP_TYPE}")
|
||||
if(IDF_BUILD_V2)
|
||||
__ulp_resolve_type(ULP_TYPE "${ULP_TYPE}")
|
||||
endif()
|
||||
|
||||
__setup_ulp_project("${app_name}" "${project_path}" "${ULP_PREFIX}" "${ULP_TYPE}" "" "")
|
||||
__setup_ulp_project("${app_name}" "${project_path}" "${ULP_PREFIX}"
|
||||
"${ULP_PREFIX_APPEND_BIN_NAME}" "${ULP_TYPE}" "${ULP_BINARIES}" "" "")
|
||||
endfunction()
|
||||
|
||||
158
tools/test_build_system/buildv2/test_ulp.py
Normal file
158
tools/test_build_system/buildv2/test_ulp.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from test_build_system_helpers import IdfPyFunc
|
||||
from test_build_system_helpers import replace_in_file
|
||||
|
||||
|
||||
@pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/lp_core')
|
||||
def test_ulp_full_project_regenerates_config_from_parent_sdkconfig(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
# Full ULP subprojects use the parent sdkconfig as their source of truth.
|
||||
# Changing the parent config should regenerate the child's sdkconfig.cmake.
|
||||
assert test_app_copy.exists()
|
||||
|
||||
sdkconfig = Path('build/sdkconfig')
|
||||
|
||||
idf_py('-DIDF_TARGET=esp32c6', '-DSDKCONFIG=build/sdkconfig', 'build')
|
||||
ulp_sdkconfig_cmake_files = sorted(Path('build/subprojects').glob('*/config/sdkconfig.cmake'))
|
||||
assert len(ulp_sdkconfig_cmake_files) == 1
|
||||
ulp_sdkconfig_cmake = ulp_sdkconfig_cmake_files[0]
|
||||
assert 'set(CONFIG_ULP_COPROC_RESERVE_MEM "4096")' in ulp_sdkconfig_cmake.read_text()
|
||||
|
||||
replace_in_file(sdkconfig, 'CONFIG_ULP_COPROC_RESERVE_MEM=4096', 'CONFIG_ULP_COPROC_RESERVE_MEM=8192')
|
||||
|
||||
idf_py('build')
|
||||
assert 'set(CONFIG_ULP_COPROC_RESERVE_MEM "8192")' in ulp_sdkconfig_cmake.read_text()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'target,subproject_dir,linked_artifact,custom_section,mapped_entry,symbol',
|
||||
(
|
||||
pytest.param(
|
||||
'esp32',
|
||||
'ulp_main',
|
||||
'ulp_main.sym',
|
||||
'.ulp_fsm_extra_data',
|
||||
'*libmain.a:counter.*(.ulp_fsm_extra_data .ulp_fsm_extra_data.*)',
|
||||
'ldgen_section_marker',
|
||||
marks=[pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/fsm')],
|
||||
id='fsm',
|
||||
),
|
||||
pytest.param(
|
||||
'esp32s2',
|
||||
'ulp_main',
|
||||
'ulp_main.map',
|
||||
'.ulp_riscv_extra_data',
|
||||
'*libmain.a:main.*(.ulp_riscv_extra_data .ulp_riscv_extra_data.*)',
|
||||
'ldgen_section_marker',
|
||||
marks=[pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/riscv')],
|
||||
id='riscv',
|
||||
),
|
||||
pytest.param(
|
||||
'esp32c6',
|
||||
'ulp_build_system_example',
|
||||
'ulp_build_system_example.map',
|
||||
'.ulp_math_fast',
|
||||
'*libulp_math.a:ulp_math.*(.ulp_math_fast .ulp_math_fast.*)',
|
||||
'ulp_math_multiply',
|
||||
marks=[pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/lp_core')],
|
||||
id='lp_core',
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_ulp_full_project_applies_component_ldgen_mapping(
|
||||
idf_py: IdfPyFunc,
|
||||
test_app_copy: Path,
|
||||
target: str,
|
||||
subproject_dir: str,
|
||||
linked_artifact: str,
|
||||
custom_section: str,
|
||||
mapped_entry: str,
|
||||
symbol: str,
|
||||
) -> None:
|
||||
# These examples declare component LDFRAGMENTS and target_linker_script()
|
||||
# templates. Build the ULP child project, then check that ldgen expanded the
|
||||
# template mapping and the custom section/symbol survived the ULP link.
|
||||
assert test_app_copy.exists()
|
||||
idf_py(f'-DIDF_TARGET={target}', '-DSDKCONFIG=build/sdkconfig', 'build')
|
||||
|
||||
ulp_project_dir = Path('build/subprojects') / subproject_dir
|
||||
processed_scripts = sorted(ulp_project_dir.glob('**/ulp_sections.ld_library_*'))
|
||||
assert processed_scripts
|
||||
assert any(mapped_entry in script.read_text(encoding='utf-8') for script in processed_scripts)
|
||||
|
||||
linked_output = (ulp_project_dir / linked_artifact).read_text(encoding='utf-8')
|
||||
assert custom_section in linked_output
|
||||
assert symbol in linked_output
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'target,ulp_project_cmake,subproject_dir,project_replacement,enabled_languages,disabled_languages',
|
||||
(
|
||||
pytest.param(
|
||||
'esp32',
|
||||
'main/ulp/CMakeLists.txt',
|
||||
'ulp_main',
|
||||
None,
|
||||
('ASM',),
|
||||
('C', 'CXX'),
|
||||
marks=[pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/fsm')],
|
||||
id='fsm_asm_only',
|
||||
),
|
||||
pytest.param(
|
||||
'esp32s2',
|
||||
'main/ulp/CMakeLists.txt',
|
||||
'ulp_main',
|
||||
('project(${IDF_DEFAULT_PROJECT_NAME} C CXX ASM)', 'project(${IDF_DEFAULT_PROJECT_NAME} C ASM)'),
|
||||
('C', 'ASM'),
|
||||
('CXX',),
|
||||
marks=[pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/riscv')],
|
||||
id='riscv_c_asm',
|
||||
),
|
||||
pytest.param(
|
||||
'esp32c6',
|
||||
'main/ulp/CMakeLists.txt',
|
||||
'ulp_build_system_example',
|
||||
('project(${IDF_DEFAULT_PROJECT_NAME} C CXX ASM)', 'project(${IDF_DEFAULT_PROJECT_NAME} C ASM)'),
|
||||
('C', 'ASM'),
|
||||
('CXX',),
|
||||
marks=[pytest.mark.test_app_copy('tools/test_apps/system/ulp/full_subproject/lp_core')],
|
||||
id='lp_core_c_asm',
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_ulp_full_project_respects_child_project_enabled_languages(
|
||||
idf_py: IdfPyFunc,
|
||||
test_app_copy: Path,
|
||||
target: str,
|
||||
ulp_project_cmake: str,
|
||||
subproject_dir: str,
|
||||
project_replacement: tuple[str, str] | None,
|
||||
enabled_languages: tuple[str, ...],
|
||||
disabled_languages: tuple[str, ...],
|
||||
) -> None:
|
||||
# The ULP child project should use the languages declared by its own
|
||||
# project() call. FSM can build as an ASM-only project, while RISC-V and
|
||||
# LP-core ULP projects do not need CXX when their child project only enables
|
||||
# C and ASM.
|
||||
if project_replacement is not None:
|
||||
replace_in_file(test_app_copy / ulp_project_cmake, project_replacement[0], project_replacement[1])
|
||||
ulp_project_cmake_path = test_app_copy / ulp_project_cmake
|
||||
ulp_project_cmake_path.write_text(
|
||||
ulp_project_cmake_path.read_text(encoding='utf-8')
|
||||
+ '\nget_property(ulp_enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)\n'
|
||||
+ 'file(WRITE "${CMAKE_BINARY_DIR}/enabled_languages.txt" "${ulp_enabled_languages}\\n")\n',
|
||||
encoding='utf-8',
|
||||
)
|
||||
|
||||
idf_py(f'-DIDF_TARGET={target}', '-DSDKCONFIG=build/sdkconfig', 'build')
|
||||
|
||||
child_languages = (
|
||||
(Path('build/subprojects') / subproject_dir / 'enabled_languages.txt').read_text(encoding='utf-8').strip()
|
||||
)
|
||||
for language in enabled_languages:
|
||||
assert language in child_languages.split(';')
|
||||
for language in disabled_languages:
|
||||
assert language not in child_languages.split(';')
|
||||
Reference in New Issue
Block a user