feat(cmakev2): preprocess linker scripts with component includes

Resolve #include lines in linker script templates against the linked
component graph: idf_build_library appends every linked component's
INCLUDE_DIRS to the C preprocessor invocation for each .in linker
script, so a template can include any component header (e.g. a ULP
memory-layout template including soc/soc.h) without the owning
component having to know about it.

Also:
- Always pass -I<config_dir> so templates can include sdkconfig.h.
- Add a FLAGS option to target_linker_script for explicit preprocessor
  flags (e.g. -D__ASSEMBLER__ or ld-snippet include dirs); when given,
  FLAGS replaces the parent-dir==target include heuristic for that
  script.
- Add a MEMORY option to target_linker_script that emits the marked
  linker script as -T before all others, so section-placement scripts
  in one component can reference MEMORY regions and REGION_ALIASes
  declared by a memory-layout script in another component.
- Make C-preprocessor comment keeping (-C) part of the default flag set
  rather than hardcoded, so FLAGS can drop it. linker_script_preprocessor
  no longer forces -C; both the cmakev1 and cmakev2 preprocessors add it
  to their default CFLAGS (output unchanged for existing scripts). A ULP
  template that includes soc/soc.h omits -C so ld does not choke on the
  header's // comments.
- Store per-script metadata (generated output, flags) in MD5-keyed
  component properties instead of parallel lists.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
This commit is contained in:
Frantisek Hrbata
2026-07-15 09:14:35 +09:00
committed by Renz Bagaporo
parent a78b61cf19
commit aaca1e20ea
5 changed files with 184 additions and 50 deletions
+42 -4
View File
@@ -165,6 +165,25 @@ endfunction()
``linkerscript`` template. The ``linkerscript`` is processed with ldgen
to produce the ``output``.
*FLAGS[in,opt]*
Explicit preprocessor flags for the linker script(s) registered by this
call, for example ``-D`` defines or extra ``-I`` include directories.
When given, they replace the default parent-dir==target include
heuristic while a ``.in`` script or template is preprocessed.
``-I<config_dir>`` and the linked components' include directories are
always added regardless. Applies to every ``scriptfile`` in the same
call.
*MEMORY[opt]*
Marks the script(s) as the memory-layout base for the link. Such
scripts are emitted as ``-T`` before all other linker scripts, so that
section-placement scripts from other components can reference their
``MEMORY`` regions and ``REGION_ALIAS`` names. Needed when the memory
layout lives in a different component than the section scripts that
depend on it.
This function adds one or more linker scripts to the specified component
target, incorporating the linker script into the linking process.
@@ -178,19 +197,38 @@ function(target_linker_script target deptype scriptfiles)
# The linker script files, templates, and their output filenames are stored
# only as component properties. The script files are generated and added to
# the library link interface in the idf_build_library function.
set(options)
set(one_value PROCESS)
set(options MEMORY)
set(one_value PROCESS FLAGS)
set(multi_value)
cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN})
foreach(scriptfile ${scriptfiles})
get_filename_component(scriptfile "${scriptfile}" ABSOLUTE)
idf_msg("Adding linker script ${scriptfile}")
__linker_script_key("${scriptfile}" script_key)
if(ARG_PROCESS)
get_filename_component(output "${ARG_PROCESS}" ABSOLUTE)
idf_component_set_property("${target}" LINKER_SCRIPTS_TEMPLATE "${scriptfile}" APPEND)
idf_component_set_property("${target}" LINKER_SCRIPTS_GENERATED "${output}" APPEND)
# Key the generated output path by the template instead of keeping a
# second list index-aligned with LINKER_SCRIPTS_TEMPLATE.
idf_component_set_property("${target}" "LINKER_SCRIPT_GENERATED_${script_key}" "${output}")
else()
idf_component_set_property("${target}" LINKER_SCRIPTS ${scriptfile} APPEND)
idf_component_set_property("${target}" LINKER_SCRIPTS "${scriptfile}" APPEND)
endif()
# Memory-layout scripts are emitted before other scripts in the link,
# so section-placement scripts can reference their MEMORY regions.
if(ARG_MEMORY)
idf_component_set_property("${target}" "LINKER_SCRIPT_MEMORY_${script_key}" TRUE)
endif()
# Per-script preprocessor flags, consumed by __preprocess_linker_script
# when a ".in" script or template is built. The "__DEFAULT__" sentinel
# means FLAGS was not given (use the parent-dir==target heuristic); any
# other value, including empty, means FLAGS was given and replaces it.
# This distinguishes "not given" from "given empty", which the property
# value alone cannot (both would read back as empty).
if(DEFINED ARG_FLAGS)
idf_component_set_property("${target}" "LINKER_SCRIPT_FLAGS_${script_key}" "${ARG_FLAGS}")
else()
idf_component_set_property("${target}" "LINKER_SCRIPT_FLAGS_${script_key}" "__DEFAULT__")
endif()
endforeach()
endfunction()