Now that Go 1.5 is out, lots of gophers are excited to try the much improved cross compilation support. For some background on the changes to the cross compilation story you can read my previous post, or Rakyll’s excellent follow up piece.
I’ll assume that you are using the binary version of Go 1.5, as distributed from the Go website. If you are using Go 1.5 from your operating system’s distribution, or homebrew, the process will be the same, however paths may differ slightly.
How to cross compile
To cross compile a Go program using Go 1.5 the process is as follows:
GOARCH to be the values for the target operating system and architecture.
go build -v YOURPACKAGE
If the compile is successful you’ll have a binary called
YOURPACKAGE (possibly with a
.exe extension if you’re targeting Windows) in your current working directory.
-o may be used to alter the name and destination of your binary, but remember that go build takes a value that is relative to your
$GOPATH/src, not your working directory, so changing directories then executing the
go build command is also an option.
I prefer to combine the two steps outlined above into one, like this:
% env GOOS=linux GOARCH=arm go build -v github.com/constabulary/gb/cmd/gb
% file ./gb
./gb: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped
and that’s all there is to it.
Using go build vs go install
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
The reason for this is
go install always caches compiled packages,
.a files, into the
pkg/ directory that matches the root of the source code.
For example, if you are building
$GOPATH/src/github.com/lib/pq, then the compiled package will be installed into
This logic also holds true for the standard library, which lives in
/usr/local/go/src, so 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.
go build rather that
go install is the solution here, because
go build builds, then throws away most of the result (rather than caching it for later), leaving you with the final binary in the current directory, which is most likely writeable by you.
Ugh, this is really slow!
In the procedure described above, cross compilation always rebuilds that standard library for the target every time. Depending on your workflow this is either not an issue, or a really big issue. If it’s the latter then I recommend you remove the binary distribution and build from source into a path that is writeable by you, then you’ll have the full gamut of
go commands available to you.
Cross compilation support in gb is being actively developed and will not have this restriction.
What about GOARM?
go tool chooses a reasonable value for
GOARM by default. You should not change this unless you have a good reason.
But but, what about GOARM=7?
Sure, knock yourself out, but that means your program won’t run on all models of the Raspberry Pi. The difference between
GOARM=6 (the default) and
GOARM=7 is enabling a few more floating point registers, and a few more operations that allow floating point double values to be passed to and from the ARMv7 (VPFv3) floating point co processor more efficiently. IMO, with the current Go 1.5 arm compiler, it’s not worth the bother.