The board name lands unquoted in two -D bodies and the flash linker
script name joins under the SDK and build ld dirs, so both are now
shape-validated like f_cpu. A VTABLES_IN_* define carrying a body would
split the compile line from the linker script and is refused. The
damaged-cache overwrite moves into a shared _write_generated helper
scoped to the comparison read: a corrupt existing copy is logged and
replaced (the testing-mode flash ld gets the same recovery), while a
genuine write failure still raises with its cause.
A dependency whose version is a repository URL names one specific
source, so it is now detected before the backend-provided skip and
resolves as git instead of being replaced by the bundled copy. The
library header-suffix set becomes LIBRARY_HEADER_SUFFIXES so it cannot
shadow esphome.const's narrower HEADER_FILE_EXTENSIONS. Suppressing a
genuinely bundled name on an external short-name match warns (an
accidental collision would surface as link errors), a converted library
with no sources and no headers warns by name, and the walk's
unreachable nameless-dependency check is gone.
copy_src_tree is always mocked in the writer tests, so the new
missing/stale/unreadable debug branches were unreachable; the decision
moves into _build_info_stale with a test covering every branch.
voluptuous fills schema defaults in set-iteration order, so the
validated dict's key order changes with the process hash seed; the
unsorted dump churned the comment block in main.cpp and relinked the
firmware on every esphome run for any config using a defaults-heavy
action (logger.log in a button's on_press was enough). Affects the
PlatformIO path identically.
Every sources_changed site now logs which file (or which build-info
staleness) triggered it, so a config that relinks on every run can be
diagnosed from one -v compile instead of diffing the build tree.
A framework tree without libraries/ now raises naming the path instead
of silently rerouting every bundled name to the registry, matching the
empty-bundled-dir error. check_library_data accepts framework=None to
skip the framework check (mirroring platform=None), so the backend-side
platform re-check no longer re-fires the frameworks-mismatch warning
the walk already emitted. The platform-rejection-is-debug test patched
the wrong module and asserted nothing; it now patches the backend's
import and asserts the dependency is absent from the resolved set.
The walk now drains its frontier, prefetches the wave's registry
archives with a small thread pool (deduped by URL, progress bars
suppressed per thread since parallel bars would interleave), and then
processes the wave sequentially; the sequential download() call stays
authoritative so failures surface with resume exactly as before. Same
approach as the espidf tool prefetch in #18513.
voluptuous accepts [] for [cv.string], so vals[-1] could raise an
IndexError at codegen time; an empty list now falls through to the
ignored-option warning.
The backend-side bundled filter now checks compatibility silently (the
shared walk owns the warning), so one manifest fault warns once instead
of twice. Bundled-name membership uses the exact on-disk directory
names instead of a per-name is_dir() probe, so a case-insensitive
filesystem cannot match a case-mismatched dependency and build the same
bundled library twice.
The schema permits the list form, so the routing now stores the last
value (like a later platformio.ini line) and the generator always sees a
scalar. The using_native_toolchain docstring points at write_cpp_file's
dispatch so NATIVE_TOOLCHAINS membership and the project-writing branch
flip together.
An owner-qualified dependency name (Owner/Pkg, both halves safe) is the
converter's to resolve and no longer draws the malformed-entry warning,
which stays for genuinely unsafe shapes. A declared srcFilter matching
only inert files now warns like one matching nothing, while matched
headers still read as a header-only library. The short-name suppression
logs the assumed external at debug so an accidental collision is
attributable. A failing ar batch unlinks the truncated archive before
returning its exit code.
cv.boolean's inline tuples and the ccache env tables were two copies of
the same spellings; TRUTHY_BOOL_STRINGS/FALSY_BOOL_STRINGS now live in
esphome/helpers.py, cv.boolean consumes them, and parse_enable_env
derives its tables by adding the 1/0 env convention.
parse_enable_env's inline tuples become TRUTHY_ENV_STRINGS and
FALSY_ENV_STRINGS frozensets mirroring cv.boolean's spellings (enable
and disable included) plus the 1/0 env convention, matching
device-builder's TRUTHY_BOOL_STRINGS pattern.
The typed IncompatiblePlatform exception, dependency_is_usable,
warn_properties_depends, the lex_build_flags helper (espidf switches to
it), the normalize_dependencies validation, the manifest shape check,
the component-level drop-warning split, and the SCons case-sensitive
.C/.C++ suffixes all harden the shared converter independently of the
arduino backend, so they belong in this PR; the provides hook and the
version-less reconciliation stay with the backend that needs them.
build_tool gains one function per mode plus a shared rspfile reader.
_library_info becomes an orchestrator over _resolve_src_dir,
_resolve_lib_archive, _classify_build_flags, _resolve_include_dirs, and
_collect_lib_sources. The version-less reconciliation moves into
_warn_unsatisfied_versionless. _is_safe_library_name switches from a
character denylist to a filename-plain allowlist, which excludes
separators, drive colons, and dot-only names by shape.
The unmapped-suffix warning fired for every header-only library (the
default +<*> filter matches headers), so ArduinoJson would have warned
on every ESP8266 build. It now names exactly the source-like files
(.CPP, .ino and case-variants of the map) the case-sensitive suffix map
rejects, partial drops included, and stays quiet for headers and
metadata.
The ar shim batches the expanded object list by argv length (rc then q
appends), keeping the command line under the Windows 32767-char limit
the rspfile existed to avoid. A non-iterable dependencies value in a
manifest now warns by library name instead of raising a bare
TypeError.