[espidf] Stop perpetual reconfigure loop on native ESP-IDF builds (#16415)

This commit is contained in:
Jonathan Swoboda
2026-05-13 23:19:30 -04:00
committed by GitHub
parent d2107e40c8
commit e593cb6efc
2 changed files with 19 additions and 18 deletions
+6 -1
View File
@@ -2509,7 +2509,12 @@ def _write_idf_component_yml():
stubs_dir = CORE.relative_build_path("component_stubs") stubs_dir = CORE.relative_build_path("component_stubs")
stubs_dir.mkdir(exist_ok=True) stubs_dir.mkdir(exist_ok=True)
for component_name in components_to_stub: # Sort so the dict insertion order (and thus the generated
# src/idf_component.yml) is deterministic across runs; otherwise
# the manifest content shuffles every build, write_file_if_changed
# always writes, and ninja keeps triggering CMake re-runs on
# otherwise-cached rebuilds.
for component_name in sorted(components_to_stub):
# Create stub directory with minimal CMakeLists.txt # Create stub directory with minimal CMakeLists.txt
stub_path = stubs_dir / _idf_component_stub_name(component_name) stub_path = stubs_dir / _idf_component_stub_name(component_name)
stub_path.mkdir(exist_ok=True) stub_path.mkdir(exist_ok=True)
+13 -17
View File
@@ -191,13 +191,19 @@ def run_reconfigure() -> int:
def has_outdated_files(): def has_outdated_files():
"""Check if the build configuration is stale. """Check if the build configuration is stale.
Returns True if required build files are missing or if configuration inputs Returns True if required build files are missing or if external
are newer than the generated CMake/Ninja build artifacts. configuration inputs (IDF install, sdkconfig, CMake's own build/config
dir) are newer than CMakeCache.txt. We deliberately don't watch the
top-level/src ``CMakeLists.txt`` here -- those are written by
``write_project`` via ``write_file_if_changed`` (so an mtime bump
means our content actually changed) and ninja already tracks them as
configure-time deps via ``build.ninja``. Including them in this check
causes a perpetual reconfigure loop: the two-pass write leaves
CMakeLists newer than CMakeCache.txt, and CMake doesn't restamp the
cache when only ``idf_build_set_property`` values change, so the
check would trip on every subsequent build.
""" """
cmakecache_txt_path = CORE.relative_build_path("build/CMakeCache.txt") cmakecache_txt_path = CORE.relative_build_path("build/CMakeCache.txt")
cmakelists_txt_build_path = CORE.relative_build_path("CMakeLists.txt")
cmakelists_txt_src_path = CORE.relative_src_path("CMakeLists.txt")
build_config_path = CORE.relative_build_path("build/config") build_config_path = CORE.relative_build_path("build/config")
sdkconfig_internal_path = CORE.relative_build_path( sdkconfig_internal_path = CORE.relative_build_path(
f"sdkconfig.{CORE.name}.esphomeinternal" f"sdkconfig.{CORE.name}.esphomeinternal"
@@ -221,8 +227,6 @@ def has_outdated_files():
os.path.getmtime(f) > cmakecache_txt_mtime os.path.getmtime(f) > cmakecache_txt_mtime
for f in [ for f in [
_get_idf_path(), _get_idf_path(),
cmakelists_txt_build_path,
cmakelists_txt_src_path,
sdkconfig_internal_path, sdkconfig_internal_path,
build_config_path, build_config_path,
] ]
@@ -302,21 +306,13 @@ def run_compile(config, verbose: bool) -> int:
return rc return rc
_LOGGER.info("Regenerating CMakeLists.txt with discovered components...") _LOGGER.info("Regenerating CMakeLists.txt with discovered components...")
write_project(minimal=False) write_project(minimal=False)
# The post-discovery rewrite leaves CMakeLists newer than
# CMakeCache.txt. CMake won't re-touch CMakeCache.txt on a
# configure that only changes idf_build_set_property values
# (those aren't cache variables), so has_outdated_files() would
# return True on every subsequent build, perpetually retriggering
# the two-pass. Touch CMakeCache.txt now so its mtime stays past
# the rewritten CMakeLists.
cmakecache = CORE.relative_build_path("build/CMakeCache.txt")
if cmakecache.is_file():
os.utime(cmakecache)
if CORE.testing_mode: if CORE.testing_mode:
# Reconfigure again so cmake is up to date with the full # Reconfigure again so cmake is up to date with the full
# component list before the build's idf.py invocation runs -- # component list before the build's idf.py invocation runs --
# idf.py build would otherwise re-run cmake and regenerate # idf.py build would otherwise re-run cmake and regenerate
# memory.ld, wiping the DRAM/IRAM patches applied below. # memory.ld, wiping the DRAM/IRAM patches applied below.
# Outside testing mode ninja's own configure-time dep on
# CMakeLists.txt handles the re-run as part of the build step.
rc = run_reconfigure() rc = run_reconfigure()
if rc != 0: if rc != 0:
_LOGGER.error("Reconfigure with discovered components failed") _LOGGER.error("Reconfigure with discovered components failed")