Merge branch 'esp8266-native-pch' into esp32-idf-pch

This commit is contained in:
J. Nick Koston
2026-08-25 14:21:46 -05:00
4 changed files with 41 additions and 15 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ PCH_CORE_HEADER = "esphome/core/defines.h"
# ccache cannot hash through a .gch; CCACHE_PCH_EXTSUM makes it hash the
# .sum sidecar instead of the .gch bytes, which are not reproducible.
# Keep in sync with the literals in components/esp8266/pch.py.script.
# Keep in sync with the literals in platformio/pch.py.script.
_CCACHE_PCH_ENV = {
"CCACHE_SLOPPINESS": "pch_defines,time_macros",
"CCACHE_PCH_EXTSUM": "true",
+2 -2
View File
@@ -35,7 +35,7 @@ from esphome.core import (
)
from esphome.core.config import BOARD_MAX_LENGTH
from esphome.helpers import IS_MACOS, copy_file_if_changed
from esphome.platformio.toolchain import copy_ccache_script
from esphome.platformio.toolchain import copy_ccache_script, copy_pch_script
from esphome.storage_json import StorageJSON
from esphome.types import ConfigType
@@ -579,7 +579,6 @@ def copy_files() -> None:
dir = Path(__file__).parent
for script in (
"post_build",
"pch",
"testing_mode",
"exclude_updater",
"exclude_waveform",
@@ -591,6 +590,7 @@ def copy_files() -> None:
CORE.relative_build_path(f"{script}.py"),
)
copy_ccache_script()
copy_pch_script()
# ESP logs stack trace decoder, based on https://github.com/me-no-dev/EspExceptionDecoder
@@ -10,12 +10,13 @@ import subprocess
Import("env", "projenv") # noqa: F821
# Precompile the src force-includes plus defines.h (which pulls in
# Arduino.h) and force-include the result into C++ src compiles only; those
# TUs already include this content first, so their preprocessed output is
# unchanged. Post script: the final src flags exist, nothing compiled yet.
# Registration is gated host-side (esp8266/__init__.py, pch_enabled()).
# Keep the header tail, ccache values, include-closure recipe, and the
# checksum/failed-marker stamp flow in sync with build_helpers/pch.py.
# Arduino.h on Arduino platforms) and force-include the result into C++ src
# compiles only; those TUs already include this content first, so their
# preprocessed output is unchanged. Post script: the final src flags exist,
# nothing compiled yet. Registration is gated host-side (the platform's
# __init__.py, pch_enabled()). Keep the header tail, ccache values,
# include-closure recipe, and the checksum/failed-marker stamp flow in sync
# with build_helpers/pch.py.
_INCLUDE_RE = re.compile(rb'^\s*#\s*include\s+"([^"]+)"', re.MULTILINE)
_CORE_HEADER = "esphome/core/defines.h"
@@ -46,7 +47,16 @@ def _include_closure(src_dir: Path, roots: list) -> dict:
return seen
def _esp8266_setup_pch() -> None:
def _shell_arg(element) -> str:
"""One compiler argv from one SCons element, matching the real spawn:
SCons whole-quotes spaced elements, the shell unquotes the rest."""
arg = str(element)
if " " in arg:
return arg.replace('\\"', '"')
return shlex.split(arg)[0] if arg else arg
def _setup_pch() -> None:
# Project root, not $BUILD_DIR: SCons compiles run with the project dir
# as cwd, so "-include esphome_pch.h" resolves here as a relative path.
# An absolute path would put the per-device build path on every compile
@@ -62,7 +72,10 @@ def _esp8266_setup_pch() -> None:
# not see them; consumers keep theirs, which the .gch then satisfies.
flags = []
include_headers = []
flag_it = iter(shlex.split(projenv.subst("$CXXFLAGS $CCFLAGS $_CCCOMCOM"))) # noqa: F821
flag_it = iter(
_shell_arg(element)
for element in projenv.subst_list("$CXXFLAGS $CCFLAGS $_CCCOMCOM")[0] # noqa: F821
)
for tok in flag_it:
if tok == "-include":
include_headers.append(next(flag_it, ""))
@@ -82,10 +95,14 @@ def _esp8266_setup_pch() -> None:
flags_id = flags_id.replace(basedir, "")
digest.update(flags_id.encode())
# GCC never validates a .gch against its source headers, and PlatformIO
# package paths carry no version, so a platform bump must invalidate here
# package paths carry no version, so a package bump must invalidate here
platform = env.PioPlatform() # noqa: F821
for package in ("framework-arduinoespressif8266", "toolchain-xtensa"):
digest.update(str(platform.get_package_version(package)).encode())
for package in sorted(platform.packages):
try:
version = platform.get_package_version(package)
except Exception: # noqa: BLE001 -- absent optional package
version = None
digest.update(f"{package}={version}".encode())
digest.update(b"\0")
closure = _include_closure(src_dir, [*include_headers, _CORE_HEADER])
for rel in sorted(closure):
@@ -142,4 +159,4 @@ def _esp8266_setup_pch() -> None:
print("ESPHome: Compiling with precompiled header")
_esp8266_setup_pch()
_setup_pch()
+9
View File
@@ -289,6 +289,15 @@ def copy_ccache_script() -> None:
)
def copy_pch_script() -> None:
"""Copy the shared precompiled-header SCons post-script into the build
dir; platform components pair it with ``post:pch.py`` in extra_scripts."""
copy_file_if_changed(
Path(__file__).parent / "pch.py.script",
CORE.relative_build_path("pch.py"),
)
def run_platformio_cli(*args, **kwargs) -> str | int:
# Re-provision the PlatformIO cache if the interpreter's major.minor changed
# since it was last built; a stale platform otherwise rejects the new Python