Cross-compilation — Junior¶
1. What is cross-compilation?¶
Cross-compilation means producing an executable for one operating system or CPU architecture while building on a different one. For example, on your macOS laptop you can build a binary that runs on a Linux server, without ever installing Linux.
Most languages need a separate toolchain or SDK per target. Go bakes cross-compilation into the standard distribution: a single go install can produce binaries for dozens of target platforms out of the box, for pure-Go programs.
The result, app, is a Linux ELF binary you can scp to a server and run.
2. Prerequisites¶
- Go 1.21+ installed (
go version). - A
mainpackage you can build withgo build .. - Basic familiarity with environment variables in your shell.
3. Glossary¶
| Term | Meaning |
|---|---|
| Host | The machine you build on |
| Target | The OS/architecture the binary will run on |
| GOOS | Target operating system (linux, darwin, windows, ...) |
| GOARCH | Target CPU architecture (amd64, arm64, 386, ...) |
| Pure Go | A program with no import "C" (no cgo) |
| cgo | The mechanism that lets Go call C code |
| ELF / PE / Mach-O | Binary formats for Linux / Windows / macOS |
4. The two switches that matter¶
Two environment variables control the target:
You set them for one command:
Or export them for a whole shell session:
Without these, go build produces a binary for your host (runtime.GOOS / runtime.GOARCH).
5. Listing the supported targets¶
Ask the toolchain what it can build for:
You get pairs like:
aix/ppc64
android/amd64
darwin/amd64
darwin/arm64
linux/386
linux/amd64
linux/arm
linux/arm64
windows/386
windows/amd64
windows/arm64
js/wasm
wasip1/wasm
...
Each line is a valid GOOS/GOARCH combination.
6. A worked example — build for Linux from any host¶
A tiny program:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("hello from %s/%s\n", runtime.GOOS, runtime.GOARCH)
}
Build for Linux/amd64:
GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
file app-linux-amd64
# app-linux-amd64: ELF 64-bit LSB executable, x86-64, ...
The file command confirms the binary is an ELF executable for x86-64 Linux, even though you built it on macOS.
7. Building for Windows¶
Notice the .exe suffix — Windows expects it. The output is a PE/COFF binary.
You can copy app.exe to a Windows machine and run it directly.
8. Why this "just works"¶
For pure-Go programs the toolchain ships its own compiler, assembler, and linker for every supported target — no external C compiler is needed. The standard library has per-platform implementations (e.g., system calls), and the build system picks the right ones automatically based on GOOS and GOARCH.
The moment you import a C library through cgo, this stops being trivial: cgo cross-compilation needs a C cross-toolchain. As a junior you usually do not have cgo dependencies, so pure-Go cross-builds are your default world.
9. Common mistake — running the cross-built binary locally¶
That is not a bug. You built a Linux binary; your macOS kernel cannot run it. Copy it to a Linux host (or run it inside a container) and it works.
10. Summary¶
Cross-compilation lets one machine build binaries for other operating systems and architectures. In Go you do it by setting GOOS and GOARCH before go build. The list of valid targets comes from go tool dist list. For pure-Go code, nothing else is required — no SDK, no extra toolchain. The cross-built binary runs on the target, not on your host.
Further reading¶
go help build,go help environmentgo tool dist list— supported targetscmd/godocumentation: https://pkg.go.dev/cmd/go- Installing Go: https://go.dev/doc/install