mirror of
https://github.com/esphome/esphome.git
synced 2026-08-29 09:13:28 +00:00
Honor lib_archive, guard unknown boards by name, quote archive names, fix the asm flag filter
This commit is contained in:
@@ -495,8 +495,11 @@ def write_project(paths: InstalledPaths) -> bool:
|
||||
flag_defines = _flag_defines()
|
||||
config = _resolve_build_config(flag_defines)
|
||||
esp8266_data = CORE.data[KEY_ESP8266]
|
||||
# Board support was validated at config time (_validate_native_toolchain).
|
||||
board = esp8266_data[KEY_BOARD]
|
||||
# Config-time validation rejects unsupported boards before this runs;
|
||||
# guard anyway so a bypassing caller fails by name, not KeyError
|
||||
if board not in BOARDS or board not in ESP8266_BOARD_BUILD:
|
||||
raise EsphomeError(f"Board '{board}' is not supported by the native toolchain")
|
||||
board_build = ESP8266_BOARD_BUILD[board]
|
||||
flash_ld_name = _flash_ld_name(board)
|
||||
|
||||
@@ -557,12 +560,13 @@ def write_project(paths: InstalledPaths) -> bool:
|
||||
+ get_project_cxx_compile_flags()
|
||||
)
|
||||
# PlatformIO's ASPPCOM carries defines and includes but not CCFLAGS,
|
||||
# so only -D/-I user flags reach assembly there; match it.
|
||||
# so only -D/-I user flags reach assembly there; match it. The tokens
|
||||
# are already shell-quoted, so test past a leading quote too.
|
||||
asflags = (
|
||||
_ASFLAGS
|
||||
+ defines
|
||||
+ includes
|
||||
+ [f for f in project_compile_flags if f.startswith(("-D", "-I"))]
|
||||
+ [f for f in project_compile_flags if f.lstrip('"').startswith(("-D", "-I"))]
|
||||
)
|
||||
|
||||
# build_unflags applies to the framework flag sets too (compile and link),
|
||||
@@ -654,6 +658,7 @@ def write_project(paths: InstalledPaths) -> bool:
|
||||
core_exclude |= _CORE_EXCLUDE_WAVEFORM
|
||||
|
||||
archives = []
|
||||
direct_objs: list[str] = []
|
||||
# variant_dir existence was already enforced with the include dirs
|
||||
variant_sources = _collect_sources(variant_dir)
|
||||
if variant_sources:
|
||||
@@ -690,6 +695,12 @@ def write_project(paths: InstalledPaths) -> bool:
|
||||
f"lib/{lib.name}",
|
||||
flags=" ".join(_shell_token(f) for f in lib.flags),
|
||||
)
|
||||
if not lib.lib_archive:
|
||||
# libArchive: false / dot_a_linkage=false: hand the objects to
|
||||
# the linker directly so unreferenced-but-required symbols
|
||||
# (exception handlers, weak overrides) survive
|
||||
direct_objs.extend(objs)
|
||||
continue
|
||||
archive = f"lib{lib.name}.a"
|
||||
lines.append(f"build {_e(archive)}: ar {' '.join(objs)}")
|
||||
archives.append(archive)
|
||||
@@ -706,10 +717,10 @@ def write_project(paths: InstalledPaths) -> bool:
|
||||
if CORE.testing_mode:
|
||||
ld_deps.append(f"ld/{flash_ld}")
|
||||
lines.append(
|
||||
f"build firmware.elf: link {' '.join(src_objs)} | "
|
||||
f"build firmware.elf: link {' '.join(src_objs + direct_objs)} | "
|
||||
f"{' '.join(_e(a) for a in archives)} {' '.join(_e(d) for d in ld_deps)}"
|
||||
)
|
||||
lines.append(f" archives = {' '.join(archives)}")
|
||||
lines.append(f" archives = {' '.join(_shell_token(a) for a in archives)}")
|
||||
lines.append("build firmware.bin: elf2bin firmware.elf")
|
||||
lines.append("build firmware.factory.bin: copy firmware.bin")
|
||||
lines.append("build firmware.ota.bin: copy firmware.bin")
|
||||
|
||||
@@ -772,3 +772,47 @@ def test_generate_ld_scripts_missing_compiler_is_clean(tmp_path: Path) -> None:
|
||||
_set_flags()
|
||||
with pytest.raises(EsphomeError, match="Could not run"):
|
||||
_run_generate_ld_scripts(paths)
|
||||
|
||||
|
||||
def test_write_project_asm_keeps_quoted_defines(tmp_path: Path) -> None:
|
||||
"""A spaced -D/-I user flag arrives shell-quoted; assembly must still
|
||||
receive it."""
|
||||
paths = _make_framework(tmp_path)
|
||||
_set_flags('-DGREETING="hello world"', "-Wno-volatile")
|
||||
content = _write_ninja(paths)
|
||||
asflags = next(line for line in content.splitlines() if line.startswith("asflags"))
|
||||
assert '"-DGREETING=hello world"' in asflags
|
||||
assert "-Wno-volatile" not in asflags
|
||||
|
||||
|
||||
def test_write_project_unarchived_library_links_objects(tmp_path: Path) -> None:
|
||||
"""A libArchive:false library's objects reach the link directly."""
|
||||
from esphome.arduino.library import ArduinoLibrary
|
||||
|
||||
paths = _make_framework(tmp_path)
|
||||
lib_src = tmp_path / "gdb" / "src"
|
||||
lib_src.mkdir(parents=True)
|
||||
(lib_src / "GDBStub.cpp").write_text("")
|
||||
_set_flags()
|
||||
lib = ArduinoLibrary(
|
||||
name="GDBStub",
|
||||
sources=[lib_src / "GDBStub.cpp"],
|
||||
include_dirs=[lib_src],
|
||||
lib_archive=False,
|
||||
)
|
||||
content = _write_ninja(paths, libraries=[lib])
|
||||
assert "libGDBStub.a" not in content
|
||||
link_line = next(
|
||||
line for line in content.splitlines() if line.startswith("build firmware.elf")
|
||||
)
|
||||
assert "GDBStub.cpp.o" in link_line
|
||||
|
||||
|
||||
def test_write_project_unknown_board_fails_by_name(tmp_path: Path) -> None:
|
||||
"""A caller bypassing config validation gets the board named, not a
|
||||
KeyError."""
|
||||
paths = _make_framework(tmp_path)
|
||||
_set_flags()
|
||||
CORE.data[KEY_ESP8266][KEY_BOARD] = "not_a_board"
|
||||
with pytest.raises(EsphomeError, match="'not_a_board' is not supported"):
|
||||
_write_ninja(paths)
|
||||
|
||||
Reference in New Issue
Block a user