diff --git a/esphome/build_gen/arduino8266.py b/esphome/build_gen/arduino8266.py index e29ffca66d..bccdb23d0d 100644 --- a/esphome/build_gen/arduino8266.py +++ b/esphome/build_gen/arduino8266.py @@ -176,10 +176,15 @@ def _flag_defines() -> dict[str, str]: defines: dict[str, str] = {} for flag in CORE.build_flags: # Shell-lex multi-token entries the way PlatformIO does, so a knob - # in "-DKNOB -DOTHER" is still detected; single tokens pass verbatim - # to keep any quoting in their bodies intact. - for tok in split_flag_entry(flag, "esphome") if " " in flag else (flag,): - if tok.startswith("-D"): + # in "-DKNOB -DOTHER" or a spaced "-D KNOB" is still detected; + # single tokens pass verbatim to keep quoting in their bodies intact. + tokens = ( + join_flag_args(split_flag_entry(flag, "esphome"), "esphome") + if " " in flag + else (flag,) + ) + for tok in tokens: + if tok.startswith("-D") and len(tok) > 2: body = tok[2:] defines[body.split("=", 1)[0]] = body return defines diff --git a/esphome/platformio/library.py b/esphome/platformio/library.py index c1e659e0f6..753bbdd8a3 100644 --- a/esphome/platformio/library.py +++ b/esphome/platformio/library.py @@ -564,11 +564,12 @@ def split_flag_entry(entry: str, owner: str) -> list[str]: def join_flag_args(tokens: Iterable[str], owner: str) -> list[str]: - """Join a bare ``-I``/``-L``/``-l`` with its following token (PIO lexing).""" + """Join a bare ``-I``/``-L``/``-l``/``-D`` with its following token, + the way PlatformIO's ParseFlags lexes them.""" out: list[str] = [] it = iter(tokens) for tok in it: - if tok in ("-I", "-L", "-l"): + if tok in ("-I", "-L", "-l", "-D"): arg = next(it, None) if arg is None: _LOGGER.warning("Ignoring trailing '%s' in %s build flags", tok, owner) diff --git a/tests/unit_tests/build_gen/test_arduino8266.py b/tests/unit_tests/build_gen/test_arduino8266.py index f5d1368c94..a511226867 100644 --- a/tests/unit_tests/build_gen/test_arduino8266.py +++ b/tests/unit_tests/build_gen/test_arduino8266.py @@ -665,3 +665,11 @@ def test_write_project_empty_core_raises(tmp_path: Path) -> None: pytest.raises(EsphomeError, match="no core sources"), ): arduino8266.write_project(paths) + + +def test_flag_defines_joins_spaced_define() -> None: + """A spaced "-D KNOB" entry is detected exactly as PlatformIO detects it.""" + _set_flags("-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH") + defines = _flag_defines() + assert "PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH" in defines + assert "" not in defines diff --git a/tests/unit_tests/test_platformio_library.py b/tests/unit_tests/test_platformio_library.py index 6c7f6d6462..25af9f6794 100644 --- a/tests/unit_tests/test_platformio_library.py +++ b/tests/unit_tests/test_platformio_library.py @@ -538,5 +538,9 @@ def test_split_flag_entry_unbalanced_quote_is_clean() -> None: from esphome.platformio.library import split_flag_entry assert split_flag_entry('-DX="a b"', "library x") == ["-DX=a b"] + # join_flag_args re-glues a spaced -D like ParseFlags does + from esphome.platformio.library import join_flag_args + + assert join_flag_args(["-D", "FOO=1", "-Os"], "x") == ["-DFOO=1", "-Os"] with pytest.raises(EsphomeError, match=r"Malformed build flag.*library x"): split_flag_entry('-DX="unclosed', "library x")