[esp32] Suppress -Wvolatile in the direct ESP-IDF build (#17404)

This commit is contained in:
J. Nick Koston
2026-07-05 22:02:12 -05:00
committed by GitHub
parent 39c0f9cc84
commit e095c457ff
10 changed files with 127 additions and 4 deletions
+15 -1
View File
@@ -6,7 +6,11 @@ from pathlib import Path
from esphome.components.esp32 import get_esp32_variant, idf_version
import esphome.config_validation as cv
from esphome.core import CORE
from esphome.framework_helpers import get_project_compile_flags, get_project_link_flags
from esphome.framework_helpers import (
get_project_compile_flags,
get_project_cxx_compile_flags,
get_project_link_flags,
)
from esphome.helpers import mkdir_p, write_file_if_changed
# Replaces the IDF default C++ standard (-std=gnu++2b appended to
@@ -91,6 +95,14 @@ def get_project_cmakelists(minimal: bool = False) -> str:
for flag in project_compile_opts
)
# Flags registered via cg.add_cxx_build_flag() go on CXX_COMPILE_OPTIONS
# (not COMPILE_OPTIONS) because GCC warns when a C++-only flag such as
# -Wno-volatile is passed on a C compile.
cxx_compile_options = "\n".join(
f'idf_build_set_property(CXX_COMPILE_OPTIONS "{flag}" APPEND)'
for flag in get_project_cxx_compile_flags()
)
cpp_standard_options = (
CPP_STANDARD_TEMPLATE.format(standard=CORE.cpp_standard)
if CORE.cpp_standard
@@ -155,6 +167,8 @@ include($ENV{{IDF_PATH}}/tools/cmake/project.cmake)
{cpp_standard_options}
{cxx_compile_options}
{extra_compile_options}
{managed_components_property}
+2 -3
View File
@@ -108,7 +108,6 @@ Import("env")
def write_cxx_flags_script() -> None:
path = CORE.relative_build_path(CXX_FLAGS_FILE_NAME)
contents = CXX_FLAGS_FILE_CONTENTS
if not CORE.is_host:
contents += 'env.Append(CXXFLAGS=["-Wno-volatile"])'
contents += "\n"
for flag in sorted(CORE.cxx_build_flags):
contents += f'env.Append(CXXFLAGS=["{flag}"])\n'
write_file_if_changed(path, contents)
+1
View File
@@ -25,6 +25,7 @@ from esphome.cpp_generator import ( # noqa: F401
add,
add_build_flag,
add_build_unflag,
add_cxx_build_flag,
add_define,
add_global,
add_library,
+9
View File
@@ -591,6 +591,9 @@ class EsphomeCore:
self.platformio_libraries: dict[str, Library] = {}
# A set of build flags to set in the platformio project
self.build_flags: set[str] = set()
# A set of build flags that apply to C++ compiles only (CXXFLAGS /
# CXX_COMPILE_OPTIONS), for flags GCC rejects or warns about on C
self.cxx_build_flags: set[str] = set()
# A set of build unflags to set in the platformio project
self.build_unflags: set[str] = set()
# The C++ language standard for the build (e.g. "gnu++20"), set via cg.set_cpp_standard()
@@ -650,6 +653,7 @@ class EsphomeCore:
self.global_statements = []
self.platformio_libraries = {}
self.build_flags = set()
self.cxx_build_flags = set()
self.build_unflags = set()
self.cpp_standard = None
self.defines = set()
@@ -957,6 +961,11 @@ class EsphomeCore:
_LOGGER.debug("Adding build flag: %s", build_flag)
return build_flag
def add_cxx_build_flag(self, build_flag: str) -> str:
self.cxx_build_flags.add(build_flag)
_LOGGER.debug("Adding C++ build flag: %s", build_flag)
return build_flag
def add_build_unflag(self, build_unflag: str) -> None:
if self.using_toolchain_esp_idf:
# The native ESP-IDF build generator does not consume build_unflags
+9
View File
@@ -723,6 +723,15 @@ async def to_code(config: ConfigType) -> None:
cg.add_build_flag("-Wno-unused-variable")
cg.add_build_flag("-Wno-unused-but-set-variable")
cg.add_build_flag("-Wno-sign-compare")
# C++20 deprecated ++/--, compound assignment, and chained assignment on
# volatile lvalues; GCC warns via -Wvolatile, on by default at gnu++20.
# C++23 (P2327R1) removed the deprecation for compound assignment, so the
# warning flags patterns that are valid again under newer standards.
# C++-only flag: GCC warns when it is passed on a C compile, hence
# add_cxx_build_flag. Skipped for host builds, where the compiler may be
# clang, which does not know this GCC option.
if not CORE.is_host:
cg.add_cxx_build_flag("-Wno-volatile")
if config[CONF_DEBUG_SCHEDULER]:
cg.add_define("ESPHOME_DEBUG_SCHEDULER")
+9
View File
@@ -699,6 +699,15 @@ def add_build_flag(build_flag: str):
CORE.add_build_flag(build_flag)
def add_cxx_build_flag(build_flag: str) -> None:
"""Add a global build flag that applies to C++ compiles only.
Use for flags GCC rejects or warns about when passed on C compiles
(e.g. ``-Wno-volatile``).
"""
CORE.add_cxx_build_flag(build_flag)
def add_build_unflag(build_unflag: str) -> None:
"""Add a global build unflag to the compiler flags."""
CORE.add_build_unflag(build_unflag)
+7
View File
@@ -37,6 +37,13 @@ def get_project_compile_flags() -> list[str]:
]
def get_project_cxx_compile_flags() -> list[str]:
"""Return the sorted flags that apply to C++ compiles only."""
from esphome.core import CORE # local import to avoid circular dependency
return sorted(CORE.cxx_build_flags)
def str_to_lst_of_str(a: str | list[str]) -> list[str]:
"""
Convert a string to a list of string
+23
View File
@@ -243,6 +243,7 @@ def test_get_project_cmakelists_no_cpp_standard(tmp_path: Path) -> None:
patch("esphome.build_gen.espidf.get_esp32_variant", return_value="ESP32"),
patch.object(CORE, "name", "test"),
patch.object(CORE, "cpp_standard", None),
patch.object(CORE, "cxx_build_flags", set()),
):
from esphome.build_gen.espidf import get_project_cmakelists
@@ -251,6 +252,28 @@ def test_get_project_cmakelists_no_cpp_standard(tmp_path: Path) -> None:
assert "CXX_COMPILE_OPTIONS" not in content
def test_get_project_cmakelists_cxx_build_flags(tmp_path: Path) -> None:
"""Flags registered via cg.add_cxx_build_flag() are appended to
CXX_COMPILE_OPTIONS (C++-only, GCC warns if they reach C compiles)
between include(project.cmake) and project()."""
with (
patch("esphome.build_gen.espidf.get_esp32_variant", return_value="ESP32"),
patch.object(CORE, "name", "test"),
patch.object(CORE, "cpp_standard", None),
patch.object(CORE, "cxx_build_flags", {"-Wno-volatile"}),
):
from esphome.build_gen.espidf import get_project_cmakelists
content = get_project_cmakelists(minimal=True)
flag_line = 'idf_build_set_property(CXX_COMPILE_OPTIONS "-Wno-volatile" APPEND)'
assert flag_line in content
include_pos = content.index("tools/cmake/project.cmake")
flag_pos = content.index(flag_line)
project_pos = content.index("project(test)")
assert include_pos < flag_pos < project_pos
def test_get_component_cmakelists_no_compile_features() -> None:
"""The C++ standard is pinned project-wide via CXX_COMPILE_OPTIONS in the
top-level CMakeLists; the src component must not set its own."""
@@ -200,3 +200,32 @@ def test_get_ini_content_no_cpp_standard(
content = platformio.get_ini_content()
assert "-std=" not in content
def test_write_cxx_flags_script_emits_registered_flags(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Flags registered via cg.add_cxx_build_flag() are emitted as CXXFLAGS,
sorted, so they apply to C++ compiles only."""
CORE.build_path = str(tmp_path)
monkeypatch.setattr(CORE, "cxx_build_flags", {"-Wno-volatile", "-Wno-deprecated"})
platformio.write_cxx_flags_script()
content = (tmp_path / platformio.CXX_FLAGS_FILE_NAME).read_text()
assert (
'env.Append(CXXFLAGS=["-Wno-deprecated"])\n'
'env.Append(CXXFLAGS=["-Wno-volatile"])\n'
) in content
def test_write_cxx_flags_script_no_flags(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
CORE.build_path = str(tmp_path)
monkeypatch.setattr(CORE, "cxx_build_flags", set())
platformio.write_cxx_flags_script()
content = (tmp_path / platformio.CXX_FLAGS_FILE_NAME).read_text()
assert "CXXFLAGS" not in content
@@ -26,6 +26,7 @@ from esphome.framework_helpers import (
create_venv,
download_from_mirrors,
get_project_compile_flags,
get_project_cxx_compile_flags,
get_project_link_flags,
get_python_env_executable_path,
get_system_python_path,
@@ -1048,3 +1049,25 @@ class TestGetProjectLinkFlags:
):
result = get_project_link_flags()
assert result == sorted(result)
def _make_core_cxx(flags: set[str]) -> MagicMock:
core = MagicMock()
core.cxx_build_flags = flags
return core
class TestGetProjectCxxCompileFlags:
def test_returns_sorted_flags(self) -> None:
with patch(
"esphome.core.CORE",
_make_core_cxx({"-Wno-volatile", "-Wno-deprecated"}),
):
assert get_project_cxx_compile_flags() == [
"-Wno-deprecated",
"-Wno-volatile",
]
def test_empty_flags(self) -> None:
with patch("esphome.core.CORE", _make_core_cxx(set())):
assert get_project_cxx_compile_flags() == []