Per-Platform Contributor Lanes
These are the in-tree just recipes contributors use to build fixture
sets, boot QEMU lanes, and run per-platform test sweeps from a nano-ros
checkout. Users never need them — the user path (setup, build, run with
the vendor’s own tools) is on each platform’s own page, which links back
here per platform. Every lane assumes source ./activate.sh (or
direnv allow) in the checkout first.
FreeRTOS
Lanes for FreeRTOS (QEMU MPS2-AN385).
The prebuilt test fixtures bake per-language allocator ports instead
of 7447 (the copy-out examples’ port) so suites run in parallel;
just freertos talker boots the fixture, so pair it with
just freertos zenohd (listens on 7800, the Rust pub/sub fixture port).
just freertos build-fixtures builds every in-tree zenoh + DDS example
across Rust / C / C++ in one pass.
just freertos zenohd & starts the router on the fixture port (7800)
and just freertos talker boots the prebuilt talker fixture in QEMU
instead of the copy-out example. For batch testing without manual QEMU
launches, just freertos test runs every E2E (pub/sub, service,
action) against a temporary in-test zenohd.
just freertos build / just freertos test build and exercise the
in-tree fixtures.
ESP32
Lanes for ESP32 (esp-hal, bare-metal Rust).
Build:
# QEMU ESP32 (qemu-system-riscv32). `just esp32 build-qemu` (which
# `just esp32 talker` depends on) builds the QEMU-board variant; the
# example's build.rs invokes `nros generate-rust` automatically, so
# the `generated/` dir populates on first build (gitignored).
just esp32 build-qemu
Run (the router must already be listening on the port the example dials — see the platform page):
# Boot the talker binary in qemu-system-riscv32 (esp32c3):
just esp32 talker
# Expected serial output (per src/lib.rs):
# Publishing: 'Hello World: 1'
# Publishing: 'Hello World: 2'
# ...
The just esp32 talker recipe re-runs build-qemu every invocation,
so a first / cold run adds ~25 s of build time on top of the ~15 s
readiness signal.
The shorter deployment spelling:
just esp32 build
just esp32 talker
NuttX
Lanes for NuttX (QEMU) and Integration: NuttX external app.
Build (arm QEMU):
just nuttx build
This cross-compiles all NuttX examples for armv7a-nuttx-eabi using
cargo +nightly build --release.
Build (RISC-V rv-virt):
just nuttx build-riscv-c # C example fixtures
just nuttx build-riscv-rust # Rust example fixtures
Test:
just nuttx test # arm QEMU integration tests
just nuttx test-all # including the networked E2E lanes
Run: for nano-ros’s own in-tree QEMU examples, just nuttx zenohd &
starts the router on the fixture port (8200) and just nuttx talker
wraps qemu-system-arm with the right wiring. talker there is the
Rust variant; the C / C++ variants boot through the make-driven path
described under “Auto-configure glue” in
Integration: NuttX external app.
Zephyr
Lanes for Zephyr (native_sim) and Zephyr Integration (west module).
E2E testing:
# Zenoh examples
just zephyr build # Build Rust zenoh examples
just zephyr build-c # Build C zenoh examples
just zephyr test # Run zenoh E2E tests
# XRCE examples
just zephyr build-xrce # Build all XRCE examples (Rust + C)
just zephyr test-xrce # Run XRCE E2E tests
# All examples
just zephyr build-all # Build everything
just zephyr ci # Doctor + test (CI shortcut)
nano-ros’s own zephyr talker has a matching recipe for the canonical
native_sim build path: just zephyr talker, paired with
just zephyr zenohd & (listens on the fixture port 7400).
To completely recreate the in-tree Zephyr workspace:
just setup zephyr --force
Arm FVP
Lanes for ARM FVP (FVP_BaseR_AEMv8R).
Doctor: nros doctor --board fvp-aemv8r-smp runs the FVP resolution
cross-check (it delegates part of its report to just doctor, so it
needs just on PATH). The just zephyr run-fvp-ws-entry /
run-fvp-board-import recipes do the equivalent inline via
scripts/zephyr/resolve-fvp-bin.sh and skip with a clear hint when the
binary can’t be found.
Build: just zephyr build-fvp-all runs the FVP build lanes.
# The workspace C++ RT-tiers Entry — the canonical ASI-consumption
# reference (nano_ros_use_board + run_tiers).
just zephyr build-fvp-ws-entry
# The minimal board-crate IMPORT surface: nano_ros_use_board() and a
# trivial printk app, so the import path can be checked on its own.
just zephyr build-fvp-board-import
Each recipe shells west build -b fvp_baser_aemv8r/fvp_aemv8r_aarch64/smp
inside the zephyr-workspace/ directory and produces zephyr.elf at:
zephyr-workspace/build-fvp-ws-entry/zephyr/zephyr.elfzephyr-workspace/build-fvp-board-import/zephyr/zephyr.elf
Run (once the build artifacts and ARM_FVP_DIR / ARMFVP_BIN_PATH are
in place):
# Boot the workspace RT-tiers Entry (prints `[ctrl] tick=` / `[telem] tick=`).
just zephyr run-fvp-ws-entry
# Boot the board-import smoke (prints `nros: smoke ok`).
just zephyr run-fvp-board-import
Under the hood the recipe:
- Verifies
west+ the Zephyr workspace +zephyr.elfexist; skips with a hint otherwise. - Resolves the FVP binary directory via
scripts/zephyr/resolve-fvp-bin.sh(priority order:ARMFVP_BIN_PATH→ARM_FVP_DIR/models/Linux64_GCC-*/→dirname $(command -v FVP_BaseR_AEMv8R)). - Exports
ARMFVP_BIN_PATH=<dir>and shellswest build -d <build-dir> -t run, which drives Zephyr’scmake/emu/armfvp.cmaketarget with the canonicalboards/arm/fvp_baser_aemv8r/board.cmake-Cflags — UART 0–3 piped to stdout, GICv3, cache state, NUM_CORES fromCONFIG_MP_MAX_NUM_CPUS. No flags are duplicated in thejustrecipe.
Exit cleanly with Ctrl-C.
ThreadX
Lanes for ThreadX (Linux sim / RISC-V64 QEMU).
just <flavour> build-fixtures produces threadx_cpp_* and
riscv64_threadx_cpp_* binaries alongside the Rust + C ones:
just threadx_linux build-fixtures # build all rust + c examples
just threadx_riscv64 build-fixtures
just threadx_riscv64 talker boots the prebuilt riscv64 talker
fixture in qemu-system-riscv64 with the virtio-net + Slirp wiring
baked in. For batch testing, just threadx_linux test runs every
pubsub / service / action against an in-test zenohd.
Cyclone DDS
Lanes for the Cyclone DDS backend
(Choosing an RMW Backend). These are
contributor-only recipes — a bare cmake / cargo consumer build
needs no just cyclonedds pre-step; the consumer build self-provisions
Cyclone from source.
just setup cyclonedds # build Cyclone DDS from third-party/dds/cyclonedds (tag 0.10.5)
just cyclonedds build-rmw # build packages/rmw/cyclonedds/nros-rmw-cyclonedds
just cyclonedds test # run the CTest harness
Serial transport (QEMU)
Lane for Serial Transport: the
integration test test_qemu_serial_pubsub_e2e in
packages/testing/nros-tests/tests/emulator.rs automates the full
QEMU serial pub/sub workflow. Run it with:
source ./activate.sh
just qemu build-fixtures # the test consumes a prebuilt
# qemu-arm-baremetal fixture
cargo nextest run -p nros-tests --test emulator test_qemu_serial_pubsub_e2e
(A bare cargo nextest counts a skipped-precondition test as a FAILURE;
the contributor lane just test-all is what rewrites those into skips.
Read the panic text before treating a red here as a regression.)