From ea429ffdb6f799b556b21f3a2d4a661a80d79f82 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 20 Aug 2026 15:28:55 -0500 Subject: [PATCH] Derive the suffix rule map, dedupe quoting and unflag filtering, adopt the moved library backend --- esphome/build_gen/arduino8266.py | 62 +++++++++---------- .../unit_tests/build_gen/test_arduino8266.py | 4 +- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/esphome/build_gen/arduino8266.py b/esphome/build_gen/arduino8266.py index f3de978f76..432647046b 100644 --- a/esphome/build_gen/arduino8266.py +++ b/esphome/build_gen/arduino8266.py @@ -39,25 +39,19 @@ from esphome.const import KEY_CORE, KEY_FRAMEWORK_VERSION from esphome.core import CORE, EsphomeError from esphome.framework_helpers import get_project_cxx_compile_flags from esphome.helpers import mkdir_p, write_file_if_changed -from esphome.platformio.library import join_flag_args, split_flag_entry +from esphome.platformio.library import ( + SOURCE_KIND_FOR_SUFFIX, + join_flag_args, + split_flag_entry, +) _LOGGER = logging.getLogger(__name__) -# Compile rule per source suffix; keys must cover SRC_FILE_EXTENSIONS so any -# source a library manifest selects has a rule (pinned by a drift test). +# Compile rule per source suffix, derived from the shared suffix -> kind map +# so every source extension a library manifest can select has a rule. +_RULE_FOR_KIND = {"c": "cc", "cxx": "cxx", "asm": "asm"} _RULE_FOR_SUFFIX = { - ".c": "cc", - ".cpp": "cxx", - ".cc": "cxx", - ".cxx": "cxx", - ".c++": "cxx", - ".S": "asm", - ".spp": "asm", - ".SPP": "asm", - ".sx": "asm", - ".s": "asm", - ".asm": "asm", - ".ASM": "asm", + suffix: _RULE_FOR_KIND[kind] for suffix, kind in SOURCE_KIND_FOR_SUFFIX.items() } # Always excluded from the core build: ESPHome uses its own native OTA @@ -309,16 +303,11 @@ def _quote_arg(tok: str) -> str: return f'"{quoted}"' -def _q(value) -> str: - """Force-quote a path for the ninja command line (shell/CreateProcess).""" - return _quote_arg(str(value).replace("$", "$$")) - - _NEEDS_QUOTE = re.compile(r'[\s"\']') -def _shell_token(tok: str) -> str: - """Quote a lexed token only when needed; ``_q`` force-quotes paths. +def _shell_token(tok: str, force: bool = False) -> str: + """Quote a lexed token only when needed; ``force`` always quotes. Lexing strips the quoting a user wrote (``-DX="a b"`` becomes the single token ``-DX=a b``); re-quote on the way out so the compiler receives the @@ -328,9 +317,14 @@ def _shell_token(tok: str) -> str: PlatformIO parity. """ tok = tok.replace("$", "$$") # ninja would expand a bare $ to nothing - if not _NEEDS_QUOTE.search(tok): - return tok - return _quote_arg(tok) + if force or _NEEDS_QUOTE.search(tok): + return _quote_arg(tok) + return tok + + +def _q(value) -> str: + """Force-quote a path for the ninja command line (shell/CreateProcess).""" + return _shell_token(str(value), force=True) def _defines_flags( @@ -505,7 +499,7 @@ def write_project(paths: dict[str, Path]) -> bool: Returns True when ``build.ninja`` changed, so the caller can skip work derived purely from it (the compile database) on unchanged builds. """ - from esphome.arduino8266.component import resolve_libraries + from esphome.arduino.library import resolve_libraries from esphome.arduino8266.framework import ccache_path framework = paths["framework_path"] @@ -528,7 +522,12 @@ def write_project(paths: dict[str, Path]) -> bool: variant_dir = framework / "variants" / board_build["variant"] src_dir = CORE.relative_src_path() - libraries = resolve_libraries(framework) + libraries = resolve_libraries( + framework, + pio_platform="espressif8266", + board_mcu="esp8266", + cache_key="arduino8266", + ) # A missing install directory would otherwise surface as a wall of # include errors; failing here names the path instead. @@ -574,11 +573,10 @@ def write_project(paths: dict[str, Path]) -> bool: # build_unflags applies to the framework flag sets too (compile and link), # as under PlatformIO (a silently ignored ``build_unflags: -Os`` would # diverge between the toolchains). - cflags = [f for f in cflags if f not in unflags] - cxxflags = [f for f in cxxflags if f not in unflags] - asflags = [f for f in asflags if f not in unflags] - - link_flags = [f for f in _LINKFLAGS if f not in unflags] + cflags, cxxflags, asflags, link_flags = ( + [f for f in flags if f not in unflags] + for flags in (cflags, cxxflags, asflags, _LINKFLAGS) + ) if esp8266_data[KEY_SCANF_FLOAT]: link_flags += ["-u", "_scanf_float"] link_flags += project_link_flags diff --git a/tests/unit_tests/build_gen/test_arduino8266.py b/tests/unit_tests/build_gen/test_arduino8266.py index 4b0c2e8af7..69f84896ca 100644 --- a/tests/unit_tests/build_gen/test_arduino8266.py +++ b/tests/unit_tests/build_gen/test_arduino8266.py @@ -201,7 +201,7 @@ def _write_ninja( with ( patch.object(arduino8266, "generate_ld_scripts"), patch( - "esphome.arduino8266.component.resolve_libraries", + "esphome.arduino.library.resolve_libraries", return_value=libraries or [], ), patch("esphome.arduino8266.framework.ccache_path", return_value=ccache), @@ -460,7 +460,7 @@ def test_generate_ld_scripts_testing_mode(tmp_path: Path) -> None: def test_write_project_libraries_and_variant( tmp_path: Path, caplog: pytest.LogCaptureFixture ) -> None: - from esphome.arduino8266.component import ArduinoLibrary + from esphome.arduino.library import ArduinoLibrary paths = _make_framework(tmp_path) variant_src = paths["framework_path"] / "variants" / "nodemcu" / "variant.cpp"