diff --git a/tools/cmake/deduplicate_flags.cmake b/tools/cmake/deduplicate_flags.cmake index 7398f2c743..c388a30752 100644 --- a/tools/cmake/deduplicate_flags.cmake +++ b/tools/cmake/deduplicate_flags.cmake @@ -4,6 +4,8 @@ # Remove duplicates from a string containing compilation flags function(remove_duplicated_flags FLAGS UNIQFLAGS) set(FLAGS_LIST "${FLAGS}") + # Remove leading and trailing spaces + string(STRIP "${FLAGS_LIST}" FLAGS_LIST) # Convert the given flags, as a string, into a CMake list type separate_arguments(FLAGS_LIST) # Remove all the duplicated flags diff --git a/tools/cmake/toolchain.cmake b/tools/cmake/toolchain.cmake index db1f80181b..2d0d9b33d4 100644 --- a/tools/cmake/toolchain.cmake +++ b/tools/cmake/toolchain.cmake @@ -1,4 +1,5 @@ include(${CMAKE_CURRENT_LIST_DIR}/toolchain_flags.cmake) +include($ENV{IDF_PATH}/tools/cmake/deduplicate_flags.cmake) if(NOT CMAKE_PARENT_LIST_FILE) message(FATAL_ERROR "toolchain.cmake cannot be used standalone (use chip-specific toolchain file instead)") @@ -69,17 +70,30 @@ if(_idf_toolchain_dir STREQUAL _current_toolchain_dir) CXX_COMPILE_OPTIONS "${CMAKE_CXX_FLAGS}" ASM_COMPILE_OPTIONS "${CMAKE_ASM_FLAGS}" LINK_OPTIONS "${CMAKE_EXE_LINKER_FLAGS}") + # Clear CMAKE_*_FLAGS because all flags are written to response files. + set(CMAKE_C_FLAGS "") + set(CMAKE_CXX_FLAGS "") + set(CMAKE_ASM_FLAGS "") + set(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() +# Merge the response file path with any existing CMAKE_*_FLAGS (e.g. from +# ExternalProject_Add), then remove duplicates. Deduplication is needed because +# CMake may execute this toolchain file multiple times during initialization. +remove_duplicated_flags("@\"${IDF_TOOLCHAIN_BUILD_DIR}/cflags\" ${CMAKE_C_FLAGS}" CMAKE_C_FLAGS) +remove_duplicated_flags("@\"${IDF_TOOLCHAIN_BUILD_DIR}/cxxflags\" ${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS) +remove_duplicated_flags("@\"${IDF_TOOLCHAIN_BUILD_DIR}/asmflags\" ${CMAKE_ASM_FLAGS}" CMAKE_ASM_FLAGS) +remove_duplicated_flags("@\"${IDF_TOOLCHAIN_BUILD_DIR}/ldflags\" ${CMAKE_EXE_LINKER_FLAGS}" CMAKE_EXE_LINKER_FLAGS) + # 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) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) diff --git a/tools/test_apps/build_system/.build-test-rules.yml b/tools/test_apps/build_system/.build-test-rules.yml index 6318cde345..c02632e34a 100644 --- a/tools/test_apps/build_system/.build-test-rules.yml +++ b/tools/test_apps/build_system/.build-test-rules.yml @@ -16,6 +16,12 @@ tools/test_apps/build_system/embed_test: temporary: false reason: Hardware independent feature, no need to test on all targets +tools/test_apps/build_system/external_project: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3"] + temporary: false + reason: Verifies toolchain preserves CMAKE_*_FLAGS in ExternalProject_Add context + tools/test_apps/build_system/ld_non_contiguous_memory: disable: - if: SOC_MEM_NON_CONTIGUOUS_SRAM != 1 # TODO: IDF-13411, since P4 REV2, the SRAM is contiguous diff --git a/tools/test_apps/build_system/external_project/CMakeLists.txt b/tools/test_apps/build_system/external_project/CMakeLists.txt new file mode 100644 index 0000000000..4163b50666 --- /dev/null +++ b/tools/test_apps/build_system/external_project/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# Trim the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +project(external_project) diff --git a/tools/test_apps/build_system/external_project/README.md b/tools/test_apps/build_system/external_project/README.md new file mode 100644 index 0000000000..1fb88efd15 --- /dev/null +++ b/tools/test_apps/build_system/external_project/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C3 | +| ----------------- | ----- | -------- | diff --git a/tools/test_apps/build_system/external_project/components/ext_component/CMakeLists.txt b/tools/test_apps/build_system/external_project/components/ext_component/CMakeLists.txt new file mode 100644 index 0000000000..eda1903281 --- /dev/null +++ b/tools/test_apps/build_system/external_project/components/ext_component/CMakeLists.txt @@ -0,0 +1,19 @@ +idf_component_register() + +include(ExternalProject) +externalproject_add(ext_subproject + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/subproject + CMAKE_ARGS + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -DCMAKE_C_FLAGS=-DEXTERNAL_PROJECT_FLAG=1 + -DCMAKE_CXX_FLAGS=-DEXTERNAL_PROJECT_CXX_FLAG=1 + -DCMAKE_ASM_FLAGS=-DEXTERNAL_PROJECT_ASM_FLAG=1 + -DCMAKE_EXE_LINKER_FLAGS=-Wl,--defsym=EXTERNAL_PROJECT_LINKER_CHECK=1 + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/subproject" + INSTALL_COMMAND "" + BUILD_BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/subproject/libext_lib.a" +) + +add_prebuilt_library(ext_lib "${CMAKE_CURRENT_BINARY_DIR}/subproject/libext_lib.a") + +target_link_libraries(${COMPONENT_LIB} INTERFACE ext_lib) diff --git a/tools/test_apps/build_system/external_project/components/ext_component/subproject/CMakeLists.txt b/tools/test_apps/build_system/external_project/components/ext_component/subproject/CMakeLists.txt new file mode 100644 index 0000000000..e61f2bc3f3 --- /dev/null +++ b/tools/test_apps/build_system/external_project/components/ext_component/subproject/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.22) + +project(ext_subproject LANGUAGES C CXX ASM) +add_library(ext_lib STATIC check_flag.c check_flag.cpp check_flag.S) +add_executable(ext_link_test link_check.c) +target_link_libraries(ext_link_test PRIVATE ext_lib) diff --git a/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.S b/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.S new file mode 100644 index 0000000000..6fe5a292c3 --- /dev/null +++ b/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.S @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef EXTERNAL_PROJECT_ASM_FLAG +#error "EXTERNAL_PROJECT_ASM_FLAG not defined - toolchain did not preserve CMAKE_ASM_FLAGS from ExternalProject_Add" +#endif diff --git a/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.c b/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.c new file mode 100644 index 0000000000..09f256c288 --- /dev/null +++ b/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.c @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef EXTERNAL_PROJECT_FLAG +#error "EXTERNAL_PROJECT_FLAG not defined - toolchain did not preserve CMAKE_C_FLAGS from ExternalProject_Add" +#endif diff --git a/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.cpp b/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.cpp new file mode 100644 index 0000000000..c5588e5c84 --- /dev/null +++ b/tools/test_apps/build_system/external_project/components/ext_component/subproject/check_flag.cpp @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef EXTERNAL_PROJECT_CXX_FLAG +#error "EXTERNAL_PROJECT_CXX_FLAG not defined - toolchain did not preserve CMAKE_CXX_FLAGS from ExternalProject_Add" +#endif diff --git a/tools/test_apps/build_system/external_project/components/ext_component/subproject/link_check.c b/tools/test_apps/build_system/external_project/components/ext_component/subproject/link_check.c new file mode 100644 index 0000000000..fca4e64dac --- /dev/null +++ b/tools/test_apps/build_system/external_project/components/ext_component/subproject/link_check.c @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +extern char EXTERNAL_PROJECT_LINKER_CHECK; + +int _start(void) +{ + return (int)&EXTERNAL_PROJECT_LINKER_CHECK; +} diff --git a/tools/test_apps/build_system/external_project/main/CMakeLists.txt b/tools/test_apps/build_system/external_project/main/CMakeLists.txt new file mode 100644 index 0000000000..ce65804eaa --- /dev/null +++ b/tools/test_apps/build_system/external_project/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_main.c" + REQUIRES ext_component) diff --git a/tools/test_apps/build_system/external_project/main/test_main.c b/tools/test_apps/build_system/external_project/main/test_main.c new file mode 100644 index 0000000000..850221b77b --- /dev/null +++ b/tools/test_apps/build_system/external_project/main/test_main.c @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include + +void app_main(void) +{ + printf("external_project test OK\n"); +}