How to build a mando-cli release binary for Linux x86_64 / WSL locally from an Apple Silicon (ARM64) Mac. This is the manual, one-off path — for the automated CI pipeline see mando-cli-github-build-mirror.
For Agents
- Binary:
mando— project:mando-cliv0.4.0 — repo:/Volumes/bandi/coding/poc/mando-cli- Target:
x86_64-unknown-linux-musl(fully static, CI artifact namemando-linux-x86_64).- Two non-obvious gotchas below must both be handled or the build fails. Skip to Working Command for the verified one-liner.
- Use this note when a tester needs an ad-hoc Linux/WSL binary and CI is not an option. Otherwise prefer CI / install scripts.
When to Use This vs CI
| Path | Use when |
|---|---|
| CI build (mando-cli-github-build-mirror) | Normal releases — GitHub Actions Build Linux x86_64 job on native x86_64 Linux runners. Ships mando-linux-x86_64. |
| This note | Ad-hoc local build, e.g. a tester needs a binary now and a release/tag is not warranted. |
CI runners are native x86_64 Linux, which is exactly why CI never hits the gotcha below. Reproducing it locally on Apple Silicon requires the --platform linux/amd64 workaround.
Target Choice — x86_64-unknown-linux-musl
Use the musl target, not glibc:
- Produces a fully static (
static-pie) binary — nolibcversion dependency. - Runs on any WSL distro (Ubuntu, Alpine, Debian, …) regardless of its glibc version.
- Matches the CI artifact
mando-linux-x86_64.
Gotcha 1 — Docker pulls the ARM64 image on Apple Silicon
The natural first attempt is to build inside the CI base image rust:1.88-bookworm via Docker. On Apple Silicon, Docker pulls the arm64 image variant by default.
This breaks musl cross-compilation because of a transitive C dependency:
mando-cli→reqwest(rustls TLS) →ring 0.17.ringis not pure Rust — it contains C crypto sources (curve25519.c, etc.) and itsbuild.rsuses thecccrate.- Inside an arm64 container,
ccinvokesmusl-gccwith-m64to produce x86_64 objects, but the arm64musl-gccrejects that flag:
cc1: error: unrecognized command-line option '-m64'
The error blames the C compiler, not Docker
The failure surfaces deep in
ring’s build script as acc1error. It looks like a toolchain bug. The real cause is the container architecture mismatch — an arm64musl-gcccannot emit x86_64 code via-m64.
Fix — force an x86_64 container
Pass --platform linux/amd64 to docker run:
- The container is then genuinely x86_64 (OrbStack runs it via Rosetta emulation).
musl-gccinside is x86_64-native, so the musl build is same-arch — no-m64cross-compile.- This mirrors the CI environment (native x86_64), which is why CI never hits this.
Gotcha 2 — Path dependencies leak in during resolution
mando-cli’s Cargo.toml has an optional query feature with path dependencies pointing into a sibling git worktree:
../mando/.worktrees/BE-1595/mandarrow-client
../mando/.worktrees/BE-1595/mando-core
Cargo reads path-dep manifests even for disabled features
queryis off by default and its code is not compiled, but Cargo still reads thoseCargo.tomlmanifests during dependency resolution. If the container cannot see those paths, resolution fails before any compilation starts.
Fix — mount the poc/ parent directory
Mount the parent poc/ directory, not just mando-cli/:
-v /Volumes/bandi/coding/poc:/work
so the container can resolve ../mando/.worktrees/.... Build with the query feature OFF (the default — do not pass --features query).
Working Command
Verified build command (run from the host; ~2m27s with crates cached in the mando-cli-cargo Docker volume):
docker run --rm --platform linux/amd64 \
-v /Volumes/bandi/coding/poc:/work \
-v mando-cli-cargo:/cargo \
-w /work/mando-cli \
-e CARGO_HOME=/cargo -e CARGO_TARGET_DIR=/build-target \
rust:1.88-bookworm \
bash -euxc 'apt-get update -qq && apt-get install -y -qq musl-tools pkg-config libssl-dev && rustup target add x86_64-unknown-linux-musl && cargo build --release --target x86_64-unknown-linux-musl'| Element | Why |
|---|---|
--platform linux/amd64 | Gotcha 1 — forces a native-x86_64 container so musl-gcc is same-arch. |
-v /Volumes/bandi/coding/poc:/work | Gotcha 2 — exposes the ../mando/.worktrees/... path deps for resolution. |
-v mando-cli-cargo:/cargo + CARGO_HOME=/cargo | Persistent crate cache across runs (registry + git checkouts). |
CARGO_TARGET_DIR=/build-target | Keeps build artifacts off the bind mount (faster, avoids polluting the host target/). |
musl-tools | Provides musl-gcc, required by the musl target + ring’s cc build. |
pkg-config libssl-dev | Build-time deps satisfied for the toolchain image. |
Extract the binary
The binary lands inside the container at:
/build-target/x86_64-unknown-linux-musl/release/mando
Copy it out to dist/mando-linux-x86_64. One way — append a copy step to the in-container script writing into /work (the bind mount), e.g. cp /build-target/x86_64-unknown-linux-musl/release/mando /work/mando-cli/dist/mando-linux-x86_64.
Verification Performed
The produced binary was verified before handing to the tester:
| Check | Result |
|---|---|
file | ELF 64-bit LSB pie executable, x86-64, static-pie linked |
ldd (in ubuntu:24.04) | statically linked |
mando --version (in ubuntu:24.04) | mando cli 0.4.0 — exit 0 |
mando --help (in ubuntu:24.04) | full CLI output — exit 0 |
Run in alpine (musl base) | OK |
| Size | ~13 MB, unstripped |
| sha256 | bf5a99b98257a83fe6065ae37bd7227be4cdc9eb484401c30d98456877f3b76c |
ubuntu:24.04 was used as the verification environment because it is representative of what WSL runs.
Runtime Requirement on WSL
WSL needs Docker Compose v2
The
mandobinary shells out todocker composeat runtime. The WSL environment must have Docker installed withdocker composev2.20+ available — the static binary itself does not bundle it. See mando-cli-docker-lifecycle for the runtime model.
Alternative — cargo-zigbuild (not used here)
cargo-zigbuild uses Zig as the cross C-compiler and linker. It also produces a working x86_64-unknown-linux-musl binary and runs natively on the ARM host with no emulation (faster than a Rosetta-emulated container). Not used for this build because it requires installing zig + cargo-zigbuild on the host; the Docker path needs no extra host tooling and mirrors CI more closely.
Related
- mando-cli-github-build-mirror — automated CI cross-platform build pipeline (the standard release path).
- mando-cli-docker-lifecycle — runtime Docker/Compose model the binary depends on.
- mando-cli — CLI overview.
- Alpiq BESS