Ramblings of an aging IT geek
← Ramblings of an aging IT geek
golang

building once on the laptop, running on the pi

Cross-compiling a small Go service for an ARM single-board computer turned out to be two environment variables, until cgo got involved.

A code editor with a Go file open

I have a little Go service that lives on an ARM single-board computer in the cupboard, and for a while I was building it on the cupboard, which meant a five-minute compile on a board that wheezes under load. Daft, when Go cross-compiles better than almost anything.

The whole trick is two environment variables:

GOOS=linux GOARCH=arm64 go build -o svc ./cmd/svc

That's it for pure-Go code. The toolchain ships every target, no extra installs, no Docker. Build on the laptop in two seconds, scp the binary across, done. For the older 32-bit boards it's GOARCH=arm plus GOARM=7 to pin the ARM version, otherwise you can get an instruction the chip doesn't have.

The one place it stops being free is cgo. The moment you pull in a library that links C, CGO_ENABLED=1 needs an actual ARM cross-compiler, and now you're installing gcc-aarch64-linux-gnu and setting CC. My rule is to avoid cgo entirely on anything destined for the cupboard. A pure static binary with CGO_ENABLED=0 has no libc dependency, copies anywhere, and runs on whatever ancient userland the board shipped with. The compile-on-target era is over and I don't miss it.