mirror of
https://github.com/esphome/esphome.git
synced 2026-08-23 06:36:23 +00:00
Add the arduino toolchain enum and validate --toolchain on every platform
This commit is contained in:
@@ -1083,6 +1083,11 @@ def _resolve_toolchain(value: ConfigType) -> ConfigType:
|
||||
# CORE.toolchain instead of re-resolving it from the config dict.
|
||||
if CORE.toolchain is None:
|
||||
CORE.toolchain = value.get(CONF_TOOLCHAIN, Toolchain.ESP_IDF)
|
||||
if CORE.toolchain not in (Toolchain.PLATFORMIO, Toolchain.ESP_IDF):
|
||||
raise cv.Invalid(
|
||||
f"Unsupported toolchain '{CORE.toolchain.value}' for ESP32. "
|
||||
"Supported toolchains are 'platformio' and 'esp-idf'."
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -244,6 +244,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_ENABLE_SCANF_FLOAT): cv.boolean,
|
||||
}
|
||||
),
|
||||
# Until the native toolchain lands, PlatformIO is the only backend;
|
||||
# reject a --toolchain this platform cannot serve yet.
|
||||
cv.require_platformio_toolchain("ESP8266"),
|
||||
set_core_data,
|
||||
)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
),
|
||||
set_core_data,
|
||||
cv.require_platformio_toolchain("host"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -315,6 +315,7 @@ BASE_SCHEMA = cv.Schema(
|
||||
|
||||
BASE_SCHEMA.add_extra(_detect_variant)
|
||||
BASE_SCHEMA.add_extra(_update_core_data)
|
||||
BASE_SCHEMA.add_extra(cv.require_platformio_toolchain("LibreTiny"))
|
||||
|
||||
|
||||
def _configure_lwip(config: dict) -> None:
|
||||
|
||||
@@ -128,6 +128,11 @@ def set_core_data(config: ConfigType) -> ConfigType:
|
||||
def _resolve_toolchain(config: ConfigType) -> ConfigType:
|
||||
if CORE.toolchain is None:
|
||||
CORE.toolchain = config.get(CONF_TOOLCHAIN, Toolchain.SDK_NRF)
|
||||
if CORE.toolchain not in (Toolchain.PLATFORMIO, Toolchain.SDK_NRF):
|
||||
raise cv.Invalid(
|
||||
f"Unsupported toolchain '{CORE.toolchain.value}' for nRF52. "
|
||||
"Supported toolchains are 'platformio' and 'sdk-nrf'."
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
|
||||
@@ -313,6 +313,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.has_at_least_one_key(CONF_BOARD, CONF_VARIANT),
|
||||
_detect_variant,
|
||||
set_core_data,
|
||||
cv.require_platformio_toolchain("RP2"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2532,6 +2532,28 @@ def platformio_version_constraint(value):
|
||||
return constraints
|
||||
|
||||
|
||||
def require_platformio_toolchain(platform_name: str):
|
||||
"""Reject a CLI-selected toolchain other than PlatformIO.
|
||||
|
||||
For platforms with only the PlatformIO backend; without this a
|
||||
``--toolchain`` they cannot serve would silently build with PlatformIO.
|
||||
"""
|
||||
|
||||
def validator(config):
|
||||
from esphome.const import Toolchain
|
||||
|
||||
if CORE.toolchain is None:
|
||||
CORE.toolchain = Toolchain.PLATFORMIO
|
||||
if CORE.toolchain != Toolchain.PLATFORMIO:
|
||||
raise Invalid(
|
||||
f"Unsupported toolchain '{CORE.toolchain.value}' for "
|
||||
f"{platform_name}. The only supported toolchain is 'platformio'."
|
||||
)
|
||||
return config
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
def require_framework_version(
|
||||
*,
|
||||
max_version=False,
|
||||
|
||||
@@ -21,6 +21,8 @@ class Toolchain(StrEnum):
|
||||
PLATFORMIO = "platformio"
|
||||
ESP_IDF = "esp-idf"
|
||||
SDK_NRF = "sdk-nrf"
|
||||
# ESP8266: the Arduino core built directly (no PlatformIO)
|
||||
ARDUINO = "arduino"
|
||||
|
||||
|
||||
class Platform(StrEnum):
|
||||
|
||||
@@ -982,6 +982,10 @@ class EsphomeCore:
|
||||
def using_toolchain_sdk_nrf(self):
|
||||
return self.toolchain == Toolchain.SDK_NRF
|
||||
|
||||
@property
|
||||
def using_toolchain_arduino(self):
|
||||
return self.toolchain == Toolchain.ARDUINO
|
||||
|
||||
@property
|
||||
def using_zephyr(self):
|
||||
return self.target_framework == "zephyr"
|
||||
|
||||
@@ -557,10 +557,12 @@ def _add_library_str(lib: str) -> None:
|
||||
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _add_platformio_options(pio_options: dict[str, str | list[str]]) -> None:
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
# The native ESP-IDF build doesn't read platformio.ini; honor the
|
||||
# options with a native equivalent and warn about the rest, which
|
||||
# would otherwise be silently ignored.
|
||||
if CORE.using_toolchain_esp_idf or (
|
||||
CORE.using_toolchain_arduino and CORE.is_esp8266
|
||||
):
|
||||
# The native builds don't read platformio.ini; honor the options
|
||||
# with a native equivalent and warn about the rest, which would
|
||||
# otherwise be silently ignored.
|
||||
for key, val in pio_options.items():
|
||||
vals = [val] if isinstance(val, str) else val
|
||||
if key == CONF_BUILD_FLAGS:
|
||||
@@ -588,8 +590,9 @@ async def _add_platformio_options(pio_options: dict[str, str | list[str]]) -> No
|
||||
# config at upload time (upload_using_esptool)
|
||||
_LOGGER.warning(
|
||||
"esphome->platformio_options->%s is ignored when building with "
|
||||
"the native ESP-IDF toolchain",
|
||||
"the native '%s' toolchain",
|
||||
key,
|
||||
CORE.toolchain.value,
|
||||
)
|
||||
return
|
||||
# Add includes at the very end, so that they override everything
|
||||
|
||||
@@ -131,6 +131,20 @@ def test_esp32_rejects_unsupported_toolchains(
|
||||
CONFIG_SCHEMA({"variant": VARIANT_ESP32, "toolchain": config_toolchain})
|
||||
|
||||
|
||||
def test_esp32_rejects_unsupported_cli_toolchain(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
"""A --toolchain the platform cannot serve fails instead of silently
|
||||
building with PlatformIO (the CLI path bypasses the YAML validator)."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
from esphome.components.esp32 import CONFIG_SCHEMA
|
||||
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
with pytest.raises(cv.Invalid, match="Unsupported toolchain 'arduino'"):
|
||||
CONFIG_SCHEMA({"variant": VARIANT_ESP32})
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "error_match"),
|
||||
[
|
||||
|
||||
@@ -1389,3 +1389,36 @@ def test_esphome_build_internals_are_yaml_only() -> None:
|
||||
assert markers[field].visibility is cv.Visibility.ADVANCED, field
|
||||
# A regular device-config field stays on the main form.
|
||||
assert markers[CONF_NAME_ADD_MAC_SUFFIX].visibility is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
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."""
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
CORE.data[KEY_CORE] = {
|
||||
KEY_TARGET_PLATFORM: "esp8266",
|
||||
KEY_TARGET_FRAMEWORK: "arduino",
|
||||
}
|
||||
|
||||
await config._add_platformio_options(
|
||||
{
|
||||
"board_build.f_cpu": "160000000L",
|
||||
"upload_speed": "115200",
|
||||
}
|
||||
)
|
||||
|
||||
assert "esphome->platformio_options->board_build.f_cpu is ignored" in caplog.text
|
||||
assert "'arduino' toolchain" in caplog.text
|
||||
assert "upload_speed" not in caplog.text
|
||||
|
||||
|
||||
def test_esp8266_rejects_unsupported_cli_toolchain() -> None:
|
||||
"""Until the native backend lands, ESP8266 serves only PlatformIO."""
|
||||
from esphome.components.esp8266 import CONFIG_SCHEMA
|
||||
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
with pytest.raises(cv.Invalid, match="Unsupported toolchain 'arduino'"):
|
||||
CONFIG_SCHEMA({"board": "nodemcuv2"})
|
||||
|
||||
@@ -3165,3 +3165,19 @@ def test_file__remapped_path_is_directory_raises(setup_core: Path) -> None:
|
||||
|
||||
with pytest.raises(Invalid, match="is not a file"):
|
||||
cv.file_("/original/config/headers")
|
||||
|
||||
|
||||
def test_require_platformio_toolchain() -> None:
|
||||
"""Platforms with only the PlatformIO backend reject other toolchains."""
|
||||
from esphome.const import Toolchain
|
||||
from esphome.core import CORE
|
||||
|
||||
validator = cv.require_platformio_toolchain("RP2")
|
||||
CORE.toolchain = None
|
||||
config: dict = {}
|
||||
assert validator(config) is config
|
||||
assert CORE.toolchain == Toolchain.PLATFORMIO
|
||||
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
with pytest.raises(Invalid, match="Unsupported toolchain 'arduino' for RP2"):
|
||||
validator(config)
|
||||
|
||||
@@ -619,3 +619,14 @@ def test_needs_venv_rebuild_on_dangling_interpreter_symlink(tmp_path: Path) -> N
|
||||
assert not python.exists()
|
||||
|
||||
assert _needs_venv_rebuild(python, sentinel, "abc123")
|
||||
|
||||
|
||||
def test_resolve_toolchain_rejects_unsupported() -> None:
|
||||
"""A --toolchain nRF52 cannot serve fails instead of degrading silently."""
|
||||
from esphome.components.nrf52 import _resolve_toolchain
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import Toolchain
|
||||
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
with pytest.raises(cv.Invalid, match="Unsupported toolchain 'arduino'"):
|
||||
_resolve_toolchain({})
|
||||
|
||||
Reference in New Issue
Block a user