Cross Compile

Now that you know how to perform simple Go Build, you would want to build across all supported CPU and Operating System (OS). To do that, on any platform with Go compiler, you can do what we called "Cross Compile In Go". This guide will walk you through the Go Build's cross-compilation.

IMPORTANT NOTE

I'm assuming you're already familiar with Simple Go Build. Otherwise, practice that first.

List Architectures

The first thing to do is to know your Go compiler supports. One way to do it is to list out all the distributions. To list them out, use the following commands:

$ go tool dist list

Example:

$ go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/386
darwin/amd64
darwin/arm
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/s390x
nacl/386
nacl/amd64p32
nacl/arm
netbsd/386
netbsd/amd64
netbsd/arm
openbsd/386
openbsd/amd64
openbsd/arm
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386
windows/amd64
windows/arm
$

Then, identify your GOOS and GOARCH. The the before the slash (/) is GOOS; the one after is GOARCH.

Writing Architecture/OS Specific Source Codes

You need to refactor your source codes to be friendly with architecture/OS specific components. There are 2 ways to do it.


Build Tags

All you need is the build tags. Take a look at the following examples:

//+build linux darwin !windows
//+build 386 amd64

// mypkg is a package for describing your package here. This line and moving forward are comments.
package mypkg
...

This way, it made it clear to the compiler that this source code is for:

  • linux, darwin, NOT windows
  • only for 386 and amd64 microprocessor

NOTE: It is important to leave an empty line between the build tag and the package description, or the package tag. Otherwise, they will be treated as comments.


File Naming Convention

Depends and no strict rules. Normally, for best practices in other languages, we sticks to 1 type of architecture, 1 type of OS per source codes. Otherwise, you split the shared codes into a higher level library. The general naming conventions would be:

<name>_<os>_<arch>.go

Example:

config_linux_amd64.go

If you're building for all UNIX systems like FreeBSD, Darwin, Linux, you can also use UNIX as "OS" as well like:

config_unix_amd64.go

The goal is to let your developer know which file is responsible for what corresponding to the build tags. The most important part is the build tags inside the source codes.

Build It

The proper command would be declaring the ${GOOS} and ${GOARCH} environment variables. Optionally, if you worry about the inconsistency related to naming, you can also organize the name into ${APP}. Example:

$ GOOS=linux GOARCH=amd64 APP=devora
$ go build -o ./bin/${APP}-${GOOS}-${GOARCH} ./cmd/${APP}/main.go

They are actually 2 lines of commands. If you used the proper directory convention, the go build command (2nd line) is recyclable across different system.

That being said, you only need to update the 2-3 environment variables to build for other platform.

That's all about cross-compiling in Go Build.