xgo/README.md

236 lines
11 KiB
Markdown
Raw Normal View History

2014-08-13 12:09:53 +00:00
# xgo - Go CGO cross compiler
2014-08-06 20:55:14 +00:00
2014-08-07 07:05:33 +00:00
Although Go strives to be a cross platform language, cross compilation from one
platform to another is not as simple as it could be, as you need the Go sources
bootstrapped to each platform and architecture.
The first step towards cross compiling was Dave Cheney's [golang-crosscompile](https://github.com/davecheney/golang-crosscompile)
package, which automatically bootstrapped the necessary sources based on your
existing Go installation. Although this was enough for a lot of cases, certain
drawbacks became apparent where the official libraries used CGO internally: any
dependency to third party platform code is unavailable, hence those parts don't
cross compile nicely (native DNS resolution, system certificate access, etc).
A step forward in enabling cross compilation was Alan Shreve's [gonative](https://github.com/inconshreveable/gonative)
package, which instead of bootstrapping the different platforms based on the
existing Go installation, downloaded the official pre-compiled binaries from the
golang website and injected those into the local toolchain. Since the pre-built
binaries already contained the necessary platform specific code, the few missing
dependencies were resolved, and true cross compilation could commence... of pure
Go code.
However, there was still one feature missing: cross compiling Go code that used
CGO itself, which isn't trivial since you need access to OS specific headers and
libraries. This becomes very annoying when you need access only to some trivial
OS specific functionality (e.g. query the CPU load), but need to configure and
maintain separate build environments to do it.
2014-08-13 12:09:53 +00:00
## Enter xgo
2014-08-07 07:05:33 +00:00
My solution to the challenge of cross compiling Go code with embedded C/C++ snippets
2014-08-07 07:09:32 +00:00
(i.e. CGO_ENABLED=1) is based on the concept of [lightweight Linux containers](http://en.wikipedia.org/wiki/LXC).
2014-08-07 07:05:33 +00:00
All the necessary Go tool-chains, C cross compilers and platform headers/libraries
have been assembled into a single Docker container, which can then be called as if
2014-08-08 10:33:03 +00:00
a single command to compile a Go package to various platforms and architectures.
2014-08-07 07:05:33 +00:00
2014-08-13 12:09:53 +00:00
## Installation
2014-08-07 07:05:33 +00:00
Although you could build the container manually, it is available as an automatic
2015-09-14 15:28:45 +00:00
trusted build from Docker's container registry (not insignificant in size):
2014-08-07 07:05:33 +00:00
2014-08-13 12:09:53 +00:00
docker pull karalabe/xgo-latest
2014-08-07 07:05:33 +00:00
To prevent having to remember a potentially complex Docker command every time,
a lightweight Go wrapper was written on top of it.
2014-08-07 07:08:06 +00:00
go get github.com/karalabe/xgo
2014-08-07 07:05:33 +00:00
2014-08-13 12:09:53 +00:00
## Usage
2014-08-07 07:05:33 +00:00
Simply specify the import path you want to build, and xgo will do the rest:
2014-08-07 07:08:06 +00:00
$ xgo github.com/project-iris/iris
2014-08-07 07:08:52 +00:00
...
2014-08-07 07:08:06 +00:00
$ ls -al
2015-09-14 15:28:45 +00:00
-rwxr-xr-x 1 root root 10899488 Sep 14 18:05 iris-android-21-arm
-rwxr-xr-x 1 root root 6442188 Sep 14 18:05 iris-darwin-386
-rwxr-xr-x 1 root root 8228756 Sep 14 18:05 iris-darwin-amd64
-rwxr-xr-x 1 root root 9532568 Sep 14 18:05 iris-linux-386
-rwxr-xr-x 1 root root 11776368 Sep 14 18:05 iris-linux-amd64
-rwxr-xr-x 1 root root 9408928 Sep 14 18:05 iris-linux-arm
-rwxr-xr-x 1 root root 7131477 Sep 14 18:05 iris-windows-386.exe
-rwxr-xr-x 1 root root 8963900 Sep 14 18:05 iris-windows-amd64.exe
2015-09-17 13:10:47 +00:00
If the path is not a canonical import path, but rather a local path (starts with
a dot `.` or a dash `/`), xgo will use the local GOPATH contents for the cross
compilation.
### Build flags
A handful of flags can be passed to `go build`. The currently supported ones are
- `-v`: prints the names of packages as they are compiled
2015-09-14 15:28:45 +00:00
- `-x`: prints the build commands as compilation progresses
- `-race`: enables data race detection (supported only on amd64, rest built without)
- `-tags='tag list'`: list of build tags to consider satisfied during the build
- `-ldflags='flag list'`: arguments to pass on each go tool link invocation
2014-08-13 12:09:53 +00:00
### Go releases
As newer versions of the language runtime, libraries and tools get released,
these will get incorporated into xgo too as extensions layers to the base cross
compilation image (only Go 1.3 and above will be supported).
You can select which Go release to work with through the `-go` command line flag
to xgo and if the specific release was already integrated, it will automatically
be retrieved and installed.
2015-09-14 15:28:45 +00:00
$ xgo -go 1.5.1 github.com/project-iris/iris
2014-08-13 12:09:53 +00:00
Additionally, a few wildcard release strings are also supported:
2015-09-14 15:28:45 +00:00
- `1.5.x` will use the latest point release of a specific Go version
2015-11-19 13:10:51 +00:00
- `latest` will use the latest Go release (this is the default)
- `develop` will use the master branch of the Go repository
### Output prefixing
xgo by default uses the name of the package being cross compiled as the output
file prefix. This can be overridden with the `-out` flag.
$ xgo -out iris-v0.3.2 github.com/project-iris/iris
...
$ ls -al
2015-09-14 15:28:45 +00:00
-rwxr-xr-x 1 root root 10899488 Sep 14 18:08 iris-v0.3.2-android-21-arm
-rwxr-xr-x 1 root root 6442188 Sep 14 18:08 iris-v0.3.2-darwin-386
-rwxr-xr-x 1 root root 8228756 Sep 14 18:08 iris-v0.3.2-darwin-amd64
-rwxr-xr-x 1 root root 9532568 Sep 14 18:08 iris-v0.3.2-linux-386
-rwxr-xr-x 1 root root 11776368 Sep 14 18:08 iris-v0.3.2-linux-amd64
-rwxr-xr-x 1 root root 9408928 Sep 14 18:08 iris-v0.3.2-linux-arm
-rwxr-xr-x 1 root root 7131477 Sep 14 18:08 iris-v0.3.2-windows-386.exe
-rwxr-xr-x 1 root root 8963900 Sep 14 18:08 iris-v0.3.2-windows-amd64.exe
### Branch selection
Similarly to `go get`, xgo also uses the `master` branch of a repository during
source code retrieval. To switch to a different branch before compilation pass
the desired branch name through the `--branch` argument.
$ xgo --branch release-branch.go1.4 golang.org/x/tools/cmd/goimports
...
$ ls -al
2015-09-14 15:28:45 +00:00
-rwxr-xr-x 1 root root 4928992 Sep 14 18:10 goimports-android-21-arm
-rwxr-xr-x 1 root root 4139868 Sep 14 18:10 goimports-darwin-386
-rwxr-xr-x 1 root root 5186720 Sep 14 18:10 goimports-darwin-amd64
-rwxr-xr-x 1 root root 4189448 Sep 14 18:10 goimports-linux-386
-rwxr-xr-x 1 root root 5264120 Sep 14 18:10 goimports-linux-amd64
-rwxr-xr-x 1 root root 4209400 Sep 14 18:10 goimports-linux-arm
-rwxr-xr-x 1 root root 4348416 Sep 14 18:10 goimports-windows-386.exe
-rwxr-xr-x 1 root root 5415424 Sep 14 18:10 goimports-windows-amd64.exe
### Remote selection
Yet again similarly to `go get`, xgo uses the repository remote corresponding to
the import path being built. To switch to a different remote while preserving the
original import path, use the `--remote` argument.
$ xgo --remote github.com/golang/tools golang.org/x/tools/cmd/goimports
2015-09-14 15:28:45 +00:00
...
### Package selection
If you used the above *branch* or *remote* selection machanisms, it may happen
that the path you are trying to build is only present in the specific branch and
not the default respoitory, causing Go to fail at locating it. To circumvent this,
you may specify only the repository root for xgo, and use an additional `--pkg`
parameter to select the exact package within, honoring any prior *branch* and
*remote* selections.
$ xgo --pkg cmd/goimports golang.org/x/tools
...
$ ls -al
-rwxr-xr-x 1 root root 4924036 Sep 14 18:09 goimports-android-21-arm
-rwxr-xr-x 1 root root 4135776 Sep 14 18:09 goimports-darwin-386
-rwxr-xr-x 1 root root 5182624 Sep 14 18:09 goimports-darwin-amd64
-rwxr-xr-x 1 root root 4184416 Sep 14 18:09 goimports-linux-386
-rwxr-xr-x 1 root root 5254800 Sep 14 18:09 goimports-linux-amd64
-rwxr-xr-x 1 root root 4204440 Sep 14 18:09 goimports-linux-arm
-rwxr-xr-x 1 root root 4343296 Sep 14 18:09 goimports-windows-386.exe
-rwxr-xr-x 1 root root 5409280 Sep 14 18:09 goimports-windows-amd64.exe
This argument may at some point be integrated into the import path itself, but for
now it exists as an independent build parameter. Also, there is not possibility
for now to build mulitple commands in one go.
2015-09-14 15:28:45 +00:00
### Limit build targets
By default `xgo` will try and build the specified package to all platforms and
architectures supported by the underlying Go runtime. If you wish to restrict
the build to only a few target systems, use the comma separated `--targets` CLI
argument:
* `--targets=linux/arm`: builds only the ARMv5 Linux binaries
* `--targets=windows/*,darwin/*`: builds all Windows and OSX binaries
* `--targets=*/arm`: builds ARM binaries for all platforms
* `--targets=*/*`: builds all suppoted targets (default)
### Platform versions
2015-09-14 15:28:45 +00:00
By default `xgo` tries to cross compile to the lowest possible versions of every
supported platform, in order to produce binaries that are portable among various
versions of the same operating system. This however can lead to issues if a used
dependency is only supported by more recent systems. As such, `xgo` supports the
selection of specific platform versions by appending them to the OS target string.
2015-09-14 15:28:45 +00:00
* `--targets=android-16/*`: cross compile to Android Jelly Bean
* `--targets=darwin-10.9/*`: cross compile to Mac OS X Mavericks
* `--targets=windows-6.0/*`: cross compile to Windows Vista
The supported platforms are:
2015-09-14 15:33:19 +00:00
* All Android APIs up to Android Lollipop 5.0 ([API level ids](https://source.android.com/source/build-numbers.html))
* All Windows APIs up to Windows 8.1 limited by `mingw-w64` ([API level ids](https://en.wikipedia.org/wiki/Windows_NT#Releases))
* OSX APIs in the range of 10.6 - 10.9
2015-09-14 15:33:19 +00:00
### CGO dependencies
The main differentiator of xgo versus other cross compilers is support for basic
embedded C/C++ code and target-platform specific OS SDK availability. The current
xgo release introduces an experimental CGO *dependency* cross compilation, enabling
building Go programs that require external C/C++ libraries.
It is assumed that the dependent C/C++ library is `configure/make` based, was
properly prepared for cross compilation and is available as a tarball download
(`.tar`, `.tar.gz` or `.tar.bz2`). Further plans include extending this to cmake
based projects, if need arises (please open an issue if it's important to you).
Such dependencies can be added via the `--deps` argument. They will be retrieved
prior to starting the cross compilation and the packages cached to save bandwidth
on subsequent calls.
A complex sample for such a scenario is building the Ethereum CLI node, which has
the GNU Multiple Precision Arithmetic Library as it's dependency.
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
--branch=develop github.com/ethereum/go-ethereum/cmd/geth
...
$ ls -al
2015-09-14 15:34:47 +00:00
-rwxr-xr-x 1 root root 23213372 Sep 14 17:59 geth-android-21-arm
-rwxr-xr-x 1 root root 14373980 Sep 14 17:59 geth-darwin-386
-rwxr-xr-x 1 root root 17373676 Sep 14 17:59 geth-darwin-amd64
-rwxr-xr-x 1 root root 21098910 Sep 14 17:59 geth-linux-386
-rwxr-xr-x 1 root root 25049693 Sep 14 17:59 geth-linux-amd64
-rwxr-xr-x 1 root root 20578535 Sep 14 17:59 geth-linux-arm
-rwxr-xr-x 1 root root 16351260 Sep 14 17:59 geth-windows-386.exe
-rwxr-xr-x 1 root root 19418071 Sep 14 17:59 geth-windows-amd64.exe
Note, that since xgo needs to cross compile the dependencies for each platform
and architecture separately, build time can increase significantly.