diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index 4c9ff0001e..69acd116be 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -486,6 +486,7 @@ pytest_buildv2_system: --junitxml ${CI_PROJECT_DIR}/XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} -- + buildv2 test_non_default_target.py test_component_manager.py test_build.py diff --git a/.gitlab/ci/test-win.yml b/.gitlab/ci/test-win.yml index 2eceab04ba..5d7b505c22 100644 --- a/.gitlab/ci/test-win.yml +++ b/.gitlab/ci/test-win.yml @@ -165,6 +165,7 @@ pytest_buildv2_system_win: --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml --ignore-result-files ${KNOWN_FAILURE_CASES_FILE_NAME} -- + buildv2 test_non_default_target.py test_component_manager.py test_build.py diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 9bd635734d..d9c2fdc753 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -66,7 +66,7 @@ menu "Bluetooth" menu "Controller Options" depends on BT_CONTROLLER_ENABLED - source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in" + osource "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in" endmenu config BT_RELEASE_IRAM diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 4c26838cb8..23187c5c3b 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -197,6 +197,11 @@ if(arch STREQUAL "linux") PROPERTIES COMPILE_OPTIONS "-Wno-strict-prototypes" ) + if(APPLE) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _app_main") + else() + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") + endif() else() idf_component_get_property(COMPONENT_DIR freertos COMPONENT_DIR) diff --git a/components/linux/CMakeLists.txt b/components/linux/CMakeLists.txt index e446de0e9d..d271649431 100644 --- a/components/linux/CMakeLists.txt +++ b/components/linux/CMakeLists.txt @@ -3,6 +3,7 @@ if(NOT "${target}" STREQUAL "linux") return() endif() +set(srcs) set(includes "include") if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") list(APPEND srcs getrandom.c assert_func.c) diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 27cc786832..483fcc9683 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -2,6 +2,8 @@ idf_build_get_property(target IDF_TARGET) 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" diff --git a/tools/cmakev2/build.cmake b/tools/cmakev2/build.cmake index 79e806a3bf..7551640106 100644 --- a/tools/cmakev2/build.cmake +++ b/tools/cmakev2/build.cmake @@ -715,35 +715,55 @@ endfunction() .. code-block:: cmake - idf_build_generate_metadata( + idf_build_generate_metadata([BINARY ] + [EXECUTABLE ] [OUTPUT_FILE ]) - *binary[in]* + *BINARY[in,opt]* Binary target for which to generate a metadata file. + *EXECUTABLE[in,opt]* + + Executable target for which to generate a metadata file. + *OUTPUT_FILE[in,opt]* Optional output file path for storing the metadata. If not provided, the default path ``/project_description.json`` is used. - Generate metadata for the specified ``binary`` and store it in the - specified ``OUTPUT_FILE``. If no ``OUTPUT_FILE`` is provided, the default - location ``/project_description.json`` will be used. + Generate metadata for the specified ``binary`` or ``executable`` target and + store it in the specified ``OUTPUT_FILE``. If no ``OUTPUT_FILE`` is + provided, the default location ``/project_description.json`` will be + used. #]] -function(idf_build_generate_metadata binary) +function(idf_build_generate_metadata) set(options) - set(one_value OUTPUT_FILE) + set(one_value OUTPUT_FILE BINARY EXECUTABLE) set(multi_value) cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN}) - # The EXECUTABLE_TARGET property is set by the idf_build_binary or - # the idf_sign_binary function. - get_target_property(executable "${binary}" EXECUTABLE_TARGET) - if(NOT executable) - idf_die("Binary target '${binary}' is missing 'EXECUTABLE_TARGET' property.") + if(NOT DEFINED ARG_BINARY AND NOT DEFINED ARG_EXECUTABLE) + idf_die("BINARY or EXECUTABLE option is required") endif() - __get_executable_library_or_die(TARGET "${executable}" OUTPUT library) + + if(DEFINED ARG_BINARY) + # The EXECUTABLE_TARGET property is set by the idf_build_binary or + # the idf_sign_binary function. + get_target_property(ARG_EXECUTABLE "${ARG_BINARY}" EXECUTABLE_TARGET) + if(NOT ARG_EXECUTABLE) + idf_die("Binary target '${ARG_BINARY}' is missing 'EXECUTABLE_TARGET' property.") + endif() + + # The BINARY_PATH property is set by the idf_build_binary or + # the idf_sign_binary function. + get_target_property(binary_path ${ARG_BINARY} BINARY_PATH) + if(NOT binary_path) + idf_die("Binary target '${ARG_BINARY}' is missing 'BINARY_PATH' property.") + endif() + get_filename_component(PROJECT_BIN "${binary_path}" NAME) + endif() + __get_executable_library_or_die(TARGET "${ARG_EXECUTABLE}" OUTPUT library) idf_build_get_property(PROJECT_NAME PROJECT_NAME) idf_build_get_property(PROJECT_VER PROJECT_VER) @@ -752,14 +772,7 @@ function(idf_build_generate_metadata binary) idf_build_get_property(BUILD_DIR BUILD_DIR) idf_build_get_property(SDKCONFIG SDKCONFIG) idf_build_get_property(SDKCONFIG_DEFAULTS SDKCONFIG_DEFAULTS) - set(PROJECT_EXECUTABLE "$") - # The BINARY_PATH property is set by the idf_build_binary or - # the idf_sign_binary function. - get_target_property(binary_path ${binary} BINARY_PATH) - if(NOT binary_path) - idf_die("Binary target '${binary}' is missing 'BINARY_PATH' property.") - endif() - get_filename_component(PROJECT_BIN "${binary_path}" NAME) + set(PROJECT_EXECUTABLE "$") if(NOT PROJECT_BIN) set(PROJECT_BIN "") endif() diff --git a/tools/cmakev2/component.cmake b/tools/cmakev2/component.cmake index b38680cc99..08a9ca5c67 100644 --- a/tools/cmakev2/component.cmake +++ b/tools/cmakev2/component.cmake @@ -885,12 +885,12 @@ function(idf_component_include name) # helps in detecting and reporting circular dependencies, such as # C1->C2->C1. In this scenario, C2 can still use the C1 interface target, # but C1 will only be fully evaluated after C2 has been evaluated. - if("${component_name}" IN_LIST __DEPENDENCY_CHAIN) - idf_dbg("Component '${name}' in circular dependency chain '${__DEPENDENCY_CHAIN}'") + if("${component_interface}" IN_LIST __DEPENDENCY_CHAIN) + idf_dbg("Component '${component_interface}' in circular dependency chain '${__DEPENDENCY_CHAIN}'") return() endif() - list(APPEND __DEPENDENCY_CHAIN "${name}") + list(APPEND __DEPENDENCY_CHAIN "${component_interface}") # Evaluate the CMakeLists.txt file of the component. idf_component_get_property(component_build_dir "${component_name}" COMPONENT_BUILD_DIR) add_subdirectory("${component_directory}" "${component_build_dir}") diff --git a/tools/cmakev2/idf.cmake b/tools/cmakev2/idf.cmake index 7aaf3f64ad..631309e7a6 100644 --- a/tools/cmakev2/idf.cmake +++ b/tools/cmakev2/idf.cmake @@ -266,16 +266,15 @@ endfunction() #[[ __init_toolchain() - Determine the IDF_TOOLCHAIN value from the IDF_TOOLCHAIN environment - variable or the CMake cache variable. If none of these are set, use the - default gcc toolchain. Ensure there are no inconsistencies in the - IDF_TOOLCHAIN values set in different locations. Also ensure that the + Determine the toolchain file, set IDF_TOOLCHAIN_FILE build property and + global CMAKE_TOOLCHAIN_FILE CMake variable. Also ensure that the CMAKE_TOOLCHAIN_FILE is set to the correct file according to the current IDF_TARGET. - Set the IDF_TOOLCHAIN and IDF_TOOLCHAIN_FILE build properties. Also, - configure the IDF_TOOLCHAIN CMake cache variable and set the - CMAKE_TOOLCHAIN_FILE global variable. + Note: The IDF_TOOLCHAIN build property is set after the toolchain + configuration in ``idf_project_init``. The ``tools/cmake/toolchain.cmake`` + is included in the toolchain file and it sets the IDF_TOOLCHAIN variable in + CMake's cache. #]] function(__init_toolchain) set(cache_toolchain $CACHE{IDF_TOOLCHAIN}) @@ -318,9 +317,7 @@ function(__init_toolchain) idf_die("Toolchain file ${toolchain_file} not found") endif() - set(IDF_TOOLCHAIN ${toolchain} CACHE STRING "IDF Build Toolchain Type") set(CMAKE_TOOLCHAIN_FILE "${toolchain_file}" PARENT_SCOPE) - idf_build_set_property(IDF_TOOLCHAIN "${toolchain}") idf_build_set_property(IDF_TOOLCHAIN_FILE "${toolchain_file}") endfunction() diff --git a/tools/cmakev2/kconfig.cmake b/tools/cmakev2/kconfig.cmake index a9a589b162..786397b4da 100644 --- a/tools/cmakev2/kconfig.cmake +++ b/tools/cmakev2/kconfig.cmake @@ -407,9 +407,10 @@ function(__create_executable_config_env_file executable) foreach(component_interface IN LISTS component_interfaces) __idf_component_get_property_unchecked(component_kconfig "${component_interface}" __KCONFIG) __idf_component_get_property_unchecked(component_projbuild "${component_interface}" __KCONFIG_PROJBUILD) + __idf_component_get_property_unchecked(component_real_target "${component_interface}" COMPONENT_REAL_TARGET) if(component_kconfig) - if("${component_interface}" IN_LIST component_interfaces_linked) + if("${component_interface}" IN_LIST component_interfaces_linked AND component_real_target) list(APPEND kconfigs "${component_kconfig}") else() list(APPEND kconfigs_excluded "${component_kconfig}") @@ -417,7 +418,7 @@ function(__create_executable_config_env_file executable) endif() if(component_projbuild) - if("${component_interface}" IN_LIST component_interfaces_linked) + if("${component_interface}" IN_LIST component_interfaces_linked AND component_real_target) list(APPEND kconfigs_projbuild "${component_projbuild}") else() list(APPEND kconfigs_projbuild_excluded "${component_projbuild}") diff --git a/tools/cmakev2/project.cmake b/tools/cmakev2/project.cmake index 161a9c3e8c..cd0392a990 100644 --- a/tools/cmakev2/project.cmake +++ b/tools/cmakev2/project.cmake @@ -560,6 +560,11 @@ macro(idf_project_init) # Ensure this function is executed only once throughout the entire # project. + # The IDF_TOOLCHAIN variable is established as a CMake cache variable + # during the toolchain initialization process in + # ``tools/cmake/toolchain.cmake``. + idf_build_set_property(IDF_TOOLCHAIN "${IDF_TOOLCHAIN}") + # Warn about the use of deprecated variables. deprecate_variable(COMPONENTS) deprecate_variable(EXCLUDE_COMPONENTS) @@ -707,7 +712,7 @@ function(__project_default) COMPONENTS main MAPFILE_TARGET "${executable}_mapfile") - if(CONFIG_APP_BUILD_GENERATE_BINARIES) + if(CONFIG_APP_BUILD_GENERATE_BINARIES AND TARGET idf::esptool_py) # Is it possible to have a configuration where # CONFIG_APP_BUILD_GENERATE_BINARIES is not set? @@ -726,7 +731,7 @@ function(__project_default) TARGET app-flash NAME "app" FLASH) - idf_build_generate_metadata("${executable}_binary_signed") + idf_build_generate_metadata(BINARY "${executable}_binary_signed") else() idf_build_binary("${executable}" OUTPUT_FILE "${build_dir}/${executable}.bin" @@ -743,10 +748,12 @@ function(__project_default) idf_create_dfu("${executable}_binary" TARGET dfu) - idf_build_generate_metadata("${executable}_binary") + idf_build_generate_metadata(BINARY "${executable}_binary") endif() idf_build_generate_flasher_args() + else() + idf_build_generate_metadata(EXECUTABLE "${executable}") endif() idf_create_menuconfig("${executable}" diff --git a/tools/cmakev2/test/CMakeLists.txt b/tools/cmakev2/test/CMakeLists.txt index 0981ec92af..8eb5c75ac1 100644 --- a/tools/cmakev2/test/CMakeLists.txt +++ b/tools/cmakev2/test/CMakeLists.txt @@ -232,7 +232,7 @@ function(test_executable) NAME fatfs_example) idf_create_menuconfig(fatfs_example TARGET menuconfig-fatfs) - idf_build_generate_metadata(fatfs_example_bin + idf_build_generate_metadata(BINARY fatfs_example_bin OUTPUT_FILE project_description_fatfs.json) idf_build_generate_depgraph(fatfs_example OUTPUT_FILE component_deps_fatfs.dot) @@ -257,7 +257,7 @@ function(test_executable) NAME hello_world_example) idf_create_menuconfig(hello_world_example TARGET menuconfig-hello_world) - idf_build_generate_metadata(hello_world_example_bin + idf_build_generate_metadata(BINARY hello_world_example_bin OUTPUT_FILE project_description_hello_world.json) idf_build_generate_depgraph(hello_world_example OUTPUT_FILE component_deps_hello_world.dot) diff --git a/tools/test_build_system/buildv2/test_linux_build.py b/tools/test_build_system/buildv2/test_linux_build.py new file mode 100644 index 0000000000..68ab9f09e2 --- /dev/null +++ b/tools/test_build_system/buildv2/test_linux_build.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import logging +import sys + +import pytest +from test_build_system_helpers import IdfPyFunc + + +@pytest.mark.skipif(sys.platform == 'win32', reason='Unix test') +@pytest.mark.usefixtures('test_app_copy') +def test_linux_target_build(idf_py: IdfPyFunc) -> None: + logging.info('Can build for Linux target') + idf_py('--preview', '-DIDF_TARGET=linux', 'build') diff --git a/tools/test_build_system/conftest.py b/tools/test_build_system/conftest.py index 773f718e1e..d8d85ce0a0 100644 --- a/tools/test_build_system/conftest.py +++ b/tools/test_build_system/conftest.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import datetime import logging @@ -241,10 +241,23 @@ def idf_py(default_idf_env: EnvDict) -> IdfPyFunc: def pytest_collection_modifyitems(session: Session, config: Config, items: list[Item]) -> None: - if not config.getoption('--buildv2', False): - return + buildv2_dir = Path(__file__).parent / 'buildv2' + is_buildv2 = config.getoption('--buildv2', False) + for item in items: - marker = item.get_closest_marker('buildv2_skip') - if marker: - reason = marker.args[0] if marker.args else 'Skipped as this test is specific to build system v1.' - item.add_marker(pytest.mark.skip(reason=reason)) + if is_buildv2: + marker = item.get_closest_marker('buildv2_skip') + if marker: + reason = marker.args[0] if marker.args else 'Skipped as this test is specific to build system v1.' + item.add_marker(pytest.mark.skip(reason=reason)) + else: + if buildv2_dir in item.path.parents or item.path == buildv2_dir: + item.add_marker(pytest.mark.skip(reason='Skipped as build system v2 tests are disabled.')) + + +def pytest_report_header(config: Config) -> str: + """Add a clear header to the terminal output whether buildv1 or buildv2 testing is in progress.""" + if config.getoption('--buildv2'): + return 'Testing ESP-IDF CMake-based build system v2' + else: + return 'Testing ESP-IDF CMake-based build system v1'