Address review: route versioned bare libraries to the registry, deterministic MMU order, scoped toolchain branches, diagnostics

This commit is contained in:
J. Nick Koston
2026-08-20 00:00:51 -05:00
parent 66f6f5c004
commit 60b7b874f1
13 changed files with 137 additions and 16 deletions
+2 -2
View File
@@ -813,7 +813,7 @@ def write_cpp_file() -> int:
from esphome.build_gen import espidf
espidf.write_project()
elif CORE.using_toolchain_arduino:
elif CORE.is_esp8266 and CORE.using_toolchain_arduino:
# The ninja project is generated at compile time by
# esphome.arduino8266.toolchain (it needs the downloaded framework).
pass
@@ -968,7 +968,7 @@ def upload_using_esptool(
flash_images = [
FlashImage(path=toolchain.get_factory_firmware_path(), offset="0x0")
]
elif CORE.using_toolchain_arduino:
elif CORE.is_esp8266 and CORE.using_toolchain_arduino:
# The native backend writes PlatformIO-compatible output paths, so the
# shared property already points at the right file.
flash_images = [FlashImage(path=CORE.firmware_bin, offset="0x0")]
+15 -2
View File
@@ -78,7 +78,13 @@ def _library_info(name: str, read_path: Path, data: dict) -> ArduinoLibrary:
include_flags: list[str] = []
for tok in it:
if tok in ("-I", "-L", "-l"):
tok += next(it, "")
arg = next(it, None)
if arg is None:
_LOGGER.warning(
"Ignoring trailing '%s' in library %s build flags", tok, name
)
break
tok += arg
if tok.startswith("-I"):
include_flags.append(tok[2:])
elif tok.startswith("-L"):
@@ -116,7 +122,14 @@ def resolve_libraries(framework_path: Path) -> list[ArduinoLibrary]:
bundled: list[ArduinoLibrary] = []
external: list[Library] = []
for library in CORE.platformio_libraries.values():
if library.repository or not library.name or "/" in library.name:
# A version pin means a registry package ("pngle@1.1.0"), never a
# framework-bundled library.
if (
library.repository
or library.version
or not library.name
or "/" in library.name
):
external.append(library)
elif (framework_path / "libraries" / library.name).is_dir():
bundled.append(_bundled_library(framework_path, library.name))
+3 -1
View File
@@ -92,7 +92,8 @@ def _parse_app_size(build_dir: Path) -> int | None:
try:
ld_text = get_flash_ld_path(build_dir).read_text(encoding="utf-8")
except OSError:
except OSError as err:
_LOGGER.debug("Cannot read linker script for the Flash summary: %s", err)
return None
return segment_length(ld_text, "irom0_0_seg")
@@ -114,6 +115,7 @@ def _print_size_summary(build_dir: Path, toolchain_path: Path) -> None:
close_fds=False,
)
if result.returncode != 0:
_LOGGER.warning("Could not summarize firmware size: %s", result.stderr)
return
sections: dict[str, int] = {}
for line in result.stdout.splitlines():
+13 -2
View File
@@ -199,8 +199,10 @@ def _resolve_build_config(defines: dict[str, str]) -> _BuildConfig:
if "PIO_FRAMEWORK_ARDUINO_WAVEFORM_LOCKED_PHASE" in defines:
knob_defines.append("WAVEFORM_LOCKED_PHASE=1")
# Sorted so the pick is deterministic: the dict is built from a set of
# build flags, whose iteration order varies between processes.
vtables = next(
(name for name in defines if name.startswith("VTABLES_IN_")),
(name for name in sorted(defines) if name.startswith("VTABLES_IN_")),
"VTABLES_IN_FLASH",
)
@@ -233,7 +235,9 @@ def _resolve_build_config(defines: dict[str, str]) -> _BuildConfig:
"PIO_FRAMEWORK_ARDUINO_MMU_CUSTOM requires MMU_IRAM_SIZE and "
"MMU_ICACHE_SIZE build flags"
)
mmu = [body for name, body in defines.items() if name.startswith("MMU_")]
# Sorted so build.ninja and the linker-script stamp stay byte-stable
# across runs (the flag set has no deterministic iteration order).
mmu = sorted(body for name, body in defines.items() if name.startswith("MMU_"))
else:
mmu = ["MMU_IRAM_SIZE=0x8000", "MMU_ICACHE_SIZE=0x8000"]
@@ -419,6 +423,13 @@ def write_project(paths: dict[str, Path]) -> bool:
libraries = resolve_libraries(framework)
# A missing framework-owned directory is a broken install; failing here
# names the path instead of producing a wall of include errors.
for required in (sdk / "include", core_dir, sdk / "lwip2" / "include", variant_dir):
if not required.is_dir():
raise EsphomeError(
f"Arduino framework install is incomplete: missing {required}"
)
include_dirs = [
src_dir,
sdk / "include",
+13 -1
View File
@@ -62,7 +62,19 @@ def apply_extra_script(
source_path = component.source_dir
library_root = source_path.resolve()
script_path = (source_path / extra_script).resolve()
if not script_path.is_relative_to(library_root) or not script_path.is_file():
if not script_path.is_relative_to(library_root):
_LOGGER.warning(
"Ignoring extraScript %s of library %s: it escapes the library directory",
extra_script,
component.name,
)
return
if not script_path.is_file():
_LOGGER.debug(
"extraScript %s of library %s not found; skipping",
extra_script,
component.name,
)
return
if callable(idf_target):
idf_target = idf_target()