Merge branch 'esp32-idf-pch' into platformio-pch-rp2

This commit is contained in:
J. Nick Koston
2026-08-25 20:56:16 -05:00
4 changed files with 37 additions and 2 deletions
+6 -1
View File
@@ -146,7 +146,12 @@ def _include_closure(src_dir: Path, roots: Iterable[str]) -> dict[str, bytes]:
data = f"<unreadable:{st.st_mtime_ns}:{st.st_size}>".encode()
seen[rel] = data
parent = posixpath.dirname(rel)
stack.extend((inc.decode(), parent) for inc in _INCLUDE_RE.findall(data))
stack.extend(
# surrogateescape: a non-UTF-8 include name must not abort the
# build; it simply will not resolve and ends the walk
(inc.decode(errors="surrogateescape"), parent)
for inc in _INCLUDE_RE.findall(data)
)
return seen
+12 -1
View File
@@ -54,7 +54,10 @@ def _include_closure(src_dir: Path, roots: list) -> dict:
data = f"<unreadable:{st.st_mtime_ns}:{st.st_size}>".encode()
seen[rel] = data
parent = posixpath.dirname(rel)
stack.extend((inc.decode(), parent) for inc in _INCLUDE_RE.findall(data))
stack.extend(
(inc.decode(errors="surrogateescape"), parent)
for inc in _INCLUDE_RE.findall(data)
)
return seen
@@ -264,6 +267,14 @@ def _setup_pch() -> None:
):
if key not in os.environ:
projenv["ENV"][key] = value # noqa: F821
sloppiness = os.environ.get("CCACHE_SLOPPINESS")
if sloppiness is not None:
missing = [t for t in ("pch_defines", "time_macros") if t not in sloppiness]
if missing:
# Without these ccache declines every pch-consuming compile;
# union rather than override so the user's own tokens survive
projenv["ENV"]["CCACHE_SLOPPINESS"] = ",".join((sloppiness, *missing)) # noqa: F821
print(f"ESPHome: adding {','.join(missing)} to CCACHE_SLOPPINESS for the pch")
# Prepended so it is processed before the build_src_flags -include
# entries: GCC only uses a .gch while no other tokens have been seen.
@@ -166,3 +166,12 @@ def test_include_closure_raises_when_identity_unknown(
with pytest.raises(OSError, match="stat failed"):
pch._include_closure(_FakeSrcDir(), ["a.h"])
assert "Could not read a.h" in caplog.text
def test_include_closure_survives_non_utf8_include_name(tmp_path: Path) -> None:
"""A non-UTF-8 quoted include must not abort the build; it simply does
not resolve and ends the walk."""
(tmp_path / "a.h").write_bytes(b'#include "bad\xff.h"\n#include "b.h"\n')
(tmp_path / "b.h").write_text("")
closure = pch._include_closure(tmp_path, ["a.h"])
assert set(closure) == {"a.h", "b.h"}
@@ -273,6 +273,16 @@ def test_copy_pch_script(tmp_path: Path) -> None:
assert (tmp_path / "pch.py").read_text() == _SCRIPT.read_text()
def test_pch_script_unions_user_sloppiness(
tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
"""A user CCACHE_SLOPPINESS without the pch tokens gets them unioned on,
mirroring ccache_pch_env, or every src TU is a permanent miss."""
scons_env = _run_script(tmp_path, env_vars={"CCACHE_SLOPPINESS": "locale"})
assert scons_env["ENV"]["CCACHE_SLOPPINESS"] == "locale,pch_defines,time_macros"
assert "adding pch_defines,time_macros" in capsys.readouterr().out
def test_pch_script_nobuild_without_projenv_is_noop(tmp_path: Path) -> None:
"""-t nobuild never exports projenv; the script must not abort."""
proj = tmp_path / "dev"