Backend-agnostic dispatch guards, positive native polarity, warn on dropped upload_speed

This commit is contained in:
J. Nick Koston
2026-08-20 20:44:08 -05:00
parent 77e9a1d991
commit 3f96590567
4 changed files with 33 additions and 12 deletions
+19 -4
View File
@@ -813,9 +813,10 @@ def write_cpp_file() -> int:
from esphome.build_gen import espidf
espidf.write_project()
elif CORE.using_toolchain_arduino:
# The ninja project is generated at compile time by
# esphome.arduino8266.toolchain (it needs the downloaded framework).
elif CORE.using_native_toolchain:
# Native builds generate their project at compile time (the ESP8266
# ninja build needs the downloaded framework); nothing to write here,
# and never a platformio.ini (must agree with _add_platformio_options)
pass
else:
from esphome.build_gen import platformio
@@ -1937,7 +1938,15 @@ def _native_toolchain_module():
return toolchain
module = importlib.import_module("esphome.components." + CORE.target_platform)
get_native = getattr(module, "native_toolchain_module", None)
return get_native() if get_native is not None else None
native = get_native() if get_native is not None else None
if native is None and CORE.using_native_toolchain:
# A missing/renamed hook must fail, not silently degrade the native
# build's tooling to the PlatformIO path
raise EsphomeError(
f"Platform {CORE.target_platform} resolved toolchain "
f"'{CORE.toolchain.value}' but provides no native toolchain module"
)
return native
def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
@@ -2000,6 +2009,12 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
idedata = None
native_toolchain = _native_toolchain_module()
if native_toolchain is None and not CORE.using_toolchain_platformio:
_LOGGER.error(
"analyze-memory is not supported with the '%s' toolchain",
CORE.toolchain.value if CORE.toolchain else "unresolved",
)
return 1
if native_toolchain is not None:
objdump_path = str(native_toolchain.get_objdump_path())
readelf_path = str(native_toolchain.get_readelf_path())
+5 -3
View File
@@ -23,9 +23,11 @@ _LOGGER = logging.getLogger(__name__)
# ESP8266 user RAM (matches upload.maximum_ram_size in every board manifest)
_MAX_RAM_SIZE = 81920
# platformio_options keys the native build consumes (lib_ignore) or that are
# read from the raw config elsewhere (upload_speed, at upload time)
_CONSUMED_PIO_OPTIONS = frozenset({"lib_ignore", "upload_speed"})
# platformio_options keys the native build consumes. YAML-set upload_speed
# never reaches CORE.platformio_options under the native toolchain (it is
# read from the raw config at upload time), so anything here came from a
# component and genuinely is dropped; warn for it.
_CONSUMED_PIO_OPTIONS = frozenset({"lib_ignore"})
_RAM_SECTIONS = (".data", ".rodata", ".bss")
+6 -4
View File
@@ -536,7 +536,8 @@ async def finalize_serial_config() -> None:
# Called by __main__.compile_program; returning False falls through to the
# PlatformIO toolchain.
def run_compile(args, config: ConfigType) -> bool:
if CORE.using_toolchain_platformio:
# Positive check: the native backend only runs when explicitly resolved
if not CORE.using_toolchain_arduino:
return False
from esphome.arduino8266 import toolchain
@@ -547,9 +548,10 @@ def run_compile(args, config: ConfigType) -> bool:
# Called by writer.py
def copy_files() -> None:
if not CORE.using_toolchain_platformio:
# The extra scripts are PlatformIO/SCons-only; the native toolchain
# applies their logic in the build generator instead.
# Positive check, matching run_compile: only the arduino native backend
# skips the PlatformIO/SCons extra scripts (their logic lives in the
# build generator there)
if CORE.using_toolchain_arduino:
return
dir = Path(__file__).parent
for script in (
@@ -336,7 +336,9 @@ def test_warn_ignored_platformio_options(caplog: pytest.LogCaptureFixture) -> No
assert "platformio_options->board_build.ldscript is ignored" in caplog.text
assert "native 'arduino' toolchain" in caplog.text
assert "lib_ignore" not in caplog.text
assert "upload_speed" not in caplog.text
# Component-added upload_speed never gets read under the native
# toolchain, so it must warn
assert "upload_speed" in caplog.text
def test_run_compile_idedata_error_does_not_fail_build(