We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
One of the nice things of Go is that you can cross compile for another architecture or operating system on your local system. If you want to build an linux version of your app, you don't need to compile on an actual linux box, you can just do this on your mac.
As of Go 1.5, cross compilation is supported out of the box and doesn't require any extra things to be installed. You can read all the details about this change here.
The cross compilation is configured by setting two environment variables, namely $GOOS
and $GOARCH
. These are special environment variables which influence the way the go tools work. They are discussed in great detail in the documentation.
The variable $GOOS
indicates the operating system you are building for. The $GOARCH
variable lets the compiler know for which architecture you want to build.
So, imagine we have a very basic go program which we want to compile:
package main
import "fmt"
import "runtime"
func main() {
fmt.Println("OS: %s", runtime.GOOS)
fmt.Println("Architecture: %s", runtime.GOARCH)
}
If you compile it without explicitely setting the environment variables, you will get a build for the current OS and architecture:
$ go build main.go
$ file main
main: Mach-O 64-bit executable x86_64
If we want to compile for a 64-bit Linux system, we would prepend the correct $GOOS
and $GOARCH
environment variables with the go build
command:
$ GOOS=linux GOARCH=amd64 go build main.go
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
To do the same when you want to create a Windows executable, you will execute the following commands:
$ GOOS=windows GOARCH=amd64 go build main.go
$ file main.exe
main.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
As you can see, when building for Windows, the .exe
suffix is automatically appended.
There are many combinations possible which are all listed here.
The most common ones are:
$GOOS $GOARCH
darwin 386 -- 32 bit MacOSX
darwin amd64 -- 64 bit MacOSX
linux 386 -- 32 bit Linux
linux amd64 -- 64 bit Linux
linux arm -- RISC Linux
windows 386 -- 32 bit Windows
windows amd64 -- 64 bit Windows
Caveats
There are some small things which you need to take into account when using cross compilation as not everything is supported.
CGO is not supported
It is currently not possible to produce a cgo
enabled binary when cross compiling from one operating system to another. This is that packages which use cgo
invoke the C compiler as part of the build process to compile their C code and produce the C to Go mapping functions. In the current versions of Go, the name of the C compiler is hardcoded to gcc
. This assumes the system default gcc
compiler even if a cross compiler is installed.
Install vs build
When cross compiling, you should use go build
, not go install
. This is the one of the few cases where go build
is preferable to go install
.
The reason for this is that go install
caches compiled packages, .a
files, into the pkg/
directory which matches the root of the source code.
Take the following example. You are building $GOPATH/src/github.com/lib/mylib
then the compiled package will be installed into $GOPATH/pkg/$GOOS_$GOARCH/github.com/lib/mylib.a
.
The logic is the same for the standard library, which lives in /usr/local/go/src
. They will be compiled to /usr/local/go/pkg/$GOOS_$GOARCH
. This is a problem, because when cross compiling the go tool needs to rebuild the standard library for your target, but the binary distribution expects that /usr/local/go
is not writeable.
Using go build
rather than go install
is the solution, because go build
builds and then throws away most of the result (rather than caching it for later). This leaves you with the final binary in the current directory, which is most likely writeable by you.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.