SDK Tiers for Setup
Setup is split by customer workflow. scripts/bootstrap.sh is the
entrypoint for a fresh checkout with no just installed yet; once just
is available, all paths delegate to the same recipes.
scripts/bootstrap.sh # install/check just, then show setup choices
scripts/bootstrap.sh base # first-time quick start
scripts/bootstrap.sh platform zephyr # focused platform developer
scripts/bootstrap.sh all # contributor / full test-all setup
just setup # print setup choices
just setup base # base quick-start tier
just setup all # full contributor / test-all tier
just <platform> setup # focused platform setup
just doctor # diagnose base tier
just doctor tier=all # diagnose full tier
just setup with no argument is a menu and does not fetch/install.
NROS_SETUP_TIER still overrides the default no-argument just doctor
tier. Valid tiers are base and all. Legacy aliases minimal and
default map to base; extended and everything map to all.
Tiers
| Tier | Modules | Use case |
|---|---|---|
base | cli (in-tree CLI build → packages/cli/target/release/nros, Phase 218), workspace (incl. Corrosion → ~/.nros/sdk/corrosion/, ninja, make, rust pinned toolchains), zenohd | First-time users who want native nano-ros examples and standard ROS/zenoh workflows without every RTOS SDK |
| platform-specific | one module, e.g. zephyr, nuttx, esp_idf, px4 | Developers focused on one target platform |
all | workspace, verification, zenohd, qemu, freertos, nuttx, threadx_{linux,riscv64}, esp32, zephyr, xrce, rmw_zenoh, orin_spe, cyclonedds, platformio, esp_idf, px4 | Contributors preparing for just build-test-fixtures and just test-all |
cli (Phase 218 monorepo merge) is the first step of the base
tier — just setup-cli runs cargo build --release --manifest-path packages/cli/Cargo.toml --bin nros, producing the per-checkout
packages/cli/target/release/nros. Every downstream just <module> setup recipe assumes this binary is present (it is the canonical
provisioner). packages/cli/ is a sub-workspace (own Cargo.toml,
own Cargo.lock) so its host-only deps (clap, askama, syn, ureq)
stay outside the runtime no_std feature-unification view
(Phase 214.F.3). Per-checkout, not ~/.nros/bin — contributors with
multiple worktrees get tree-isolated CLIs with no global PATH skew.
A source ./activate.sh / direnv allow puts the resulting binary on
PATH.
Corrosion (the CMake ↔ Rust/Cargo bridge corrosion_import_crate()
uses) is installed by just workspace install-corrosion to
~/.nros/sdk/corrosion/ whenever the workspace module runs — i.e. on
every tier (base and all), since workspace is the first
module in both branches of justfile::_orchestrate. The pin is in
just/workspace.just::CORROSION_VERSION; the SDK-index counterpart
[tool.corrosion] in nros-sdk-index.toml pins the same tag so
nros setup --tool corrosion --prefix $HOME/.nros/sdk/corrosion
lands an equivalent install. Header/config-only at install time,
well under the 500 MB / 5 min default tier policy, idempotent
(stamp-file gated). Phase 212.D + H.4 mixed Rust+C++ workspace tests
(phase212_d_workspace_metadata::cmake_mixed_corrosion_bridge_builds)
green-path here once the workspace module runs.
The launch parser is not a provisioned tool. It is linked into
nros-launch-resolve, built from the packages/cli/third-party/play_launch
submodule by just setup-launch-resolve (and shipped beside nros in a
release). The standalone play_launch_parser store tool was retired by issue
1413: no build path ran it, and it carried a second, lagging pin.
all is intentionally explicit because it pulls many submodules and
installs large SDKs. A module never moves between tiers without bumping
this document and the orchestrator switch in justfile::_orchestrate.
Policy: when does a module join base?
A module joins base when all of:
- Expected by first-time users. It supports native examples, standard ROS/zenoh interop, or core workspace development.
- Moderate surprise. It does not fetch large platform SDKs such as PX4-Autopilot, ESP-IDF, Zephyr, or full RTOS trees.
- Idempotent on re-run. No destructive ops, no
sudo, no network-only stages that flap.
A module joins all when it is needed by full-matrix development or
just test-all, but is too heavy or platform-specific for the default
quick start.
A module stays opt-in entirely (neither tier) when it pulls
in private SDKs, requires sudo, or carries license-restricted
bits. ARM FVP, NVIDIA SDK Manager, Cadence Tensilica toolchain,
proprietary vendor BSPs all fall here. Contributors needing them
run just <module> setup explicitly out-of-band.
CycloneDDS — self-provisioned in CMake (Phase 186)
nros-rmw-cyclonedds consumes Cyclone via find_package(CycloneDDS) and never
compiled it itself. Phase 186 moved provisioning into the build system: the
backend’s nros_provide_cyclonedds() resolves Cyclone in order —
- an already-defined
CycloneDDS::ddsctarget, find_package(CycloneDDS CONFIG)— a prebuilt install onCMAKE_PREFIX_PATH/CycloneDDS_DIR(a user install),- self-provision from source —
add_subdirectory(${CYCLONEDDS_SOURCE_DIR})(defaults to the pinnedthird-party/dds/cycloneddssubmodule; a user points it at their own checkout), with the per-platform flags staged incmake/platform/nano-ros-<plat>.cmakeand sccache as the compiler launcher.
So a bare cmake/cargo build self-provisions Cyclone with no just cyclonedds pre-step — freertos / threadx-rv64 / native all build it on demand
(just <plat> build-fixtures), gated on the relevant cross toolchain. There is no
longer a build/cyclonedds-<rtos>-install artifact (the old cross-probe scripts
are deleted); the targets link a static ddsc (no runtime libddsc.so, so no
rpath and no risk of ld.so substituting a mismatched system /opt/ros Cyclone).
Availability still follows the tier that ships the cross toolchains:
alltier (shipsarm-none-eabi-gccviafreertos, RV64 GCC viathreadx_riscv64): the embedded-Cyclonetest-allcases build + pass.basetier (no cross toolchains): the embedded-Cyclone tests are filtered out oftest-all(gated oncommand -v <cross-cc>, Phase 185.2/ 186.4) so they reportskipped, notfailed. ThreadX-RV64 Cyclone fixtures stay behind the experimentalNROS_THREADX_RV64_CYCLONEDDS_FIXTURES=1.
Host build/install (the cyclonedds setup module) is still built — for the
backend standalone CI (just cyclonedds build-rmw/test/ci), the Zephyr-Cyclone
host idlc, and the not-yet-migrated threadx-linux host-Cyclone path. Example
builds no longer depend on it (Phase 186 “host build.sh” follow-up tracks full
removal).
Run test-all in the all tier for full Cyclone coverage.
Adding a new module
When introducing a new RTOS / SDK module:
- Land
just/<module>.justwithsetup(idempotent) anddoctor(read-only) recipes. - Add
mod <module> 'just/<module>.just'tojustfile. - Decide whether it belongs in
base,all, or platform-only setup. - Add
run <module>to the matching tier branch of_orchestrateinjustfile. - Update the table in §Tiers in this doc.
- Update
AGENTS.md’s “Build, Test, and Development Commands” if the change is user-facing.
If the module is opt-in entirely, skip steps 3–5 and add a note to its own README explaining why.
Cold-start verification
For full-matrix cold start, run:
rm -rf build target*
scripts/bootstrap.sh all
source ./setup.bash
just build-test-fixtures
just test-all
For quick-start cold start, use scripts/bootstrap.sh without all.
Relation to Cargo features
Tiers describe what gets installed (host SDKs, toolchains,
clones). Cargo features describe what gets compiled inside
the nano-ros workspace. The two axes are orthogonal: a
contributor may install tier=extended (every SDK) but build
with --no-default-features (minimum nros feature set).
Relation to packaged releases (Phase 139.8)
Downstream consumers of a packaged nano-ros release (ESP-IDF
component registry, PlatformIO library, Zephyr west.yml,
NuttX-apps, PX4 external module) never invoke just setup.
They pull a pinned release through their RTOS’s package manager
and the host-SDK install is handled by the RTOS toolchain. Tier
policy applies to local development of nano-ros itself, not to
consumers. See registry-publishing.md.