diff --git a/Kconfig b/Kconfig index 5ba808b014..3fbc29f2f8 100644 --- a/Kconfig +++ b/Kconfig @@ -370,6 +370,27 @@ mainmenu "Espressif IoT Development Framework Configuration" endchoice + config COMPILER_ENABLE_RISCV_ZCMP + bool "Enable RISCV ZCMP extension" + depends on SOC_CPU_ZCMP_WORKAROUND + default n + help + Enable the RISC-V ZCMP (Compressed Macro) extension to reduce binary size + by optimizing function prologue and epilogue sequences. + + Note: Due to a hardware issue on some ESP32 chips (e.g., ESP32C5, ESP32C61, + ESP32H4), executing "cm.push" may re-enable interrupts even when global + interrupts are disabled (mstatus.mie = 0). This can cause unexpected interrupts + during CPU retention or within critical sections. + + Workarounds are implemented in the IDF codebase. However, if user code + directly disables interrupts, additional actions may be required. Refer + to code examples under the SOC_CPU_ZCMP_WORKAROUND macro, or disable + the ZCMP extension for source files that contain functions which may + execute while mstatus.mie = 0. + + Even with these workarounds, the issue may still affect dual-core variants. + choice COMPILER_OPTIMIZATION_ASSERTION_LEVEL prompt "Assertion level" default COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 911db5057e..a084e3498f 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -205,17 +205,8 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/soc/${target}") ) endif() -if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) - if(CMAKE_C_COMPILER_ID MATCHES "GNU") - # 1. Set xespv2p1 explicitly to override the default xespv2p2. - # 2. Remove zc* extensions: - # The ESP32-P4 has always supported the zc* extensions, - # but revisions earlier than v3.0 are affected by hardware issue DIG-661 - # and lack the mintthresh_csr register needed for the workaround. - idf_build_set_property(COMPILE_OPTIONS "-march=rv32imafc_zicsr_zifencei_zaamo_zalrsc_xesploop_xespv2p1" APPEND) - endif() -elseif(CONFIG_IDF_TARGET_ESP32P4) - if(CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO: LLVM-478 +if(NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3 AND CONFIG_IDF_TARGET_ESP32P4) + if(CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO: LLVM-478 IDF-14338 message(FATAL_ERROR "ESP32-P4 rev. 3.0 or higher is not supported in Clang-based toolchain") endif() endif() diff --git a/components/esp_libc/CMakeLists.txt b/components/esp_libc/CMakeLists.txt index 9aaebf5825..02a03423b5 100644 --- a/components/esp_libc/CMakeLists.txt +++ b/components/esp_libc/CMakeLists.txt @@ -136,8 +136,6 @@ if(CONFIG_LIBC_NEWLIB_NANO_FORMAT) ) get_filename_component(libc_dir ${libc_dir} DIRECTORY) target_link_directories(${COMPONENT_LIB} INTERFACE "${libc_dir}/nano") - else() - target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs") endif() endif() diff --git a/components/esp_libc/project_include.cmake b/components/esp_libc/project_include.cmake index 6292237846..e365170283 100644 --- a/components/esp_libc/project_include.cmake +++ b/components/esp_libc/project_include.cmake @@ -1,3 +1,23 @@ -if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) - idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND) +if(CONFIG_IDF_TOOLCHAIN_GCC) + if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mdisable-hardware-atomics") + else() + idf_toolchain_remove_flags(COMPILE_OPTIONS "-mdisable-hardware-atomics") + endif() + + if(CONFIG_LIBC_PICOLIBC) + idf_toolchain_add_flags(COMPILE_OPTIONS "-specs=picolibc.specs") + else() + idf_toolchain_remove_flags(COMPILE_OPTIONS "-specs=picolibc.specs") + endif() + + if(CONFIG_LIBC_NEWLIB_NANO_FORMAT) + idf_toolchain_add_flags(LINK_OPTIONS "--specs=nano.specs") + else() + idf_toolchain_remove_flags(LINK_OPTIONS "--specs=nano.specs") + endif() +else() # TODO IDF-14338 + if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) + idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND) + endif() endif() diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt index cee5723b8d..72e42a0977 100644 --- a/components/esp_psram/CMakeLists.txt +++ b/components/esp_psram/CMakeLists.txt @@ -50,7 +50,8 @@ if(CONFIG_SPIRAM) endif() -if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) +# TODO IDF-14338 +if(CONFIG_IDF_TOOLCHAIN_CLANG AND CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) # Note: Adding as a PUBLIC compile option here causes this option to propagate to all # components that depend on esp_psram. # diff --git a/components/esp_psram/project_include.cmake b/components/esp_psram/project_include.cmake index 4e77c0389e..aa9ff60758 100644 --- a/components/esp_psram/project_include.cmake +++ b/components/esp_psram/project_include.cmake @@ -1,17 +1,34 @@ -if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) - # We do this here as well as in CMakeLists.txt, because targets that - # are not part of the ESP-IDF build system (for cases where a generic - # non-IDF CMakeLists.txt file is imported into a component) don't depend - # on the esp32 component so don't get the extra flag. This handles that case. - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue" APPEND) - # note that we don't need to set link options as the library linked is independent of this - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=dupldst" APPEND) +if(CONFIG_IDF_TOOLCHAIN_GCC) + # Remove all "-mfix-esp32-psram-cache*" from toolchain flags + # that may have appeared during configuration changes. + idf_toolchain_remove_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache") + if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue") + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=dupldst") + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=memw") + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=nops") + endif() endif() - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=memw" APPEND) - endif() - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=nops" APPEND) +else() + if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) + # We do this here as well as in CMakeLists.txt, because targets that + # are not part of the ESP-IDF build system (for cases where a generic + # non-IDF CMakeLists.txt file is imported into a component) don't depend + # on the esp32 component so don't get the extra flag. This handles that case. + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue" APPEND) + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=dupldst" APPEND) + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=memw" APPEND) + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=nops" APPEND) + endif() endif() endif() diff --git a/components/riscv/project_include.cmake b/components/riscv/project_include.cmake deleted file mode 100644 index b50a98454d..0000000000 --- a/components/riscv/project_include.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# avoid esp-clang "unused-command-line-argument" warning -if(NOT (CMAKE_C_COMPILER_ID MATCHES "Clang") ) - set(compile_options "-nostartfiles") - idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND) -endif() diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 0614bb3f3e..5ba8c1c92b 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -487,6 +487,14 @@ config SOC_CPU_ZCMP_WORKAROUND bool default y +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_DS_SIGNATURE_MAX_BIT_LEN int default 3072 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 08711e7be8..03a20df79c 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -183,6 +183,8 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 #define SOC_CPU_ZCMP_WORKAROUND 1 +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ /** The maximum length of a Digital Signature in bits. */ diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 50f5015b38..c36aa2493d 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -375,6 +375,14 @@ config SOC_CPU_ZCMP_WORKAROUND bool default y +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 94d31afaf8..7b46369c53 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -150,6 +150,8 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 #define SOC_CPU_ZCMP_WORKAROUND 1 +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 /*-------------------------- DMA Common CAPS ----------------------------------------*/ #define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index c6463d26dd..2b87bc70da 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -247,10 +247,26 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_HAS_ZC_EXTENSIONS + bool + default y + +config SOC_CPU_HAS_ZB_EXTENSIONS + bool + default y + config SOC_CPU_ZCMP_WORKAROUND bool default y +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 0d962b197a..8e63145983 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -175,7 +175,12 @@ #define SOC_HP_CPU_HAS_MULTIPLE_CORES 1 // Convenience boolean macro used to determine if a target has multiple cores. #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_HAS_ZC_EXTENSIONS 1 +#define SOC_CPU_HAS_ZB_EXTENSIONS 1 + #define SOC_CPU_ZCMP_WORKAROUND 1 +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 /*-------------------------- DMA Common CAPS ----------------------------------------*/ #define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 2d01e0849f..237d9c797a 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -591,6 +591,18 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_HAS_ZC_EXTENSIONS + bool + default y + +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_SIMD_PREFERRED_DATA_ALIGNMENT int default 16 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 439c124d2d..43c729d583 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -209,6 +209,11 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_HAS_ZC_EXTENSIONS 1 + +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 + #define SOC_SIMD_PREFERRED_DATA_ALIGNMENT 16 // The preferred data alignment accepted by the SIMD instructions, in bytes /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake new file mode 100644 index 0000000000..624e16fbcb --- /dev/null +++ b/components/soc/project_include.cmake @@ -0,0 +1,109 @@ +if(CONFIG_IDF_TOOLCHAIN_GCC) + # Common flags + idf_toolchain_add_flags(LINK_OPTIONS "-nostartfiles") + + # Target-specific flags + if(CONFIG_IDF_TARGET_ESP32) + idf_toolchain_add_flags(COMPILE_OPTIONS "-Wno-frame-address") + elseif(CONFIG_IDF_TARGET_ESP32C2 OR + CONFIG_IDF_TARGET_ESP32C3) + set(_march "rv32imc_zicsr_zifencei") + elseif(CONFIG_IDF_TARGET_ESP32C5 OR + CONFIG_IDF_TARGET_ESP32C6 OR + CONFIG_IDF_TARGET_ESP32C61 OR + CONFIG_IDF_TARGET_ESP32H2 OR + CONFIG_IDF_TARGET_ESP32H21) + set(_march "rv32imac_zicsr_zifencei_zaamo_zalrsc") + elseif(CONFIG_IDF_TARGET_ESP32H4) + set(_march "rv32imafcb_zicsr_zifencei_zaamo_zalrsc") + elseif(CONFIG_IDF_TARGET_ESP32P4) + set(_march "rv32imafc_zicsr_zifencei_zaamo_zalrsc") + elseif(NOT(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3)) + message(FATAL_ERROR "Unknown Espressif target: ${CONFIG_IDF_TARGET}") + endif() + + # Architecture-specific flags + if(CONFIG_IDF_TARGET_ARCH_XTENSA) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mlongcalls" + "-fno-builtin-memcpy" + "-fno-builtin-memset" + "-fno-builtin-bzero") + elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + if(NOT DEFINED _march) + message(FATAL_ERROR "-march option is not defined for target ${CONFIG_IDF_TARGET}!") + endif() + + # Clean compile options that were added by previous configurations and may be outdated + idf_toolchain_remove_flags(COMPILE_OPTIONS "-march=" + "-mno-cm-push-reverse" + "-mno-cm-popret") + + if(CONFIG_SOC_CPU_HAS_ZB_EXTENSIONS) + set(_march "${_march}_zba_zbb_zbs") + endif() + + if((CONFIG_SOC_CPU_HAS_ZC_EXTENSIONS AND NOT CONFIG_SOC_CPU_ZCMP_WORKAROUND) OR + CONFIG_COMPILER_ENABLE_RISCV_ZCMP) + if(NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + set(_march "${_march}_zcb_zcmp_zcmt") + + if(CONFIG_SOC_CPU_ZCMP_PUSH_REVERSED) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mno-cm-push-reverse") + endif() + if(CONFIG_SOC_CPU_ZCMP_POPRET_ISSUE) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mno-cm-popret") + endif() + endif() + endif() + + if(CONFIG_SOC_CPU_HAS_HWLOOP) + set(_march "${_march}_xesploop") + endif() + + if(CONFIG_SOC_CPU_HAS_PIE) + set(_march "${_march}_xespv") + if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + set(_march "${_march}2p1") + endif() + endif() + + if(CONFIG_SOC_CPU_HAS_DSP) + set(_march "${_march}_xespdsp") + endif() + + # Set ABI and ARCH options + if(CONFIG_SOC_CPU_HAS_FPU) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mabi=ilp32f") + endif() + idf_toolchain_add_flags(COMPILE_OPTIONS "-march=${_march}") + + if(NOT CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mtune=esp-base") + endif() + else() + message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}") + endif() + + # Workaround: Re-run CMake compiler ABI detection after ABI flags are set. + # + # Problem: CMake performs compiler checks at an early stage during + # toolchain.cmake processing. At this early stage, response files are not yet + # ready, which causes CMake paths (e.g., CMAKE__IMPLICIT_LINK_DIRECTORIES) + # to be incorrectly determined. + # + # Solution: Re-run the ABI detection after ABI flags are present to correctly + # determine these paths. + # + # Note: If the CMake API changes, this solution may need to be revised. + set(lang_ext_pairs "C|c" "CXX|cpp") + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + foreach(lang_ext ${lang_ext_pairs}) + string(REPLACE "|" ";" lang_ext_parts ${lang_ext}) + list(GET lang_ext_parts 0 lang) + list(GET lang_ext_parts 1 ext) + if(DEFINED CMAKE_${lang}_ABI_COMPILED) + unset(CMAKE_${lang}_ABI_COMPILED) + cmake_determine_compiler_abi(${lang} ${CMAKE_ROOT}/Modules/CMake${lang}CompilerABI.${ext}) + endif() + endforeach() +endif() diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index d8bcd76b7a..5fc8159977 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -1054,10 +1054,6 @@ Obviously, there are cases where all these recipes are insufficient for a certai - The second set of commands adds a library target, which points to the "imported" library file built by the external system. Some properties need to be set in order to add include directories and tell CMake where this file is. - Finally, the generated library is added to `ADDITIONAL_CLEAN_FILES`_. This means ``make clean`` will delete this library. (Note that the other object files from the build won't be deleted.) -.. only:: esp32 - - .. note:: When using an external build process with PSRAM, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag. - .. _ADDITIONAL_CLEAN_FILES_note: diff --git a/docs/en/api-guides/performance/size.rst b/docs/en/api-guides/performance/size.rst index 23c0b1e196..3731368ae7 100644 --- a/docs/en/api-guides/performance/size.rst +++ b/docs/en/api-guides/performance/size.rst @@ -91,6 +91,7 @@ The following configuration options reduces the final binary size of almost any - Setting :ref:`CONFIG_ESP_SYSTEM_PANIC` to ``Silent reboot`` saves a small amount of binary size, however this is **only** recommended if no one will use UART output to debug the device. :CONFIG_IDF_TARGET_ARCH_RISCV: - Setting :ref:`CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS` reduces binary size by replacing inlined prologues/epilogues with library calls. - If the application binary uses only one of the security versions of the protocomm component, then the support for others can be disabled to save some code size. The support can be disabled through :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0`, :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1` or :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2` respectively. + :CONFIG_SOC_CPU_ZCMP_WORKAROUND: - Enable :ref:`CONFIG_COMPILER_ENABLE_RISCV_ZCMP` to reduce binary size by using compressed function prologues/epilogues. Read the :ref:`CONFIG_COMPILER_ENABLE_RISCV_ZCMP` notes carefully before enabling this option! .. note:: diff --git a/docs/zh_CN/api-guides/build-system.rst b/docs/zh_CN/api-guides/build-system.rst index c88434b601..fdcd0024b3 100644 --- a/docs/zh_CN/api-guides/build-system.rst +++ b/docs/zh_CN/api-guides/build-system.rst @@ -1054,10 +1054,6 @@ ESP-IDF 还支持自动生成链接脚本,它允许组件通过链接片段文 - 第二组命令添加了一个目标库,指向外部构建系统生成的库文件。为了添加 include 目录,并告知 CMake 该文件的位置,需要再设置一些属性。 - 最后,生成的库被添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 中。即执行 ``make clean`` 后会删除该库。请注意,构建系统中的其他目标文件不会被删除。 -.. only:: esp32 - - .. note:: 当外部构建系统使用 PSRAM 时,请记得将 ``-mfix-esp32-psram-cache-issue`` 添加到 C 编译器的参数中。关于该标志的更多详细信息,请参考 :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`。 - .. _ADDITIONAL_MAKE_CLEAN_FILES_note: diff --git a/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp b/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp index 0e9ecb3ba4..069296cb03 100644 --- a/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp +++ b/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp @@ -7,7 +7,6 @@ #include "esp_log.h" #include "esp_vfs_fat.h" #include "tinyxml2.h" -#include "sdkconfig.h" // TODO IDF-11323: remove static const char *TAG = "example"; @@ -30,12 +29,11 @@ extern "C" void app_main(void) tinyxml2::XMLDocument data; data.LoadFile("/spiflash/sample.xml"); -#if !CONFIG_LIBC_PICOLIBC // TODO IDF-11323: subproject builds with default toolchain-esp*.cmake. No additional -specs=picolibc.specs applied tinyxml2::XMLPrinter printer; data.Print(&printer); ESP_LOGI(TAG, "Read XML data:\n%s", printer.CStr()); -#endif + const char* to_data = data.FirstChildElement("note")->FirstChildElement("to")->GetText(); const char* from_data = data.FirstChildElement("note")->FirstChildElement("from")->GetText(); const char* heading_data = data.FirstChildElement("note")->FirstChildElement("heading")->GetText(); diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index 3ba5875682..b0eb39d715 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -885,13 +885,6 @@ macro(project project_name) unset(idf_target) endif() - - if(CONFIG_LIBC_PICOLIBC) - idf_build_set_property(C_COMPILE_OPTIONS "-specs=picolibc.specs" APPEND) - idf_build_set_property(CXX_COMPILE_OPTIONS "-specs=picolibcpp.specs" APPEND) - idf_build_set_property(LINK_OPTIONS "-specs=picolibc.specs" APPEND) - endif() - set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${mapfile}" "${project_elf_src}") diff --git a/tools/cmake/targets.cmake b/tools/cmake/targets.cmake index e4c3f195b1..aa4c85c0e2 100644 --- a/tools/cmake/targets.cmake +++ b/tools/cmake/targets.cmake @@ -1,3 +1,4 @@ +include(${CMAKE_CURRENT_LIST_DIR}/toolchain_flags.cmake) # # Get target from single sdkconfig file # @@ -71,7 +72,7 @@ endfunction() # Set the target used for the standard project build. # macro(__target_init config_file) - # Input is IDF_TARGET environement variable + # Input is IDF_TARGET environment variable set(env_idf_target $ENV{IDF_TARGET}) if(NOT env_idf_target) @@ -129,30 +130,30 @@ macro(__target_set_toolchain) set(env_idf_toolchain $ENV{IDF_TOOLCHAIN}) if(NOT env_idf_toolchain) # IDF_TOOLCHAIN not set in environment, see if it is set in cache - if(IDF_TOOLCHAIN) - set(env_idf_toolchain ${IDF_TOOLCHAIN}) - else() - set(env_idf_toolchain gcc) - endif() - elseif(DEFINED CACHE{IDF_TOOLCHAIN}) - # IDF_TOOLCHAIN set both in environment and in cache, must be the same - if(NOT $CACHE{IDF_TOOLCHAIN} STREQUAL ${env_idf_toolchain}) - message(FATAL_ERROR " IDF_TOOLCHAIN '$CACHE{IDF_TOOLCHAIN}' in CMake cache does not match" - " currently selected IDF_TOOLCHAIN '${env_idf_toolchain}'. To change the toolchain, clear" - " the build directory and sdkconfig file, and build the project again.") + set(env_idf_toolchain ${IDF_TOOLCHAIN}) + if(NOT env_idf_toolchain) + set(env_idf_toolchain "gcc") endif() endif() - # Finally, set IDF_TOOLCHAIN in cache - set(IDF_TOOLCHAIN ${env_idf_toolchain} CACHE STRING "IDF Build Toolchain Type") + if(DEFINED CACHE{IDF_TOOLCHAIN} AND NOT "$CACHE{IDF_TOOLCHAIN}" STREQUAL "${env_idf_toolchain}") + # IDF_TOOLCHAIN set both in environment and in cache, must be the same + message(FATAL_ERROR " IDF_TOOLCHAIN '$CACHE{IDF_TOOLCHAIN}' in CMake cache does not match" + " currently selected IDF_TOOLCHAIN '${env_idf_toolchain}'. To change the toolchain, clear" + " the build directory and sdkconfig file, and build the project again.") + endif() if(${env_idf_toolchain} STREQUAL "clang") - set(toolchain_type "clang-") + # TODO IDF-14338: remove the line below since it will be set in toolchain.cmake + set(IDF_TOOLCHAIN ${env_idf_toolchain} CACHE STRING "IDF Build Toolchain Type") + set(toolchain_filename "toolchain-clang-${IDF_TARGET}.cmake") + else() + set(toolchain_filename "toolchain-${IDF_TARGET}.cmake") endif() # Check if selected target is consistent with toolchain file in CMake cache if(DEFINED CMAKE_TOOLCHAIN_FILE) - string(FIND "${CMAKE_TOOLCHAIN_FILE}" "-${toolchain_type}${IDF_TARGET}.cmake" found) + string(FIND "${CMAKE_TOOLCHAIN_FILE}" "${toolchain_filename}" found) if(${found} EQUAL -1) get_filename_component(toolchain "${CMAKE_TOOLCHAIN_FILE}" NAME_WE) message(FATAL_ERROR " CMAKE_TOOLCHAIN_FILE '${toolchain}'" @@ -162,11 +163,9 @@ macro(__target_set_toolchain) endif() endif() - # First try to load the toolchain file from the tools/cmake/directory of IDF - set(toolchain_file_global ${idf_path}/tools/cmake/toolchain-${toolchain_type}${IDF_TARGET}.cmake) - if(EXISTS ${toolchain_file_global}) - set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global}) - else() - message(FATAL_ERROR "Toolchain file ${toolchain_file_global} not found") + # Check if generated toolchain filepath is correct + set(CMAKE_TOOLCHAIN_FILE "${idf_path}/tools/cmake/${toolchain_filename}") + if(NOT EXISTS ${CMAKE_TOOLCHAIN_FILE}) + message(FATAL_ERROR "Toolchain file ${CMAKE_TOOLCHAIN_FILE} not found") endif() endmacro() diff --git a/tools/cmake/toolchain-esp32.cmake b/tools/cmake/toolchain-esp32.cmake index afec940e25..8c1e461e2e 100644 --- a/tools/cmake/toolchain-esp32.cmake +++ b/tools/cmake/toolchain-esp32.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER xtensa-esp32-elf-gcc) -set(CMAKE_CXX_COMPILER xtensa-esp32-elf-g++) -set(CMAKE_ASM_COMPILER xtensa-esp32-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS - "-mlongcalls -Wno-frame-address -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${CMAKE_EXE_LINKER_FLAGS}" UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c2.cmake b/tools/cmake/toolchain-esp32c2.cmake index 4f21adc72e..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32c2.cmake +++ b/tools/cmake/toolchain-esp32c2.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imc_zicsr_zifencei") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c3.cmake b/tools/cmake/toolchain-esp32c3.cmake index 4f21adc72e..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32c3.cmake +++ b/tools/cmake/toolchain-esp32c3.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imc_zicsr_zifencei") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c5.cmake b/tools/cmake/toolchain-esp32c5.cmake index e84b261e68..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32c5.cmake +++ b/tools/cmake/toolchain-esp32c5.cmake @@ -1,24 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt \ - -mno-cm-popret -mno-cm-push-reverse") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c6.cmake b/tools/cmake/toolchain-esp32c6.cmake index ccfa5a60ed..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32c6.cmake +++ b/tools/cmake/toolchain-esp32c6.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c61.cmake b/tools/cmake/toolchain-esp32c61.cmake index e84b261e68..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32c61.cmake +++ b/tools/cmake/toolchain-esp32c61.cmake @@ -1,24 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt \ - -mno-cm-popret -mno-cm-push-reverse") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32h2.cmake b/tools/cmake/toolchain-esp32h2.cmake index ccfa5a60ed..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32h2.cmake +++ b/tools/cmake/toolchain-esp32h2.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32h21.cmake b/tools/cmake/toolchain-esp32h21.cmake index ccfa5a60ed..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32h21.cmake +++ b/tools/cmake/toolchain-esp32h21.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32h4.cmake b/tools/cmake/toolchain-esp32h4.cmake index c4937c4ab5..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32h4.cmake +++ b/tools/cmake/toolchain-esp32h4.cmake @@ -1,25 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imafcb_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt_zba_zbb_zbs_xespdsp \ - -mabi=ilp32f \ - -mno-cm-popret -mno-cm-push-reverse") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32p4.cmake b/tools/cmake/toolchain-esp32p4.cmake index 33751e1af4..9833188d7d 100644 --- a/tools/cmake/toolchain-esp32p4.cmake +++ b/tools/cmake/toolchain-esp32p4.cmake @@ -1,25 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imafc_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt_xesploop_xespv \ - -mabi=ilp32f \ - -mno-cm-popret -mno-cm-push-reverse") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32s2.cmake b/tools/cmake/toolchain-esp32s2.cmake index b0763bde62..74922e28dd 100644 --- a/tools/cmake/toolchain-esp32s2.cmake +++ b/tools/cmake/toolchain-esp32s2.cmake @@ -1,22 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER xtensa-esp32s2-elf-gcc) -set(CMAKE_CXX_COMPILER xtensa-esp32s2-elf-g++) -set(CMAKE_ASM_COMPILER xtensa-esp32s2-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32s2-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-mlongcalls -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${CMAKE_EXE_LINKER_FLAGS}" UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32s3.cmake b/tools/cmake/toolchain-esp32s3.cmake index 50dd2d684a..2deb82c2ac 100644 --- a/tools/cmake/toolchain-esp32s3.cmake +++ b/tools/cmake/toolchain-esp32s3.cmake @@ -1,22 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER xtensa-esp32s3-elf-gcc) -set(CMAKE_CXX_COMPILER xtensa-esp32s3-elf-g++) -set(CMAKE_ASM_COMPILER xtensa-esp32s3-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32s3-elf-) - -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-mlongcalls -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero") - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles ${CMAKE_EXE_LINKER_FLAGS}" UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain.cmake b/tools/cmake/toolchain.cmake new file mode 100644 index 0000000000..db1f80181b --- /dev/null +++ b/tools/cmake/toolchain.cmake @@ -0,0 +1,85 @@ +include(${CMAKE_CURRENT_LIST_DIR}/toolchain_flags.cmake) + +if(NOT CMAKE_PARENT_LIST_FILE) + message(FATAL_ERROR "toolchain.cmake cannot be used standalone (use chip-specific toolchain file instead)") +endif() + +# Paths normalization +get_filename_component(_idf_toolchain_dir "$ENV{IDF_PATH}/tools/cmake" REALPATH) +file(TO_CMAKE_PATH "${_idf_toolchain_dir}" _idf_toolchain_dir) + +get_filename_component(_toolchain_filename "${CMAKE_TOOLCHAIN_FILE}" NAME) +get_filename_component(_current_toolchain_dir "${CMAKE_TOOLCHAIN_FILE}" DIRECTORY REALPATH) +file(TO_CMAKE_PATH "${_current_toolchain_dir}" _current_toolchain_dir) + +set(CMAKE_SYSTEM_NAME Generic) + +# Set compiler tools according to the toolchain type +string(FIND "${_toolchain_filename}" "clang" found_clang) +if(NOT found_clang EQUAL -1) + set(IDF_TOOLCHAIN "clang" CACHE STRING "IDF Build Toolchain Type" FORCE) + + set(CMAKE_C_COMPILER clang) + set(CMAKE_CXX_COMPILER clang++) + set(CMAKE_ASM_COMPILER clang) + set(CMAKE_LINKER ${_CMAKE_TOOLCHAIN_PREFIX}ld) + set(CMAKE_AR llvm-ar) + set(CMAKE_RANLIB llvm-ranlib) + set(CMAKE_OBJDUMP ${_CMAKE_TOOLCHAIN_PREFIX}objdump) +else() + set(IDF_TOOLCHAIN "gcc" CACHE STRING "IDF Build Toolchain Type" FORCE) + + set(CMAKE_C_COMPILER ${_CMAKE_TOOLCHAIN_PREFIX}gcc) + set(CMAKE_CXX_COMPILER ${_CMAKE_TOOLCHAIN_PREFIX}g++) + set(CMAKE_ASM_COMPILER ${_CMAKE_TOOLCHAIN_PREFIX}gcc) +endif() + +# Handle different execution contexts for the toolchain file. +# CMake may execute this toolchain file in different contexts: +# +# 1. First execution (IDF project build): +# When CMAKE_TOOLCHAIN_FILE points to IDF sources, the toolchain file is +# executed for the main project. In this case, we create the response files +# directory in the build directory, copy the toolchain file there, initialize +# the response files, and update CMAKE_TOOLCHAIN_FILE to point to the copy. +# +# 2. Subsequent executions (External project builds): +# When CMAKE_TOOLCHAIN_FILE points to a copied toolchain file (from a +# previous root project build), the response files already exist in the same +# directory as the toolchain file. We simply set IDF_TOOLCHAIN_BUILD_DIR to +# point to that existing directory. +if(_idf_toolchain_dir STREQUAL _current_toolchain_dir) + set(IDF_TOOLCHAIN_BUILD_DIR "${CMAKE_BINARY_DIR}/toolchain" + CACHE PATH "Path to toolchain build directory containing response files and toolchain file copy" FORCE) + + # Copy toolchain file into the build directory and update CMAKE_TOOLCHAIN_FILE + # to point to the copy. This approach allows us to avoid worrying about different + # CMAKE_BINARY_DIR values between base IDF-project builds and external projects. + # For external project builds, compiler response files are located in the same + # directory as CMAKE_TOOLCHAIN_FILE, making them easy to find. + file(MAKE_DIRECTORY "${IDF_TOOLCHAIN_BUILD_DIR}") + file(COPY "${CMAKE_TOOLCHAIN_FILE}" DESTINATION "${IDF_TOOLCHAIN_BUILD_DIR}") + set(CMAKE_TOOLCHAIN_FILE "${IDF_TOOLCHAIN_BUILD_DIR}/${_toolchain_filename}") + + # Create response files before CMake performs compiler checks. + # These files are required for the compiler detection process to succeed. + # The files are created even when the flag variables are empty, ensuring + # they exist when referenced by CMAKE_*_FLAGS variables below. + idf_toolchain_add_flags(C_COMPILE_OPTIONS "${CMAKE_C_FLAGS}" + CXX_COMPILE_OPTIONS "${CMAKE_CXX_FLAGS}" + ASM_COMPILE_OPTIONS "${CMAKE_ASM_FLAGS}" + LINK_OPTIONS "${CMAKE_EXE_LINKER_FLAGS}") +else() + set(IDF_TOOLCHAIN_BUILD_DIR "${_current_toolchain_dir}" + CACHE PATH "Path to toolchain build directory containing response files and toolchain file copy" FORCE) +endif() + +# Configure CMake to use response files for compiler and linker flags. +# Some compilation options enabled by IDF configuration options are not yet +# defined at this very early CMake stage (toolchain.cmake execution). Response +# files allow these flags to be dynamically updated during the CMake configuration +# phase, after the options become available. +set(CMAKE_C_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/cflags\"" CACHE STRING "C Compiler Base Flags" FORCE) +set(CMAKE_CXX_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/cxxflags\"" CACHE STRING "C++ Compiler Base Flags" FORCE) +set(CMAKE_ASM_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/asmflags\"" CACHE STRING "Asm Compiler Base Flags" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/ldflags\"" CACHE STRING "Linker Base Flags" FORCE) diff --git a/tools/cmake/toolchain_flags.cmake b/tools/cmake/toolchain_flags.cmake new file mode 100644 index 0000000000..682e4e2602 --- /dev/null +++ b/tools/cmake/toolchain_flags.cmake @@ -0,0 +1,157 @@ +# Map option variable names to their corresponding file lists +set(_IDF_TOOLCHAIN_OPTION_MAPPINGS + "COMPILE_OPTIONS|cflags:cxxflags:asmflags" + "C_COMPILE_OPTIONS|cflags" + "CXX_COMPILE_OPTIONS|cxxflags" + "ASM_COMPILE_OPTIONS|asmflags" + "LINK_OPTIONS|ldflags" +) + +# Extract keywords from mappings (drop substring after "|") +set(_IDF_TOOLCHAIN_MULTI_VALUE_KEYWORDS "") +foreach(mapping ${_IDF_TOOLCHAIN_OPTION_MAPPINGS}) + string(REGEX REPLACE "\\|.*" "" keyword "${mapping}") + list(APPEND _IDF_TOOLCHAIN_MULTI_VALUE_KEYWORDS "${keyword}") +endforeach() + +# Helper macro to process toolchain flag options based on mappings +# Uses macro instead of function to access parent scope variables directly +# operation: "add" or "remove" +macro(_process_toolchain_flag_options) + cmake_parse_arguments(PARSE_ARGV 0 "" "" "" "${_IDF_TOOLCHAIN_MULTI_VALUE_KEYWORDS}") + + if(NOT EXISTS "${IDF_TOOLCHAIN_BUILD_DIR}") + message(FATAL_ERROR "Toolchain directory does not exist: ${IDF_TOOLCHAIN_BUILD_DIR}") + endif() + + foreach(mapping ${_IDF_TOOLCHAIN_OPTION_MAPPINGS}) + string(REPLACE "|" ";" mapping_list ${mapping}) + # Extract option variable name and add underscore prefix + list(GET mapping_list 0 option_var) + set(option_var "_${option_var}") + + # Extract file list for this option variable + list(GET mapping_list 1 files) + string(REPLACE ":" ";" files ${files}) + + # Process flags based on calling function: add or remove + if("${CMAKE_CURRENT_FUNCTION}" MATCHES "add_flags" AND DEFINED ${option_var}) + _add_flags_to_files("${files}" "${${option_var}}") + endif() + if("${CMAKE_CURRENT_FUNCTION}" MATCHES "remove_flags" AND ${option_var}) + _remove_flags_from_files("${files}" "${${option_var}}") + endif() + endforeach() +endmacro() + +# Helper function to remove flags matching patterns from specific files +function(_remove_flags_from_files files patterns) + foreach(file ${files}) + set(file_path "${IDF_TOOLCHAIN_BUILD_DIR}/${file}") + + if(EXISTS "${file_path}") + file(STRINGS "${file_path}" existing_lines) + else() + set(existing_lines "") + endif() + + file(WRITE "${file_path}" "") + foreach(line ${existing_lines}) + set(should_keep TRUE) + foreach(pattern ${patterns}) + if("${line}" MATCHES "${pattern}") + set(should_keep FALSE) + break() + endif() + endforeach() + if(should_keep) + file(APPEND "${file_path}" "${line}\n") + endif() + endforeach() + endforeach() +endfunction() + +# Helper function to add flags to specific files +function(_add_flags_to_files files flags) + foreach(file ${files}) + set(file_path "${IDF_TOOLCHAIN_BUILD_DIR}/${file}") + + if(EXISTS "${file_path}") + file(STRINGS "${file_path}" existing_lines) + else() + set(existing_lines "") + endif() + + # Split flags string using regex to respect quotes. + # Matches: double-quoted strings, single-quoted strings, or unquoted space-delimited tokens. + # + # TODO IDF-14467: + # Currently, paired linker flags are not properly handled when filtering. + # The regex-based splitting treats each flag independently, which breaks + # flag pairs that must be kept together. Future enhancement should support + # the following paired flag constructs: + # - --start-group ... --end-group + # - --push-state ... --pop-state + # - --whole-archive ... --no-whole-archive + # - --as-needed ... --no-as-needed + # - --push-section ... --pop-section + string(REGEX MATCHALL "([^\\s\"']*(\"[^\"]*\"|'[^']*')|\"[^\"]*\"|'[^']*'|[^ \"']+)" flags "${flags}") + + file(WRITE "${file_path}" "") + foreach(line ${existing_lines}) + set(should_keep TRUE) + foreach(flag ${flags}) + if("${line}" STREQUAL "${flag}") + set(should_keep FALSE) + break() + endif() + endforeach() + if(should_keep) + file(APPEND "${file_path}" "${line}\n") + endif() + endforeach() + + foreach(flag ${flags}) + # Skip flags that contain IDF_TOOLCHAIN_BUILD_DIR substring + # to avoid recursion + string(FIND "${flag}" "${IDF_TOOLCHAIN_BUILD_DIR}" found_pos) + if(found_pos EQUAL -1) + file(APPEND "${file_path}" "${flag}\n") + endif() + endforeach() + endforeach() +endfunction() + +# idf_toolchain_add_flags +# +# @brief Add compiler or linker flags to the toolchain configuration files. +# +# This function adds flags to the appropriate toolchain response files (cflags, cxxflags, +# asmflags, or ldflags) in the IDF_TOOLCHAIN_BUILD_DIR directory. Duplicate flags +# are automatically removed before adding new ones. +# +# @param[in, optional] COMPILE_OPTIONS (multivalue) flags to add to C, C++, and ASM +# compilation. Applied to cflags, cxxflags, and asmflags files. +# @param[in, optional] C_COMPILE_OPTIONS (multivalue) flags to add to C compilation only. +# Applied to cflags file. +# @param[in, optional] CXX_COMPILE_OPTIONS (multivalue) flags to add to C++ compilation only. +# Applied to cxxflags file. +# @param[in, optional] ASM_COMPILE_OPTIONS (multivalue) flags to add to ASM compilation only. +# Applied to asmflags file. +# @param[in, optional] LINK_OPTIONS (multivalue) flags to add to linking. +# Applied to ldflags file. +# +# @note Multiple keyword arguments can be specified in a single call. +# @note Flags are deduplicated - if a flag already exists in the file, it will be +# removed before adding the new one to ensure no duplicates. +# +# Example: +# idf_toolchain_add_flags(COMPILE_OPTIONS "-Wall" "-Wextra") +# idf_toolchain_add_flags(C_COMPILE_OPTIONS "-std=c99" LINK_OPTIONS "-Wl,--gc-sections") +function(idf_toolchain_add_flags) + _process_toolchain_flag_options() +endfunction() + +function(idf_toolchain_remove_flags) + _process_toolchain_flag_options() +endfunction() diff --git a/tools/test_build_system/test_cmake.py b/tools/test_build_system/test_cmake.py index a7570991d9..2739c42307 100644 --- a/tools/test_build_system/test_cmake.py +++ b/tools/test_build_system/test_cmake.py @@ -51,6 +51,58 @@ def test_build_custom_cmake_project_host() -> None: run_cmake_and_build(str(idf_path / 'examples' / 'build_system' / 'cmake' / 'idf_as_lib'), '-G', 'Ninja') +@pytest.mark.buildv2_skip('import_lib example uses cmakev1, not yet updated for buildv2 (IDF-14185)') +def test_build_cmake_library_with_toolchain_flags(test_app_copy: Path) -> None: + logging.info('Building a project with CMake library imported with modified toolchain flags') + idf_path = Path(os.environ['IDF_PATH']) + # Enable Picolibc to verify that all flags are passed correctly to the external project. + # In case something is missing, the build will fail on linking stage. + # Note: To enable Picolibc, IDF_EXPERIMENTAL_FEATURES must also be set for now. + (test_app_copy / 'sdkconfig.defaults').write_text( + '\n'.join(['CONFIG_IDF_EXPERIMENTAL_FEATURES=y', 'CONFIG_LIBC_PICOLIBC=y']) + ) + + import_lib_path = idf_path / 'examples' / 'build_system' / 'cmake' / 'import_lib' + run_cmake_and_build( + str(import_lib_path), + '-G', + 'Ninja', + f'-DSDKCONFIG_DEFAULTS={import_lib_path / "sdkconfig.defaults"};{test_app_copy / "sdkconfig.defaults"}', + ) + + +def check_flag_in_compile_commands(build_dir: Path, flag_to_find: str) -> None: + with open(build_dir / 'build' / 'compile_commands.json', encoding='utf-8') as f: + compile_commands = json.load(f) + # check if compile_commands is an array + if not isinstance(compile_commands, list): + assert False, f'compile_commands is not a list: {compile_commands}' + assert len(compile_commands) != 0, 'compile_commands is empty' + for entry in compile_commands: + command = entry['command'] + assert isinstance(command, str), f'command is not a string: {command}' + flag_is_found = flag_to_find in command + if flag_is_found: + continue # Flag found in command, no need to check response files + # check if command contains response file paths starts with @ + response_file_paths = re.findall(r'@([^\s]+)', command) + for response_file_path in response_file_paths: + # check if the flag file contains flag_to_find + try: + # Strip surrounding quotes and normalize the path + response_file_path = response_file_path.strip('"\'\\') + response_file_path = Path(response_file_path).resolve() + with open(response_file_path, encoding='utf-8') as f: + flags = f.read() + if flag_to_find in flags: + flag_is_found = True + break + except FileNotFoundError: + assert False, f'{response_file_path} does not exist' + if not flag_is_found: + assert False, f'{flag_to_find} not found in {command}' + + @pytest.mark.buildv2_skip('import_lib example uses cmakev1, not yet updated for buildv2 (IDF-14185)') def test_build_cmake_library_psram_workaround(test_app_copy: Path) -> None: logging.info( @@ -67,13 +119,7 @@ def test_build_cmake_library_psram_workaround(test_app_copy: Path) -> None: '-DSDKCONFIG_DEFAULTS={}'.format(test_app_copy / 'sdkconfig.defaults'), str(idf_path / 'examples' / 'build_system' / 'cmake' / 'import_lib'), ) - with open((test_app_copy / 'build' / 'compile_commands.json'), encoding='utf-8') as f: - data = f.read() - res = re.findall(r'.*\"command\".*', data) - for r in res: - assert 'mfix-esp32-psram-cache-issue' in r, ( - 'All commands in compile_commands.json should use PSRAM cache workaround' - ) + check_flag_in_compile_commands(test_app_copy, '-mfix-esp32-psram-cache-issue') def test_build_cmake_library_psram_strategies(idf_py: IdfPyFunc, test_app_copy: Path) -> None: @@ -97,13 +143,7 @@ def test_build_cmake_library_psram_strategies(idf_py: IdfPyFunc, test_app_copy: ) ) idf_py('reconfigure') - with open((test_app_copy / 'build' / 'compile_commands.json'), encoding='utf-8') as f: - data = f.read() - res = re.findall(r'.*\"command\".*', data) - for r in res: - assert f'mfix-esp32-psram-cache-strategy={strategy.lower()}' in r, ( - 'All commands in compile_commands.json should use PSRAM cache workaround strategy' - ) + check_flag_in_compile_commands(test_app_copy, f'-mfix-esp32-psram-cache-strategy={strategy.lower()}') (test_app_copy / 'sdkconfig').unlink()