You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2026/09/01 12:34:57 UTC
(nuttx-ntfc) 03/03: builder.py: reconfigure after applying Kconfig overrides
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 <ra...@railab.me>
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 <ra...@railab.me>
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
)