This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nuttx-ntfc.git
commit a5f250ebaedde27c289500c61951b53a3eebf037 Author: raiden00pl <[email protected]> AuthorDate: Tue Aug 4 20:51:08 2026 +0200 builder.py: reconfigure after applying Kconfig overrides CMake registers application targets at configure time from .config, but kv overrides are applied after configuring, so an override enabling a new application changed .config without ever creating its build target: code-level options took effect through the .config -> config.h rule while the application never appeared in the image. Overrides can also unlock suboptions (e.g. *_PROGNAME) whose missing defaults make cmake drop the application silently. Run olddefconfig and configure again after applying overrides. Signed-off-by: raiden00pl <[email protected]> Assisted-by: Claude Code --- src/ntfc/builder.py | 22 +++++++++++++++------- tests/test_builder.py | 52 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/ntfc/builder.py b/src/ntfc/builder.py index f99820c..22d10b1 100644 --- a/src/ntfc/builder.py +++ b/src/ntfc/builder.py @@ -24,6 +24,7 @@ import os import re import shutil import subprocess +from functools import partial from pathlib import Path from typing import Any, Dict, List, Optional @@ -351,7 +352,6 @@ class NuttXBuilder: "--build", str(build_path), ] - run_env = os.environ.copy() if env: run_env.update(env) # pragma: no cover @@ -431,8 +431,8 @@ class NuttXBuilder: if not already_build or self._rebuild: # pragma: no cover self._log_kconfig_overrides(kv_overrides) - # configure build - self._run_cmake( + configure = partial( + self._run_cmake, source=nuttx_dir, build=build_path, generator="Ninja", @@ -440,20 +440,28 @@ class NuttXBuilder: env=build_env, ) + # configure build + configure() + # apply Kconfig overrides to generated .config before build self._apply_kconfig_overrides( nuttx_conf_path, kv_overrides, cfg_cwd ) - # Regenerate include/nuttx/config.h after changing .config. - # Otherwise CMake can relink an image built with stale Kconfig - # values while the saved .config claims the override applied. - if kv_overrides: + # fill in defaults of suboptions the overrides + # unlocked (e.g. *_PROGNAME): applications are + # silently dropped at configure when these are + # missing from .config self._run_build_target( build_path, "olddefconfig", env=build_env ) + # application targets are registered at configure + # time from .config: configure again so overrides + # that enable new applications take effect + configure() + # build self._run_build(build_path, env=build_env) diff --git a/tests/test_builder.py b/tests/test_builder.py index 1dcb0fe..cd5f7a0 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -143,6 +143,35 @@ def test_builder_flat_mode_no_kernel_keys(tmp_path) -> None: ) +def test_builder_reconfigures_after_kv_overrides(monkeypatch) -> None: + config = copy.deepcopy(conf_dir) + config["product"]["cores"]["core0"]["defconfig"] = "dummy/path" + config["product"]["cores"]["core0"]["kv"] = {"CONFIG_SYSTEM_X": "y"} + + calls = [] + + def run_command_capture(cmd, env): + calls.append(cmd) + + b = NuttXBuilder(config) + b._run_command = run_command_capture + b._make_dir = builder_make_dir_dummy + monkeypatch.setattr( + b, "_apply_kconfig_overrides", lambda *args, **kwargs: None + ) + + b.build_all() + + # application targets are registered at configure time: overrides + # require an olddefconfig (defaults of unlocked suboptions) and a + # second configure before the build + assert [cmd[0] for cmd in calls] == ["cmake"] * 4 + assert calls[1][-1] == "olddefconfig" + assert calls[0][:2] == calls[2][:2] + assert calls[3][:2] == ["cmake", "--build"] + assert "olddefconfig" not in calls[3] + + def test_builder_expand_flash_cmd() -> None: b = NuttXBuilder(copy.deepcopy(conf_dir)) core_cfg = { @@ -283,7 +312,8 @@ def test_builder_regenerates_config_after_kconfig_overrides() -> None: "--target", "olddefconfig", ] - assert calls[2] == ["cmake", "--build", "bbb/product-xxx-dummy"] + assert calls[0][:2] == calls[2][:2] + assert calls[3] == ["cmake", "--build", "bbb/product-xxx-dummy"] def test_builder_run_build_target_passes_env() -> None: @@ -655,11 +685,14 @@ def test_builder_applies_kv_before_build() -> None: def run_command_capture(cmd, env): calls.append(cmd) if "--build" not in cmd: + # cmake generates .config only when it does not exist yet expected_build_path.mkdir(parents=True, exist_ok=True) - expected_conf_path.write_text( - "# CONFIG_TEST_BOOL is not set\n" "CONFIG_TEST_STR=old\n", - encoding="utf-8", - ) + if not expected_conf_path.exists(): + expected_conf_path.write_text( + "# CONFIG_TEST_BOOL is not set\n" + "CONFIG_TEST_STR=old\n", + encoding="utf-8", + ) else: cfg_text = expected_conf_path.read_text(encoding="utf-8") assert "CONFIG_TEST_BOOL=y\n" in cfg_text @@ -679,11 +712,12 @@ def test_builder_applies_kv_before_build() -> None: with patch("ntfc.builder.logger.info", side_effect=logs.append): b.build_all() - assert len(calls) == 3 + # configure, olddefconfig and reconfigure after overrides, build + assert len(calls) == 4 assert calls[0][0] == "cmake" - assert calls[1][:2] == ["cmake", "--build"] - assert calls[1][-2:] == ["--target", "olddefconfig"] - assert calls[2][:2] == ["cmake", "--build"] + assert calls[1][-1] == "olddefconfig" + assert calls[2][0] == "cmake" + assert calls[3][:2] == ["cmake", "--build"] assert any( "Applying Kconfig overrides before build:" == msg for msg in logs )
