Files
esp-idf/tools/cmakev2/test/CMakeLists.txt
T
Frantisek Hrbata 998c8870eb feat(cmakev2/kconfig): add idf_create_confserver function
This is a revised version of the existing __create_confserver_target
function. It creates a specified confserver target for a given
executable. The kconfig_menus.json file, used by the IDEs, is generated
when the confserver starts. This differs from the previous behavior,
where kconfig_menus.json was created globally along with other sdkconfig
formats. The reason for this change is that kconfig_menus.json contains
the Kconfig menu hierarchy and it is not just a flat option-value
format. It needs to accurately reflect which configurations for which
components are included or excluded. The kconfig_menus.json is generated
at `build/kconfig_menus.json`, where IDEs expect it. This means the file
is overwritten every time the server starts by kconfig_menus.json
version for given executable, so only one confserver can run at a time.

This is likely acceptable, as I don't believe it's possible to safely
run multiple instances of confserver due to the potential race
conditions when the sdkconfig file are generated.

In the future, we may include the location of kconfig_menus.json in
project_description.json so it can be easily identified by IDEs for
each executable.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00

279 lines
9.9 KiB
CMake

# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
# Simple project for basic cmakev2 testing
# Run: cmake -S . -B build
cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
project(cmakev2
VERSION 1.2.3
LANGUAGES C CXX ASM)
add_custom_target(flash)
idf_project_init()
# Test component priority
function(test_component_priority)
# Set the idf component to be replaced with a testing component of higher
# priority.
set(component_name "esp_system")
# Check that idf component is between discovered components.
__get_component_interface(COMPONENT "${component_name}"
OUTPUT component_interface)
if("${component_interface}" STREQUAL "NOTFOUND")
idf_die("Component '${component_name}' not found")
endif()
# Check that idf component has "idf_components" as source.
idf_component_get_property(component_source
${component_interface}
COMPONENT_SOURCE)
if(NOT "${component_source}" STREQUAL "idf_components")
idf_die("Unexpected idf component '${component_name}' source '${component_source}'")
endif()
# Create fake component with same name as idf component.
set(component_dir "${CMAKE_CURRENT_BINARY_DIR}/${component_name}")
file(MAKE_DIRECTORY "${component_dir}")
file(TOUCH "${component_dir}/CMakeLists.txt")
# Initialize fake component with higher "project_components" priority.
idf_build_get_property(component_prefix PREFIX)
__init_component(DIRECTORY "${component_dir}"
PREFIX "${component_prefix}"
SOURCE "project_components")
# Check that the idf component was replaced with fake component.
idf_component_get_property(component_source
${component_interface}
COMPONENT_SOURCE)
if(NOT "${component_source}" STREQUAL "project_components")
idf_die("Unexpected fake component '${component_name}' source '${component_source}'")
endif()
idf_component_get_property(component_dir
${component_interface}
COMPONENT_DIR)
if(NOT "${component_dir}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/${component_name}")
idf_die("Unexpected fake component '${component_name}' directory '${component_dir}'")
endif()
__dump_component_properties("${component_name}")
endfunction()
# Test that IDF_VERSION and IDF_VER build property is set
function(test_idf_version)
if(NOT DEFINED IDF_VERSION_MAJOR OR
NOT DEFINED IDF_VERSION_MINOR OR
NOT DEFINED IDF_VERSION_PATCH OR
NOT DEFINED ENV{IDF_VERSION})
idf_die("IDF_VERSION not set")
endif()
idf_build_get_property(idf_ver IDF_VER)
if(NOT idf_ver)
idf_die("IDF_VER build property not set")
endif()
endfunction()
# Test that Python interpreter is set
function(test_python)
if(NOT DEFINED PYTHON OR "${PYTHON}" STREQUAL "")
idf_die("PYTHON variable not defined or empty")
endif()
endfunction()
# Test that toolchain is properly set
function(test_toolchain)
if(NOT IDF_TOOLCHAIN)
idf_die("IDF_TOOLCHAIN variable not defined or empty")
endif()
if(NOT CMAKE_TOOLCHAIN_FILE)
idf_die("CMAKE_TOOLCHAIN_FILE variable not defined or empty")
endif()
idf_build_get_property(toolchain IDF_TOOLCHAIN)
if(NOT toolchain)
idf_die("IDF_TOOLCHAIN build property not set")
endif()
idf_build_get_property(toolchain_file IDF_TOOLCHAIN_FILE)
if(NOT toolchain_file)
idf_die("IDF_TOOLCHAIN_FILE build property not set")
endif()
endfunction()
# Test idf_build_library
function(test_idf_build_library)
# Create idflibtest with specific set of components and test that it
# contains them.
set(components app_trace app_update bootloader bootloader_support bt cmock)
set(idflib idflibtest)
idf_build_library("${idflib}" COMPONENTS "${components}")
if(NOT TARGET "${idflib}")
idf_die("'${idflib}' not created")
endif()
idf_library_get_property(lib_components "${idflib}" LIBRARY_COMPONENTS)
if(NOT "${lib_components}" STREQUAL "${components}")
idf_die("Library '${idflib}' components '${lib_components}' do not match "
"expected components '${components}'")
endif()
# Create idflibtest2 without specifying COMPONENTS and test that it
# contains all discovered components.
set(idflib idflibtest2)
idf_build_library("${idflib}")
if(NOT TARGET "${idflib}")
idf_die("'${idflib}' not created")
endif()
idf_library_get_property(lib_components "${idflib}" LIBRARY_COMPONENTS)
idf_build_get_property(component_names COMPONENTS_DISCOVERED)
if(NOT "${lib_components}" STREQUAL "${component_names}")
idf_die("Library '${idflib}' components '${lib_components}' do not match "
"COMPONENTS_DISCOVERED")
endif()
endfunction()
function(test_kconfig)
# Check that kconfig output files were generated
idf_build_get_property(config_dir CONFIG_DIR)
set(output_files sdkconfig.h sdkconfig.cmake sdkconfig.json)
foreach(file ${output_files})
set(file_path "${config_dir}/${file}")
if(NOT EXISTS "${file_path}")
idf_die("Missing kconfig output: ${file_path}")
endif()
file(SIZE "${file_path}" file_size)
if(file_size EQUAL 0)
idf_die("Empty kconfig output: ${file_path}")
endif()
endforeach()
# Check that kconfig targets were created
set(targets menuconfig confserver save-defconfig)
foreach(target ${targets})
if(NOT TARGET ${target})
idf_die("Missing kconfig target: ${target}")
endif()
endforeach()
endfunction()
# Test that PROJECT_NAME and PROJECT_VER build property is set and contain
# values provided in project() call.
function(test_project_properties)
idf_build_get_property(project_name PROJECT_NAME)
if(NOT project_name)
idf_die("PROJECT_NAME build property not set")
endif()
if(NOT "${project_name}" STREQUAL "${PROJECT_NAME}")
idf_die("PROJECT_NAME build property '${project_name}' != '${PROJECT_NAME}'")
endif()
idf_build_get_property(project_ver PROJECT_VER)
if(NOT project_ver)
idf_die("PROJECT_VER build property not set")
endif()
if(NOT "${project_ver}" STREQUAL "${PROJECT_VERSION}")
idf_die("PROJECT_VER build property '${project_ver}' != '${PROJECT_VERSION}'")
endif()
endfunction()
# Test that the targets for component1 and component2 are created when
# component2 is included.
function(test_include_component)
idf_build_library(idflibtest3 COMPONENTS component2)
idf_component_get_property(component_real_target
component2
COMPONENT_REAL_TARGET)
if(NOT TARGET ${component_real_target})
idf_die("Missing component2 target")
endif()
# Test that component1 is included as a dependency of component2.
idf_component_get_property(component_real_target
component1
COMPONENT_REAL_TARGET)
if(NOT TARGET ${component_real_target})
idf_die("Missing component1 target")
endif()
endfunction()
# Add two executables fatfs_example and hello_world_example, generate
# binary images for them and add flash and menuconfig targets.
# After configuration these can be build with
# idf.py hello_world_example_bin
# idf.py fatfs_example_bin
# or simply
# idf.py hello_world_example-flash monitor
# idf.py fatfs-flash monitor
# The menuconfig can be invoked with
# idf.py --no-hints menuconfig-hello_world
# idf.py --no-hints menuconfig-fatfs
# The confserver can be invoked with
# idf.py confserver-hello_world
# idf.py confserver-fatfs
function(test_executable)
idf_build_executable(fatfs_example
COMPONENTS fatfs_example)
idf_build_binary(fatfs_example
TARGET fatfs_example_bin
OUTPUT_FILE fatfs_example.bin)
idf_check_binary_size(fatfs_example_bin)
idf_flash_binary(fatfs_example_bin
TARGET fatfs_example-flash
NAME fatfs_example)
idf_create_menuconfig(fatfs_example
TARGET menuconfig-fatfs)
idf_build_generate_metadata(fatfs_example
OUTPUT_FILE project_description_fatfs.json)
idf_create_confserver(fatfs_example
TARGET confserver-fatfs)
idf_build_executable(hello_world_example
COMPONENTS hello_world_example)
idf_build_binary(hello_world_example
TARGET hello_world_example_bin
OUTPUT_FILE hello_world_example.bin)
idf_check_binary_size(hello_world_example_bin)
idf_flash_binary(hello_world_example_bin
TARGET hello_world_example-flash
NAME hello_world_example)
idf_create_menuconfig(hello_world_example
TARGET menuconfig-hello_world)
idf_build_generate_metadata(hello_world_example
OUTPUT_FILE project_description_hello_world.json)
idf_create_confserver(hello_world_example
TARGET confserver-hello_world)
endfunction()
# Run tests
test_idf_version()
test_python()
test_toolchain()
test_idf_build_library()
test_project_properties()
test_include_component()
test_executable()
# Create default project
idf_project_default()
# The kconfig test also verifies whether kconfig-related targets, such as
# menuconfig, are created. These targets are now generated within
# idf_project_default rather than globally, so this test should be run only
# after the default project is created.
test_kconfig()
# Call this test last because it replaces the ESP system component.
test_component_priority()
__dump_all_properties()
message("ALL TESTS PASSED")