mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 11:03:11 +00:00
Merge branch 'feat/add_merged_hints_to_build_v6.0' into 'release/v6.0'
Build & Config: Create a merged hints database in the build directory (v6.0) See merge request espressif/esp-idf!46963
This commit is contained in:
@@ -382,6 +382,7 @@ function(__project_info test_components)
|
||||
# file with cmake's variables substituted and unprocessed generator expressions. The second
|
||||
# step, with file(GENERATE), processes the temporary file and substitute generator expression
|
||||
# into the final project_description.json file.
|
||||
set(HINTS_FILE "${build_dir}/hints.yml")
|
||||
configure_file("${idf_path}/tools/cmake/project_description.json.in"
|
||||
"${build_dir}/project_description.json.templ")
|
||||
file(READ "${build_dir}/project_description.json.templ" project_description_json_templ)
|
||||
@@ -392,6 +393,25 @@ function(__project_info test_components)
|
||||
# Generate component dependency graph
|
||||
depgraph_generate("${build_dir}/component_deps.dot")
|
||||
|
||||
# Assumption: all hints.yml files are bare YAML lists (no "---" document
|
||||
# separators). Plain string concatenation is safe under this assumption.
|
||||
# Note for consumers: yaml.safe_load() only parses the first YAML document,
|
||||
# so document separators in source files would cause data loss.
|
||||
set(_merged_hints "")
|
||||
set(_global_hints_file "${idf_path}/tools/idf_py_actions/hints.yml")
|
||||
if(EXISTS "${_global_hints_file}")
|
||||
file(READ "${_global_hints_file}" _hints_content)
|
||||
string(APPEND _merged_hints "${_hints_content}\n")
|
||||
endif()
|
||||
foreach(_comp_dir ${build_component_paths} ${test_component_paths})
|
||||
set(_hints_file "${_comp_dir}/hints.yml")
|
||||
if(EXISTS "${_hints_file}")
|
||||
file(READ "${_hints_file}" _hints_content)
|
||||
string(APPEND _merged_hints "${_hints_content}\n")
|
||||
endif()
|
||||
endforeach()
|
||||
file(WRITE "${build_dir}/hints.yml" "${_merged_hints}")
|
||||
|
||||
# We now have the following component-related variables:
|
||||
#
|
||||
# build_components is the list of components to include in the build.
|
||||
|
||||
@@ -35,5 +35,6 @@
|
||||
"03_py_extensions": "${gdbinit_files_py_extensions}",
|
||||
"04_connect": "${gdbinit_files_connect}"
|
||||
},
|
||||
"debug_arguments_openocd": "${debug_arguments_openocd}"
|
||||
"debug_arguments_openocd": "${debug_arguments_openocd}",
|
||||
"hints_file": "${HINTS_FILE}"
|
||||
}
|
||||
|
||||
@@ -754,7 +754,8 @@ endfunction()
|
||||
|
||||
idf_build_generate_metadata([BINARY <binary>]
|
||||
[EXECUTABLE <executable>]
|
||||
[OUTPUT_FILE <file>])
|
||||
[OUTPUT_FILE <file>]
|
||||
[HINTS_OUTPUT_FILE <file>])
|
||||
|
||||
*BINARY[in,opt]*
|
||||
|
||||
@@ -769,6 +770,13 @@ endfunction()
|
||||
Optional output file path for storing the metadata. If not provided,
|
||||
the default path ``<build>/project_description.json`` is used.
|
||||
|
||||
*HINTS_OUTPUT_FILE[in,opt]*
|
||||
|
||||
Optional output file path for storing the merged hints YAML file. If
|
||||
not provided, hints generation is skipped entirely. This opt-in
|
||||
behaviour prevents hint files from different binaries overwriting each
|
||||
other in multi-binary projects.
|
||||
|
||||
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 ``<build>/project_description.json`` will be
|
||||
@@ -776,7 +784,7 @@ endfunction()
|
||||
#]]
|
||||
function(idf_build_generate_metadata)
|
||||
set(options)
|
||||
set(one_value OUTPUT_FILE BINARY EXECUTABLE)
|
||||
set(one_value OUTPUT_FILE BINARY EXECUTABLE HINTS_OUTPUT_FILE)
|
||||
set(multi_value)
|
||||
cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN})
|
||||
|
||||
@@ -865,11 +873,37 @@ function(idf_build_generate_metadata)
|
||||
|
||||
get_filename_component(ARG_OUTPUT_FILE "${ARG_OUTPUT_FILE}" ABSOLUTE BASE_DIR "${BUILD_DIR}")
|
||||
|
||||
if(DEFINED ARG_HINTS_OUTPUT_FILE)
|
||||
set(HINTS_FILE "${ARG_HINTS_OUTPUT_FILE}")
|
||||
else()
|
||||
set(HINTS_FILE "")
|
||||
endif()
|
||||
configure_file("${IDF_PATH}/tools/cmake/project_description.json.in" "${ARG_OUTPUT_FILE}.templ")
|
||||
file(READ "${ARG_OUTPUT_FILE}.templ" project_description_json_templ)
|
||||
file(REMOVE "${ARG_OUTPUT_FILE}.templ")
|
||||
file(GENERATE OUTPUT "${ARG_OUTPUT_FILE}"
|
||||
CONTENT "${project_description_json_templ}")
|
||||
|
||||
# Assumption: all hints.yml files are bare YAML lists (no "---" document
|
||||
# separators). Plain string concatenation is safe under this assumption.
|
||||
# Note for consumers: yaml.safe_load() only parses the first YAML document,
|
||||
# so document separators in source files would cause data loss.
|
||||
if(DEFINED ARG_HINTS_OUTPUT_FILE)
|
||||
set(_merged_hints "")
|
||||
set(_global_hints_file "${IDF_PATH}/tools/idf_py_actions/hints.yml")
|
||||
if(EXISTS "${_global_hints_file}")
|
||||
file(READ "${_global_hints_file}" _hints_content)
|
||||
string(APPEND _merged_hints "${_hints_content}\n")
|
||||
endif()
|
||||
foreach(_comp_dir ${build_component_paths})
|
||||
set(_hints_file "${_comp_dir}/hints.yml")
|
||||
if(EXISTS "${_hints_file}")
|
||||
file(READ "${_hints_file}" _hints_content)
|
||||
string(APPEND _merged_hints "${_hints_content}\n")
|
||||
endif()
|
||||
endforeach()
|
||||
file(WRITE "${ARG_HINTS_OUTPUT_FILE}" "${_merged_hints}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
#[[
|
||||
|
||||
@@ -741,7 +741,8 @@ function(__project_default)
|
||||
TARGET app-flash
|
||||
NAME "app"
|
||||
FLASH)
|
||||
idf_build_generate_metadata(BINARY "${executable}_binary_signed")
|
||||
idf_build_generate_metadata(BINARY "${executable}_binary_signed"
|
||||
HINTS_OUTPUT_FILE "${BUILD_DIR}/hints.yml")
|
||||
else()
|
||||
idf_build_binary("${executable}"
|
||||
OUTPUT_FILE "${build_dir}/${executable}.bin"
|
||||
@@ -758,12 +759,14 @@ function(__project_default)
|
||||
|
||||
idf_create_dfu("${executable}_binary"
|
||||
TARGET dfu)
|
||||
idf_build_generate_metadata(BINARY "${executable}_binary")
|
||||
idf_build_generate_metadata(BINARY "${executable}_binary"
|
||||
HINTS_OUTPUT_FILE "${BUILD_DIR}/hints.yml")
|
||||
endif()
|
||||
|
||||
idf_build_generate_flasher_args()
|
||||
else()
|
||||
idf_build_generate_metadata(EXECUTABLE "${executable}")
|
||||
idf_build_generate_metadata(EXECUTABLE "${executable}"
|
||||
HINTS_OUTPUT_FILE "${BUILD_DIR}/hints.yml")
|
||||
endif()
|
||||
|
||||
idf_create_menuconfig("${executable}"
|
||||
|
||||
@@ -11,6 +11,7 @@ import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from test_build_system_helpers import EnvDict
|
||||
from test_build_system_helpers import IdfPyFunc
|
||||
from test_build_system_helpers import append_to_file
|
||||
@@ -397,3 +398,46 @@ def test_hints_components_loading(
|
||||
assert 'HINT FROM PROJECT COMPONENT' in ret.stderr, (
|
||||
'Hint from project component should be displayed in build output'
|
||||
)
|
||||
|
||||
|
||||
def test_merged_hints_artifact_in_build_dir(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
"""Check that hints.yml is generated in the build directory and that hints from all components are merged"""
|
||||
# Create a local component with a uniquely identifiable hint entry so we
|
||||
# can verify it ends up in the merged output.
|
||||
test_comp_dir = test_app_copy / 'components' / 'test_hint_comp'
|
||||
test_comp_dir.mkdir(parents=True, exist_ok=True)
|
||||
(test_comp_dir / 'CMakeLists.txt').write_text('idf_component_register()\n')
|
||||
(test_comp_dir / 'hints.yml').write_text(
|
||||
'- re: "UNIQUE_TEST_HINT_MARKER_12345"\n hint: "This is a test hint for merge verification"\n'
|
||||
)
|
||||
# In buildv2, only components in the REQUIRES chain are included in
|
||||
# build_component_paths. Add test_hint_comp so its hints are merged.
|
||||
# This call is harmless in v1 (all components are auto-discovered).
|
||||
replace_in_file(
|
||||
test_app_copy / 'main' / 'CMakeLists.txt',
|
||||
'# placeholder_inside_idf_component_register',
|
||||
'REQUIRES test_hint_comp',
|
||||
)
|
||||
|
||||
idf_py('reconfigure')
|
||||
hints_file = test_app_copy / 'build' / 'hints.yml'
|
||||
assert hints_file.is_file(), 'hints.yml should exist in the build directory after reconfigure'
|
||||
content = hints_file.read_text(encoding='utf-8')
|
||||
parsed = yaml.safe_load(content)
|
||||
assert isinstance(parsed, list), 'hints.yml should be a valid YAML list'
|
||||
assert len(parsed) > 0, 'hints.yml should be non-empty'
|
||||
|
||||
# Verify hints from the custom component are actually merged in
|
||||
hint_patterns = [entry.get('re', '') for entry in parsed if isinstance(entry, dict)]
|
||||
assert any('UNIQUE_TEST_HINT_MARKER_12345' in p for p in hint_patterns), (
|
||||
'Custom component hint should be present in merged hints.yml'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.buildv2_skip('hello_world uses cmake/project.cmake (v1 only)')
|
||||
def test_merged_hints_artifact_real_project(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
"""Check that hints.yml is generated in a custom build directory (-B flag)"""
|
||||
# Verify the build dir is dynamic, not hardcoded
|
||||
idf_py('-B', 'custom_build', 'reconfigure')
|
||||
custom_hints_file = test_app_copy / 'custom_build' / 'hints.yml'
|
||||
assert custom_hints_file.is_file(), 'hints.yml should exist in a custom build directory'
|
||||
|
||||
Reference in New Issue
Block a user