Build natively on the development Orin

Two units with different jobs: one builds and runs CI, the other is the
deployment target. Building on the target architecture makes the glibc
constraint structural rather than configured.

The remaining risk is version parity between the two units, not architecture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013kj58Jugkic783b8ZrtTVZ
This commit is contained in:
2026-09-05 15:23:10 +09:00
parent 23ee20f9be
commit f49af26898
2 changed files with 32 additions and 20 deletions
+31 -20
View File
@@ -145,35 +145,46 @@ libraries.
#### Building for the Orin
Services cross-compile from the workstation:
Services build **natively on the development Orin**. The sysroot is then the
target's own, so a binary cannot reference a symbol the car unit lacks — the
guarantee is structural rather than configured.
```bash
cargo build --release --target aarch64-unknown-linux-gnu
```
Two Orin Nanos, and they have different jobs:
Each service repo's `.cargo/config.toml` points at `aarch64-linux-gnu-gcc`, from
the `gcc-aarch64-linux-gnu` package.
| Unit | Role |
|---|---|
| Development Orin | Build, CI runner, bench testing. Always powered, on the LAN |
| Car Orin | Deployment target only |
⚠ **The linker binds each symbol to the newest version present in the sysroot**,
so the cross sysroot (glibc 2.43) sets the floor, not the toolchain. Rust std
itself targets 2.17 — making the toolchain older changes nothing.
⚠ **The guarantee is version parity, not architecture.** An aarch64 binary built
on a newer userland still fails to load on an older one. A JetPack or Ubuntu
upgrade applied to one unit and not the other reintroduces the problem, silently
and only at runtime. **Upgrade both, or neither.**
Currently the highest referenced version is **2.34**, below the Orin's 2.35. Every
symbol above 2.30 comes from one event: glibc 2.34 merged `libpthread` and
`libdl` into `libc` and re-versioned the moved symbols (`__libc_start_main`, the
`pthread_*` family). Re-versioning is rare, so this ceiling is stable — exceeding
it would take a **dependency** calling a glibc function introduced after 2.35.
That failure lands at **runtime**, on the car, as a loader error; the build
succeeds. Check before deploying:
The check that catches drift between them:
```bash
objdump -T <binary> | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -1
```
At or below `GLIBC_2.35` it will run. Above it, the control is the **sysroot**:
build in a container supplying an older one — `cross` does this with the host's
own toolchain — or build on the Orin.
It detects, it does not fix — its job is to fail the build rather than let a bad
binary reach the car, and to name the symbol that caused it.
##### Cross-compiling from the workstation
Available as a fallback. Each service repo's `.cargo/config.toml` points at
`aarch64-linux-gnu-gcc`, from the `gcc-aarch64-linux-gnu` package:
```bash
cargo build --release --target aarch64-unknown-linux-gnu
```
⚠ **The linker binds each symbol to the newest version present in the sysroot**,
so the workstation's glibc 2.43 sets the floor — not the toolchain, which targets
2.17. Currently the highest referenced version is 2.34, below the Orin's 2.35,
because everything above 2.30 comes from one event: glibc 2.34 merged
`libpthread` and `libdl` into `libc` and re-versioned the moved symbols. Stable,
but not guaranteed the way a native build is.
### Writing style