mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
Hash project-local include dirs into the pch checksum and share the registration gate
This commit is contained in:
@@ -50,6 +50,12 @@ def ccache_pch_env() -> dict[str, str]:
|
||||
return {k: v for k, v in _CCACHE_PCH_ENV.items() if k not in os.environ}
|
||||
|
||||
|
||||
def pch_extra_scripts() -> list[str]:
|
||||
"""The extra_scripts entries a PlatformIO platform registers for the
|
||||
pch; empty when disabled (the script itself has no enable check)."""
|
||||
return ["post:pch.py"] if pch_enabled() else []
|
||||
|
||||
|
||||
def pch_header_text(include_headers: Iterable[str]) -> str:
|
||||
"""The prefix-header source: exactly these includes, in order."""
|
||||
return "".join(f'#include "{name}"\n' for name in include_headers)
|
||||
|
||||
@@ -6,7 +6,7 @@ import subprocess
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from esphome.build_helpers.pch import pch_enabled
|
||||
from esphome.build_helpers.pch import pch_extra_scripts
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -421,9 +421,7 @@ async def to_code(config: ConfigType) -> None:
|
||||
]
|
||||
if not enable_scanf_float:
|
||||
extra_scripts.append("pre:remove_float_scanf.py")
|
||||
# Generation-time gate: the script itself has no enable check
|
||||
if pch_enabled():
|
||||
extra_scripts.append("post:pch.py")
|
||||
extra_scripts.extend(pch_extra_scripts())
|
||||
extra_scripts.append("post:post_build.py")
|
||||
cg.add_platformio_option("extra_scripts", extra_scripts)
|
||||
|
||||
|
||||
@@ -115,6 +115,28 @@ def _setup_pch() -> None:
|
||||
digest.update(rel.encode())
|
||||
digest.update(closure[rel])
|
||||
digest.update(b"\0")
|
||||
# Project-local include dirs outside src (e.g. rp2's lwip_override)
|
||||
# hold generated headers the src closure cannot see; hash them so an
|
||||
# ESPHome-side change invalidates an existing build dir
|
||||
prev = ""
|
||||
for tok in flags:
|
||||
inc = tok[2:] if tok.startswith("-I") and len(tok) > 2 else ""
|
||||
if prev == "-I":
|
||||
inc = tok
|
||||
prev = tok
|
||||
if not inc:
|
||||
continue
|
||||
inc_dir = Path(inc)
|
||||
if not (
|
||||
inc_dir.is_dir()
|
||||
and inc_dir.is_relative_to(proj_dir)
|
||||
and not inc_dir.is_relative_to(src_dir)
|
||||
):
|
||||
continue
|
||||
for local in sorted(inc_dir.rglob("*.h")):
|
||||
digest.update(str(local.relative_to(proj_dir)).encode())
|
||||
digest.update(local.read_bytes())
|
||||
digest.update(b"\0")
|
||||
checksum = digest.hexdigest()
|
||||
|
||||
# The ccache .sum sidecar doubles as the freshness stamp
|
||||
|
||||
@@ -120,3 +120,10 @@ def test_include_closure_marks_unreadable(
|
||||
locked.chmod(0o644)
|
||||
assert closure["locked.h"] == b"<unreadable>"
|
||||
assert "Could not read locked.h" in caplog.text
|
||||
|
||||
|
||||
def test_pch_extra_scripts_gated(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert pch.pch_extra_scripts() == ["post:pch.py"]
|
||||
monkeypatch.setenv("ESPHOME_PCH_ENABLE", "0")
|
||||
assert pch.pch_extra_scripts() == []
|
||||
|
||||
@@ -165,3 +165,19 @@ def test_copy_pch_script(tmp_path: Path) -> None:
|
||||
CORE.build_path = tmp_path
|
||||
toolchain.copy_pch_script()
|
||||
assert (tmp_path / "pch.py").read_text() == _SCRIPT.read_text()
|
||||
|
||||
|
||||
def test_pch_script_hashes_project_local_include_dirs(tmp_path: Path) -> None:
|
||||
"""Generated headers in project-local -I dirs (e.g. rp2's lwip_override)
|
||||
must invalidate the checksum when they change."""
|
||||
proj = tmp_path / "dev"
|
||||
override = proj / "lwip_override"
|
||||
override.mkdir(parents=True)
|
||||
(override / "lwipopts.h").write_text("#define TCP_MSS 1460\n")
|
||||
flags = ["-DX=1", "-I", str(override)]
|
||||
_run_script(tmp_path, flags=flags)
|
||||
first = (proj / "esphome_pch.h.gch.sum").read_text()
|
||||
(override / "lwipopts.h").write_text("#define TCP_MSS 536\n")
|
||||
(tmp_path / "fake-gxx.argv").unlink(missing_ok=True)
|
||||
_run_script(tmp_path, flags=flags)
|
||||
assert (proj / "esphome_pch.h.gch.sum").read_text() != first
|
||||
|
||||
Reference in New Issue
Block a user