fix(build): backfill base static libs/crt objects — the memstick base has none #284

Merged
clawdie merged 1 commit from fix/stage-base-toolchain-static-libs into main 2026-07-21 03:08:36 +02:00
Owner

Root-caused live (20.jul.26, SSH session on a booted 0.13.0-dev stick): cargo build -p clawdie failed every build-script link with could not compile ... (build script) due to 1 previous error. First fix (a per-user .cargo/config.toml linker override) got past "no linker found" but exposed the real blocker underneath: /usr/lib/libc_nonshared.a missing.

Confirmed, not guessed:

  • No pkgbase packages installed on the live box (pkg info | grep -i '^FreeBSD-' — nothing) — rules out a one-line pkg install FreeBSD-clibs-dev fix.
  • /usr/freebsd-dist/ on the memstick has only MANIFEST, no .txz payloads — rules out a local extract.
  • build.sh's own "step 4" copies the FreeBSD installer memstick's mfsroot directly onto the image (pax -rw -pe . "$MOUNT_POINT"). That environment exists to run bsdinstall, not compile software — static libc/crt objects were never part of it. This is not a regression, it's a gap that's always been there.

Why this matters beyond one build attempt: AGENTS.md's FreeBSD Agent Constraints require cargo test on real FreeBSD 15 before any test-pass claim — on-image compiling is a documented required workflow. Every stock boot of this image was structurally unable to satisfy it.

Fix: after both base-copy code paths (fresh work.img and the missing-base-on-reattach branch), backfill the specific static objects Rust builds need (crt1.o, Scrt1.o, gcrt1.o, crti.o, crtn.o, libc.a, libc_nonshared.a, libutil.a, libm.a) from the build host's own /usr/lib — on the assumption the build host (OSA) is a normal, unstripped FreeBSD 15 install, which any regular install is by default. Only fills gaps that don't already exist in the image; warns rather than hard-fails if the build host itself is missing something.

Not yet build-tested on real FreeBSD — I don't have a FreeBSD host to run build.sh against. Flagging clearly: next real image build + boot should confirm the backfilled objects are sufficient for cargo build/cargo test to link clean end to end. Gates run: sh -n build.sh clean, ./scripts/check-format.sh clean, no bashisms (script is #!/bin/sh).

Opened as a separate PR from the recent naming-sweep PRs — this touches base image assembly and hasn't been validated on real hardware, so it shouldn't ride along with anything else.

🤖 Generated with Claude Code

Root-caused live (20.jul.26, SSH session on a booted 0.13.0-dev stick): `cargo build -p clawdie` failed every build-script link with `could not compile ... (build script) due to 1 previous error`. First fix (a per-user `.cargo/config.toml` linker override) got past "no linker found" but exposed the real blocker underneath: `/usr/lib/libc_nonshared.a` missing. **Confirmed, not guessed:** - No pkgbase packages installed on the live box (`pkg info | grep -i '^FreeBSD-'` — nothing) — rules out a one-line `pkg install FreeBSD-clibs-dev` fix. - `/usr/freebsd-dist/` on the memstick has only `MANIFEST`, no `.txz` payloads — rules out a local extract. - `build.sh`'s own "step 4" copies the FreeBSD installer memstick's mfsroot directly onto the image (`pax -rw -pe . "$MOUNT_POINT"`). That environment exists to *run* bsdinstall, not compile software — static libc/crt objects were never part of it. This is not a regression, it's a gap that's always been there. **Why this matters beyond one build attempt**: `AGENTS.md`'s FreeBSD Agent Constraints require `cargo test` on real FreeBSD 15 before any test-pass claim — on-image compiling is a documented required workflow. Every stock boot of this image was structurally unable to satisfy it. **Fix**: after both base-copy code paths (fresh `work.img` and the missing-base-on-reattach branch), backfill the specific static objects Rust builds need (`crt1.o`, `Scrt1.o`, `gcrt1.o`, `crti.o`, `crtn.o`, `libc.a`, `libc_nonshared.a`, `libutil.a`, `libm.a`) from the **build host's own** `/usr/lib` — on the assumption the build host (OSA) is a normal, unstripped FreeBSD 15 install, which any regular install is by default. Only fills gaps that don't already exist in the image; warns rather than hard-fails if the build host itself is missing something. **Not yet build-tested on real FreeBSD** — I don't have a FreeBSD host to run `build.sh` against. Flagging clearly: next real image build + boot should confirm the backfilled objects are sufficient for `cargo build`/`cargo test` to link clean end to end. Gates run: `sh -n build.sh` clean, `./scripts/check-format.sh` clean, no bashisms (script is `#!/bin/sh`). Opened as a **separate** PR from the recent naming-sweep PRs — this touches base image assembly and hasn't been validated on real hardware, so it shouldn't ride along with anything else. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Root-caused live (20.jul.26, SSH session on a booted 0.13.0-dev stick):
`cargo build -p clawdie` failed every build-script link with `could not
compile ... (build script) due to 1 previous error`, traced to a missing
linker (fixed with a per-user .cargo/config.toml linker override), then to
a missing /usr/lib/libc_nonshared.a underneath that.

Confirmed the base filesystem this image ships is not an extracted
base.txz at all — build.sh's own "step 4" copies the FreeBSD installer
memstick's mfsroot directly onto the image (`pax -rw -pe . "$MOUNT_POINT"`
from the mounted memstick). That environment exists to run bsdinstall, not
to compile software, so static libc/crt objects were never part of it.
Verified on the live box: no pkgbase packages installed (ruling out a
one-line `pkg install FreeBSD-clibs-dev` fix) and /usr/freebsd-dist/ on
the memstick has only MANIFEST, no .txz payloads (ruling out a local
extract). Neither of the cheap fixes applies.

This matters beyond one build attempt: AGENTS.md's FreeBSD Agent
Constraints require `cargo test` on real FreeBSD 15 before any test-pass
claim — on-image compiling is a documented required workflow, not an
edge case, and every stock boot of this image was structurally unable to
satisfy it.

Fix: after both base-copy code paths (fresh work.img and the
missing-base-on-reattach branch), backfill the specific static libc/crt
objects Rust builds need (crt1.o, Scrt1.o, gcrt1.o, crti.o, crtn.o,
libc.a, libc_nonshared.a, libutil.a, libm.a) from the build host's own
/usr/lib — on the assumption the build host (OSA) is a normal, unstripped
FreeBSD 15 install, which every regular install is by default. Only fills
gaps that don't already exist in the image; warns (does not hard-fail) if
the build host itself is missing something, so an unusual build host
doesn't newly brick otherwise-working builds.

Not yet build-tested on real FreeBSD (no FreeBSD host available to me) —
flagging for the next real image build/boot to confirm the backfilled
objects are sufficient and cargo actually links clean end to end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

Validated on real hardware (21.jul.26) — Hermes ran a full build.sh on OSA (image clawdie-quindecim-0.13.0.img, rev 16cfef7e, dev channel), chrooted into the built image, and confirmed:

  • All 9 backfilled static objects present (/usr/lib/crt1.o, libc.a, etc.)
  • cargo build on a scratch crate inside the image compiles and links (Finished dev profile), and the resulting binary runs (cargo build ok)

Two follow-ups noted, neither blocking this fix:

  1. cc is still not on $PATH in the image — cargo needed an explicit -C linker=clang override to find /usr/local/llvm19/bin/clang (an unversioned name that already exists under the llvm19 port's own private bin dir, worth using instead of hardcoding a versioned clangNN in any future fix). This is the separate, pre-existing gap from earlier in this thread — not caused by this PR, but still blocks a bare cargo build without a per-project linker config. Tracking as a follow-up.
  2. libnghttp2.so.14 was present but not ldconfig-mapped inside the chroot test (needed LD_LIBRARY_PATH=/usr/local/lib) — Hermes attributes this to ldconfig not running in a chroot (vs. a real boot's rc.d), not a real deploy issue. Worth a quick confirm on next real boot, not blocking.

Static-libs fix itself: confirmed working end-to-end. Ready to merge.

**Validated on real hardware (21.jul.26)** — Hermes ran a full `build.sh` on OSA (image `clawdie-quindecim-0.13.0.img`, rev `16cfef7e`, dev channel), chrooted into the built image, and confirmed: - All 9 backfilled static objects present (`/usr/lib/crt1.o`, `libc.a`, etc.) - `cargo build` on a scratch crate inside the image compiles and links (`Finished dev profile`), and the resulting binary runs (`cargo build ok`) **Two follow-ups noted, neither blocking this fix:** 1. `cc` is still not on `$PATH` in the image — cargo needed an explicit `-C linker=clang` override to find `/usr/local/llvm19/bin/clang` (an unversioned name that already exists under the llvm19 port's own private bin dir, worth using instead of hardcoding a versioned `clangNN` in any future fix). This is the separate, pre-existing gap from earlier in this thread — not caused by this PR, but still blocks a bare `cargo build` without a per-project linker config. Tracking as a follow-up. 2. `libnghttp2.so.14` was present but not `ldconfig`-mapped inside the chroot test (needed `LD_LIBRARY_PATH=/usr/local/lib`) — Hermes attributes this to `ldconfig` not running in a chroot (vs. a real boot's rc.d), not a real deploy issue. Worth a quick confirm on next real boot, not blocking. Static-libs fix itself: confirmed working end-to-end. Ready to merge.
clawdie deleted branch fix/stage-base-toolchain-static-libs 2026-07-21 03:08:36 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
clawdie/clawdie-iso!284
No description provided.