mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
Honor board_build.ldscript for the native flash linker script
Published configs override it to reserve a filesystem region or correct a board's assumed flash size; the routed value replaces the BOARDS default, and a path is rejected since the name resolves via -L.
This commit is contained in:
@@ -345,7 +345,33 @@ def _active_flash_ld_name(flash_ld_name: str) -> str:
|
||||
|
||||
|
||||
def _flash_ld_name(board: str) -> str:
|
||||
return ESP8266_LD_SCRIPTS[BOARDS[board][KEY_FLASH_SIZE]][1]
|
||||
"""The flash linker script: the board's, or a routed user override.
|
||||
|
||||
Published configs override board_build.ldscript to reserve a
|
||||
filesystem region or correct a board's assumed flash size; a bare
|
||||
name is required because the script resolves via the -L search path.
|
||||
"""
|
||||
override = _pio_option("board_build.ldscript", "")
|
||||
if not override:
|
||||
return ESP8266_LD_SCRIPTS[BOARDS[board][KEY_FLASH_SIZE]][1]
|
||||
if Path(override).name != override:
|
||||
raise EsphomeError(
|
||||
f"board_build.ldscript must be a bare script name, got {override!r}"
|
||||
)
|
||||
return override
|
||||
|
||||
|
||||
def _pio_option(key: str, default: str) -> str:
|
||||
"""A platformio_options value the native build honors (str-normalized).
|
||||
|
||||
Routed into ``CORE.platformio_options`` by core/config.py under the
|
||||
arduino toolchain; a repeated option accumulates as a list, where the
|
||||
last value wins like a later platformio.ini line.
|
||||
"""
|
||||
value = CORE.platformio_options.get(key)
|
||||
if isinstance(value, list):
|
||||
value = value[-1] if value else None
|
||||
return default if value is None else str(value)
|
||||
|
||||
|
||||
def _defines_flags(
|
||||
@@ -360,10 +386,11 @@ def _defines_flags(
|
||||
return [
|
||||
f"-D{d}"
|
||||
for d in (
|
||||
# Upstream reads this from the board manifest (build.f_cpu); all
|
||||
# 45 supported boards ship 80000000L, so the value is hardcoded
|
||||
# here rather than drift (same rationale as _MMU_DEFAULT)
|
||||
"F_CPU=80000000L",
|
||||
# Upstream reads this from the board manifest (build.f_cpu),
|
||||
# where all 45 supported boards ship 80000000L, overridable via
|
||||
# board_build.f_cpu; published configs pin 160000000L for
|
||||
# timing-sensitive integrations, so the override is honored
|
||||
f"F_CPU={_pio_option('board_build.f_cpu', '80000000L')}",
|
||||
"__ets__",
|
||||
"ICACHE_FLASH",
|
||||
"_GNU_SOURCE",
|
||||
|
||||
@@ -593,6 +593,17 @@ async def _add_platformio_options(pio_options: dict[str, str | list[str]]) -> No
|
||||
# platformio/library.py); filters top-level libraries and
|
||||
# discovered dependencies
|
||||
cg.add_platformio_option(key, vals)
|
||||
elif (
|
||||
key in ("board_build.f_cpu", "board_build.ldscript")
|
||||
and CORE.using_toolchain_arduino
|
||||
):
|
||||
# Real-world knobs many published ESP8266 configs rely on:
|
||||
# f_cpu 160000000L for timing-sensitive integrations, and a
|
||||
# custom ldscript to reserve a filesystem region or correct
|
||||
# a board's flash size. The esp8266 native generator reads
|
||||
# both; other native toolchains have no equivalent and fall
|
||||
# through to the warning.
|
||||
cg.add_platformio_option(key, val)
|
||||
elif key != "upload_speed":
|
||||
# upload_speed needs no handling: it is read from the raw
|
||||
# config at upload time (upload_using_esptool)
|
||||
|
||||
@@ -1291,3 +1291,36 @@ def test_generate_ld_scripts_gcc_change_invalidates_stamp(tmp_path: Path) -> Non
|
||||
with patch.object(arduino8266.subprocess, "run", return_value=result) as mock_run:
|
||||
_run_generate_ld_scripts(paths)
|
||||
mock_run.assert_called_once()
|
||||
|
||||
|
||||
def test_defines_flags_honors_f_cpu_override() -> None:
|
||||
"""board_build.f_cpu (a published-config overclock knob) reaches the
|
||||
compile line; the default stays 80 MHz."""
|
||||
_set_flags()
|
||||
config = _resolve_build_config(_flag_defines(set(), []))
|
||||
board_build = ESP8266_BOARD_BUILD["nodemcuv2"]
|
||||
defines = _defines_flags(config, "dout", "nodemcuv2", board_build["defines"])
|
||||
assert "-DF_CPU=80000000L" in defines
|
||||
CORE.platformio_options = {"board_build.f_cpu": "160000000L"}
|
||||
defines = _defines_flags(config, "dout", "nodemcuv2", board_build["defines"])
|
||||
assert "-DF_CPU=160000000L" in defines
|
||||
# A repeated option accumulates as a list; the last value wins
|
||||
CORE.platformio_options = {"board_build.f_cpu": ["80000000L", "160000000L"]}
|
||||
defines = _defines_flags(config, "dout", "nodemcuv2", board_build["defines"])
|
||||
assert "-DF_CPU=160000000L" in defines
|
||||
|
||||
|
||||
def test_flash_ld_name_honors_ldscript_override(tmp_path: Path) -> None:
|
||||
"""board_build.ldscript (filesystem reservation, corrected flash size)
|
||||
replaces the board default; a path is rejected since the name resolves
|
||||
via the -L search path."""
|
||||
assert arduino8266._flash_ld_name("nodemcuv2") == "eagle.flash.4m.ld"
|
||||
CORE.platformio_options = {"board_build.ldscript": "eagle.flash.4m2m.ld"}
|
||||
assert arduino8266._flash_ld_name("nodemcuv2") == "eagle.flash.4m2m.ld"
|
||||
paths = _make_framework(tmp_path)
|
||||
_set_flags()
|
||||
content = _write_ninja(paths)
|
||||
assert "-T eagle.flash.4m2m.ld" in content
|
||||
CORE.platformio_options = {"board_build.ldscript": "../evil.ld"}
|
||||
with pytest.raises(EsphomeError, match="bare script name"):
|
||||
arduino8266._flash_ld_name("nodemcuv2")
|
||||
|
||||
@@ -1397,8 +1397,8 @@ def test_esphome_build_internals_are_yaml_only() -> None:
|
||||
async def test_add_platformio_options_native_arduino(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""The native ESP8266 Arduino toolchain warns about ignored options the
|
||||
same way the native IDF toolchain does."""
|
||||
"""The native ESP8266 Arduino toolchain honors board_build.f_cpu (a
|
||||
real-world overclock knob) and warns about the rest like native IDF."""
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
CORE.data[KEY_CORE] = {
|
||||
KEY_TARGET_PLATFORM: "esp8266",
|
||||
@@ -1408,11 +1408,19 @@ async def test_add_platformio_options_native_arduino(
|
||||
await config._add_platformio_options(
|
||||
{
|
||||
"board_build.f_cpu": "160000000L",
|
||||
"board_build.ldscript": "eagle.flash.4m2m.ld",
|
||||
"board_build.filesystem": "littlefs",
|
||||
"upload_speed": "115200",
|
||||
}
|
||||
)
|
||||
|
||||
assert "esphome->platformio_options->board_build.f_cpu is ignored" in caplog.text
|
||||
assert CORE.platformio_options["board_build.f_cpu"] == "160000000L"
|
||||
assert CORE.platformio_options["board_build.ldscript"] == "eagle.flash.4m2m.ld"
|
||||
assert "board_build.f_cpu is ignored" not in caplog.text
|
||||
assert "board_build.ldscript is ignored" not in caplog.text
|
||||
assert (
|
||||
"esphome->platformio_options->board_build.filesystem is ignored" in caplog.text
|
||||
)
|
||||
assert "'arduino' toolchain" in caplog.text
|
||||
assert "upload_speed" not in caplog.text
|
||||
|
||||
|
||||
Reference in New Issue
Block a user