Every so often I'm reminded that the nicest thing about Go is the build story, and today was one of those days. I needed a binary for a little 32-bit ARM single-board computer sat in the cupboard, and the whole job was one line:
GOOS=linux GOARCH=arm GOARM=7 go build -o app .
No cross toolchain to install, no sysroot, no fighting a C compiler. Set the target with environment variables, build on my normal machine, copy the result across. It just runs.
The one gotcha is GOARM. GOARCH=arm on its own isn't enough, because "ARM" covers a range of instruction sets. The default is conservative and will produce a binary that runs almost anywhere but leaves performance on the table. If your board has hardware floating point, and most modern ones do, set GOARM=7 to get it. Pick the wrong one too high and the binary fails with an illegal instruction the moment it touches floating point; too low and it's just slower than it needs to be.
The other thing to remember: this clean cross-compile only holds while you stay pure Go. The instant cgo is in the picture you're back to needing a cross C toolchain, and the magic evaporates. For anything where I get to choose, I keep it cgo-free precisely so build day stays this boring.