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 d26aa7e46637413e77b3e32f28d8820ab5cb88d7 Author: raiden00pl <[email protected]> AuthorDate: Tue Aug 4 17:50:28 2026 +0200 device: resolve image paths before spawning with a custom exec_cwd With exec_cwd set, QEMU resolved a relative '-kernel' path against the spawn directory instead of the NTFC working directory it is expressed in, so boot timed out. Absolutize the image path in the qemu and sim start paths when a custom spawn directory is configured. Signed-off-by: raiden00pl <[email protected]> Assisted-by: Claude Code --- src/ntfc/device/host.py | 12 ++++++++++++ src/ntfc/device/qemu.py | 5 +---- src/ntfc/device/sim.py | 6 +----- tests/device/test_qemu.py | 26 ++++++++++++++++++++++++++ tests/device/test_sim.py | 30 ++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/ntfc/device/host.py b/src/ntfc/device/host.py index d632387..e188e65 100644 --- a/src/ntfc/device/host.py +++ b/src/ntfc/device/host.py @@ -61,6 +61,18 @@ class DeviceHost(DeviceCommon): """Return the spawned child PID, or ``None`` before start.""" return self._child.pid if self._child else None + def _image_path(self) -> str: + """Return the image path, absolute when spawning in another cwd. + + Relative paths are relative to the NTFC working directory, not + to the spawn directory. + """ + elf = self._conf.elf_path + if not elf: + raise IOError + + return os.path.abspath(elf) if self._cwd else str(elf) + def _dev_is_health_priv(self) -> bool: """Check if the host device is OK.""" if not self._child: diff --git a/src/ntfc/device/qemu.py b/src/ntfc/device/qemu.py index a655d26..a565003 100644 --- a/src/ntfc/device/qemu.py +++ b/src/ntfc/device/qemu.py @@ -44,12 +44,9 @@ class DeviceQemu(DeviceHost): def _start_impl(self) -> None: """Start QEMU emulator implementation.""" - elf = self._conf.elf_path + elf = self._image_path() exec_path = self._conf.exec_path exec_args = self._conf.exec_args - - if not elf: - raise IOError if not exec_path: raise KeyError("no exec_path in configuration file!") diff --git a/src/ntfc/device/sim.py b/src/ntfc/device/sim.py index c48c94a..d7c7add 100644 --- a/src/ntfc/device/sim.py +++ b/src/ntfc/device/sim.py @@ -41,11 +41,7 @@ class DeviceSim(DeviceHost): def _start_impl(self) -> None: """Start sim emulator implementation.""" - elf = self._conf.elf_path - if not elf: - raise IOError - - cmd = [elf] + cmd = [self._image_path()] uptime = self._conf.uptime # open host-based emulation diff --git a/tests/device/test_qemu.py b/tests/device/test_qemu.py index c99741e..008fd91 100644 --- a/tests/device/test_qemu.py +++ b/tests/device/test_qemu.py @@ -18,6 +18,7 @@ # ############################################################################ +import os from unittest.mock import patch import pytest @@ -89,6 +90,7 @@ def test_device_qemu_open(): config.exec_path = "" config.exec_args = "" config.elf_path = "" + config.exec_cwd = None qemu = DeviceQemu(config) @@ -175,3 +177,27 @@ def test_device_qemu_open(): config.uptime = 3 qemu.start() + + +def test_device_qemu_exec_cwd_absolute_image(tmp_path): + + from ntfc.coreconfig import CoreConfig + + config = CoreConfig( + { + "name": "t", + "device": "qemu", + "exec_path": "qemu-system-riscv64", + "exec_args": "-nographic", + "exec_cwd": str(tmp_path), + } + ) + # relative image path, resolved against the NTFC cwd at spawn time + config._config["elf_path"] = "some/image" + + qemu = DeviceQemu(config) + cmds = [] + qemu.host_open = lambda cmd, uptime: cmds.append(cmd) + qemu.start() + + assert cmds[0][2] == "-kernel " + os.path.abspath("some/image") diff --git a/tests/device/test_sim.py b/tests/device/test_sim.py index fdf8628..33fad22 100644 --- a/tests/device/test_sim.py +++ b/tests/device/test_sim.py @@ -138,3 +138,33 @@ def test_device_sim_line_buffered_write(): sent.clear() sim._write(b"abc\n") assert sent == [b"abc\n"] + + +def test_device_sim_exec_cwd_absolute_image(tmp_path): + + import os + + from ntfc.coreconfig import CoreConfig + + config = CoreConfig( + {"name": "t", "device": "sim", "exec_cwd": str(tmp_path)} + ) + # relative image path, resolved against the NTFC cwd at spawn time + config._config["elf_path"] = "some/image" + + sim = DeviceSim(config) + cmds = [] + sim.host_open = lambda cmd, uptime: cmds.append(cmd) + sim.start() + + assert cmds[0] == [os.path.abspath("some/image")] + + # without exec_cwd the image path is passed through unchanged + config = CoreConfig({"name": "t", "device": "sim"}) + config._config["elf_path"] = "some/image" + + sim = DeviceSim(config) + sim.host_open = lambda cmd, uptime: cmds.append(cmd) + sim.start() + + assert cmds[1] == ["some/image"]
