|
SafeAPI RBC 2oo2 Test Environment
End-to-end Robot Framework test suite + Docker Compose stack for the safeAPIRBC2oo2 system
|
How to go from a clean checkout of the SAPI workspace to a verified, installable package for the safeAPIRBC2oo2 RBC application (roles A/B/ Gateway). Covers the plain host path and the Docker path. For test-suite usage (Robot Framework, the 11-container stack), see doc/design/DESIGN.md and this project's own etc/scripts/{start_docker,start_containers}.sh instead - this guide stops at "I have a package/image," not "I ran the end-to-end test suite."
safeAPIRBC2oo2GP is the one that actually links everything (Framework, Backend, SA's sa::site::gp, and GA's shared library) into safeapi_example/safeapi_gateway_c - building GP's own CMakeLists.txt transitively builds every project above it via add_subdirectory() defaults, exactly like a plain local build. safeAPIRBC2oo2SA is where the final, installable output gets assembled: it doesn't relink anything, it packages GP's already-built binaries (plus GA's .so) into a self-extracting installer, and - for Docker - actually runs that installer inside the image build as a live proof the install works. See each project's own CLAUDE.md for the full design story (the GP<->GA function-pointer interface, why SA reaches into GP's/GA's headers via a sibling path instead of a Conan requires, etc.) - this guide is mechanics, not design.
Starting from nothing (no sibling checkouts on disk yet)? Run ../bootstrapWorkspace.sh from the SAPI workspace root first - it gh repo clones every subproject that's missing (this root isn't itself a git repo; each subproject is its own independent GitHub repo, see root CLAUDE.md), then builds the native C/C++ chain + Python sim wheels for your host platform by delegating to setupLocalTestEnv.sh build below. Everything past this point assumes the checkouts already exist.
One-time, per toolchain you intend to use (skip whichever you don't need - build_toolchains.sh skips gracefully, with a message, for anything not set up):
QNXMacOSToolchain is scaffold-only (needs a licensed SDP you provide yourself) - not part of this guide.
This is what you want while iterating on source - add_subdirectory() resolves Framework/Backend/SA/GA against sibling checkouts directly, no toolchain files, no installers. Produces dist/<platform>/{bin/{safeapi_example,safeapi_gateway_c},lib/libsafeapi_rbc2oo2_ga.{dylib,so}}.
(build.sh wraps build_toolchains.sh - build_toolchains.sh -t <targets> directly works too, same thing.) Targets: macos, linux-{aarch64,arm,x86_64,i686}-{glibc,musl}, freertos. FreeRTOS only builds the framework (no POSIX backend for bare-metal, out of scope for the app) - every other target builds Framework and GP/Backend/GA/SA together. Output lands the same place as the quick-loop path, just once per target under each project's own dist/<platform>/.
For genuinely different-compiler A/B channels (gcc vs clang) on the SAME platform:
Produces safeAPIRBC2oo2GP/dist/<platform>/{A/bin/safeapi_A2oo2,B/bin/safeapi_B2oo2,Gateway/bin/safeapi_gateway_c}.
Shortcut: build.sh package (config-driven) / build.sh package -a (everything that's built) from etc/scripts/ wraps Step 2 too - it just delegates to safeAPIRBC2oo2SA/build_installers.sh below, so you don't have to cd there yourself. build.sh release chains Step 1 (all) and Step 2 (package -a) into one command - source checkout straight to every installer build_toolchains.sh can produce.
packaging.conf decides, per role (A, B, Gateway), which already-built platform+channel combination goes into the package - this is the thing to edit, not the packaging script itself:
A and B may target genuinely different platforms too (hardware/OS diversity, not just compiler diversity) - just point ROLE_A_TARGET/ ROLE_B_TARGET at different ids. Then:
Errors out (doesn't silently skip) naming exactly which role/target/ channel binary is missing and which script to run first if Step 1 wasn't done for something the config references. Produces one installer per DISTINCT target referenced by the config, under dist/install/:
-a is the alternative to hand-editing packaging.conf: it sweeps every known target and packages a plain, same-platform installer for whichever ones you've actually built in Step 1, silently skipping (a one-line message, not an error) anything you haven't - useful right after a full build.sh all when you just want "one installer per platform I built," rather than the config's deliberate, strict, per-role selection.
Don't trust a package you haven't run. This is the same command safeAPIRBC2oo2SA/Dockerfile runs automatically inside every image build (see below) - do it by hand too when packaging outside Docker:
The installer's own postcheck already runs every packaged binary with no args and checks for a usage: line (proves the dynamic linker resolved against the target host's libc and against the bundled libsafeapi_rbc2oo2_ga) - a clean installer run with no error: lines is itself a real functional check, not just "the files exist."
Does everything above in one shot for whichever glibc arch the build is actually running as (native, or buildx/QEMU target): builds GP (which pulls in Framework/Backend/GA), generates a Docker-specific packaging.conf, packages, and runs the installer inside the build - a broken install fails docker build itself, not just a later docker run. Or via Compose, which does this for all six RBC containers plus the five sim images at once:
Shortcut: etc/scripts/setupDockerTestEnv.sh wraps this whole page (Step 1's build.sh release + this native-platform image build) into one command - see that script's own header. Or, if you only want the image build step on its own without Step 1: builds all 4 native-platform images (rbc2oo2/train/il/ctc) via docker compose build under the hood, one representative service per image (the six RBC role services all share the same safeapi-rbc2oo2 image, so building all of them would just be redundant, layer-cached rebuilds):
For cross-architecture images (buildx + QEMU, not just this host's own platform) see etc/scripts/build_multiarch.sh instead - a separate, slower, opt-in script, not part of build.sh.
Every service is tagged with one of five group profiles: west (c-west/a-west/b-west), east (c-east/a-east/b-east), trainsims (train-west/train-east), ilsims (il-west/il-east), ctcsims (ctc). --profile is a top-level docker compose flag - it goes before the subcommand, not after:
etc/scripts/start_containers.sh/stop_containers.sh take a --profile too (./start_containers.sh --profile west) and place it correctly for you. With no --profile at all, both scripts default to all five groups (the full 11-container topology, unchanged from before profiles existed)
| Goal | Command |
|---|---|
| From scratch: clone every repo + build | ../bootstrapWorkspace.sh (from the SAPI workspace root) |
| Iterate on source, one platform | cmake --build build in safeAPIRBC2oo2GP |
| List known platforms + readiness | safeAPIRBC2oo2TestEnv/etc/scripts/build.sh platforms |
| Build every platform | build.sh all |
| Build specific platform(s) | build.sh platform <t1,t2,...> |
| Compiler-diverse A/B (same platform) | build_channels.sh |
| Package per packaging.conf | build_installers.sh (or build.sh package) |
| Package everything that's built | build_installers.sh -a (or build.sh package -a) |
| Source to installers, one shot | build.sh release |
| Verify a package | run the generated .sh with --prefix=, then launch a binary |
| Reset build state | build.sh clean / build.sh distclean |
| One-shot build+package+verify | docker build -f safeAPIRBC2oo2SA/Dockerfile ... |
| Source to Docker test env, one shot | setupDockerTestEnv.sh (build.sh release + Docker images + product structure) |
| Build native-platform Docker image(s) only | docker compose build <service> (see setupDockerTestEnv.sh's own service map) |
| Cross-architecture Docker image(s) | build_multiarch.sh |
| Full 11-container stack | docker compose up --build from this project |
| Just one group (west/east/trainsims/ilsims/ctcsims) | docker compose --profile <group> up --build |
| Run Robot suites against Docker | runDockerTests.sh (--full adds fault_injection/) |
| Run Robot rbc_scenario against a local (non-Docker) env | runLocalTests.sh (starts/stops the env itself) |