mirror of
https://github.com/esphome/esphome.git
synced 2026-08-27 08:28:30 +00:00
Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
This commit is contained in:
@@ -249,6 +249,15 @@ def _resolve_build_config(defines: dict[str, str]) -> _BuildConfig:
|
||||
if f"PIO_FRAMEWORK_ARDUINO_ESPRESSIF_{name}" in defines:
|
||||
nonosdk = define
|
||||
break
|
||||
# Same compile-line/linked-artifact split as the lwIP knobs below: a
|
||||
# raw NONOSDK* would define a second SDK macro while the link still
|
||||
# resolves against the knob's libraries
|
||||
if raw_sdk := sorted(n for n in defines if n.startswith("NONOSDK")):
|
||||
raise EsphomeError(
|
||||
f"{', '.join(raw_sdk)} are set by the "
|
||||
"PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK* knobs; drop the raw "
|
||||
"build flags"
|
||||
)
|
||||
|
||||
tcp_mss, features, ipv6, lwip_lib = _LWIP_DEFAULT
|
||||
for knob, variant in _LWIP_VARIANTS:
|
||||
@@ -311,6 +320,17 @@ def _resolve_build_config(defines: dict[str, str]) -> _BuildConfig:
|
||||
"PIO_FRAMEWORK_ARDUINO_MMU_CUSTOM requires MMU_IRAM_SIZE and "
|
||||
"MMU_ICACHE_SIZE build flags"
|
||||
)
|
||||
for size_name in ("MMU_IRAM_SIZE", "MMU_ICACHE_SIZE"):
|
||||
# These reach the linker-script preprocessor; a bare or
|
||||
# non-numeric value would corrupt the segment lengths and fail
|
||||
# far away in ld ("48K" and a valueless flag both preprocess
|
||||
# wrong; ul suffixes survive preprocessing, see build_surgery)
|
||||
value = defines[size_name].partition("=")[2]
|
||||
if not re.fullmatch(r"(?:0[xX][0-9a-fA-F]+|\d+)[uUlL]*", value):
|
||||
raise EsphomeError(
|
||||
f"{size_name} must be a numeric literal, got "
|
||||
f"{value or '(no value)'}"
|
||||
)
|
||||
# Sorted so build.ninja and the linker-script stamp stay
|
||||
# byte-stable across runs (the flag set has no deterministic
|
||||
# iteration order).
|
||||
@@ -500,13 +520,17 @@ def _stat_sig(path: Path) -> str:
|
||||
return f"unreadable:{os.urandom(8).hex()}"
|
||||
|
||||
|
||||
def _write_note(path: Path, text: str) -> None:
|
||||
"""Best-effort bookkeeping write; a failure only costs a cache miss or
|
||||
a lost re-emitted warning, never the build."""
|
||||
def _write_note(path: Path, text: str, *, warn: bool = False) -> None:
|
||||
"""Best-effort bookkeeping write; a failure never fails the build.
|
||||
|
||||
``warn`` marks notes whose loss drops a diagnostic on later cached
|
||||
builds; a lost stamp only costs a cache miss and stays at debug.
|
||||
"""
|
||||
try:
|
||||
path.write_text(text, encoding="utf-8")
|
||||
except OSError as err:
|
||||
_LOGGER.debug("Could not write %s: %s", path, err)
|
||||
log = _LOGGER.warning if warn else _LOGGER.debug
|
||||
log("Could not write %s: %s", path, err)
|
||||
|
||||
|
||||
def _write_generated(path: Path, content: str) -> None:
|
||||
@@ -606,7 +630,7 @@ def generate_ld_scripts(
|
||||
# Preprocessor warnings on the success path must reach the user
|
||||
# on this and every later cached build (see the re-emit below)
|
||||
_LOGGER.warning("Linker-script preprocessor: %s", result.stderr.strip())
|
||||
_write_note(stderr_note, result.stderr.strip())
|
||||
_write_note(stderr_note, result.stderr.strip(), warn=True)
|
||||
else:
|
||||
stderr_note.unlink(missing_ok=True)
|
||||
if "SECTIONS" not in result.stdout:
|
||||
|
||||
@@ -1143,6 +1143,44 @@ def test_generate_ld_scripts_unreadable_note_still_warns(
|
||||
assert "could not be read" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", ["0x8000", "0xC000ul", "32768", "48UL"])
|
||||
def test_mmu_custom_numeric_sizes_accepted(value: str) -> None:
|
||||
config = _resolve(
|
||||
"-DPIO_FRAMEWORK_ARDUINO_MMU_CUSTOM",
|
||||
f"-DMMU_IRAM_SIZE={value}",
|
||||
"-DMMU_ICACHE_SIZE=0x8000",
|
||||
)
|
||||
assert f"MMU_IRAM_SIZE={value}" in config.mmu_defines
|
||||
|
||||
|
||||
@pytest.mark.parametrize("flag", ["-DMMU_IRAM_SIZE=48K", "-DMMU_IRAM_SIZE"])
|
||||
def test_mmu_custom_malformed_size_raises(flag: str) -> None:
|
||||
"""A bare or non-numeric size would corrupt the preprocessed segment
|
||||
lengths and fail far away in ld; refuse by name."""
|
||||
with pytest.raises(EsphomeError, match="MMU_IRAM_SIZE must be a numeric"):
|
||||
_resolve(
|
||||
"-DPIO_FRAMEWORK_ARDUINO_MMU_CUSTOM",
|
||||
flag,
|
||||
"-DMMU_ICACHE_SIZE=0x8000",
|
||||
)
|
||||
|
||||
|
||||
def test_raw_nonosdk_define_raises() -> None:
|
||||
"""A raw NONOSDK* define would split the compile line from the linked
|
||||
SDK libraries, like the lwIP knob overrides."""
|
||||
with pytest.raises(EsphomeError, match="NONOSDK305 are set by the"):
|
||||
_resolve("-DNONOSDK305=1")
|
||||
|
||||
|
||||
def test_write_note_warn_level(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""A lost stderr note drops a diagnostic on later cached builds, so it
|
||||
warns; a lost stamp only costs a cache miss."""
|
||||
arduino8266._write_note(tmp_path / "missing" / "note", "x", warn=True)
|
||||
assert "Could not write" in caplog.text
|
||||
|
||||
|
||||
def test_write_note_failure_is_best_effort(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user