mirror of https://github.com/status-im/xgo.git
Update xgo to versioned containers.
This commit is contained in:
parent
98aea0a339
commit
d2febd9eba
135
Dockerfile
135
Dockerfile
|
@ -1,135 +0,0 @@
|
||||||
# Go CGO cross compiler
|
|
||||||
# Copyright (c) 2014 Péter Szilágyi. All rights reserved.
|
|
||||||
#
|
|
||||||
# Released under the MIT license.
|
|
||||||
|
|
||||||
FROM ubuntu:14.04
|
|
||||||
|
|
||||||
MAINTAINER Péter Szilágyi <peterke@gmail.com>
|
|
||||||
|
|
||||||
# Create a small script to download binaries and validate their checksum
|
|
||||||
ENV FETCH ./fetch.sh
|
|
||||||
RUN \
|
|
||||||
echo '#!/bin/bash' > $FETCH && \
|
|
||||||
echo 'set -e' >> $FETCH && \
|
|
||||||
echo 'file=`basename $1`' >> $FETCH && \
|
|
||||||
echo 'echo "Downloading $1..."' >> $FETCH && \
|
|
||||||
echo 'wget -q $1' >> $FETCH && \
|
|
||||||
echo 'echo "$2 $file" > $file.sum' >> $FETCH && \
|
|
||||||
echo 'sha1sum -c $file.sum' >> $FETCH && \
|
|
||||||
echo 'rm $file.sum' >> $FETCH && \
|
|
||||||
chmod +x $FETCH
|
|
||||||
|
|
||||||
|
|
||||||
# Make sure apt-get is up to date and dependent packages are installed
|
|
||||||
RUN \
|
|
||||||
apt-get update && \
|
|
||||||
apt-get install -y automake autogen build-essential ca-certificates \
|
|
||||||
gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-multilib gcc-mingw-w64 \
|
|
||||||
clang llvm-dev libtool libxml2-dev uuid-dev libssl-dev patch make \
|
|
||||||
xz-utils cpio wget unzip git mercurial --no-install-recommends
|
|
||||||
|
|
||||||
# Configure the container for OSX cross compilation
|
|
||||||
ENV OSX_SDK_PATH https://github.com/trevd/android_platform_build2/raw/master/osxsdks10.6.tar.gz
|
|
||||||
ENV OSX_SDK MacOSX10.6.sdk
|
|
||||||
|
|
||||||
RUN \
|
|
||||||
git clone https://github.com/tpoechtrager/osxcross.git && \
|
|
||||||
sed -i.bak s/read/#read/g /osxcross/build.sh && \
|
|
||||||
\
|
|
||||||
$FETCH $OSX_SDK_PATH f526b4ae9806e8d31e3b094e3f004f8f160a3fad && \
|
|
||||||
tar -xzf `basename $OSX_SDK_PATH` --strip-components 1 SDKs/$OSX_SDK && \
|
|
||||||
tar -cjf /osxcross/tarballs/$OSX_SDK.tar.bz2 $OSX_SDK && \
|
|
||||||
rm -rf `basename $OSX_SDK_PATH` $OSX_SDK && \
|
|
||||||
\
|
|
||||||
/osxcross/build.sh
|
|
||||||
|
|
||||||
|
|
||||||
# Define the Go packages for each platform
|
|
||||||
ENV DIST_LINUX_64 http://golang.org/dl/go1.3.linux-amd64.tar.gz
|
|
||||||
ENV DIST_LINUX_32 http://golang.org/dl/go1.3.linux-386.tar.gz
|
|
||||||
ENV DIST_LINUX_ARM http://dave.cheney.net/paste/go.1.3.linux-arm~armv5-1.tar.gz
|
|
||||||
ENV DIST_OSX_64 http://golang.org/dl/go1.3.darwin-amd64-osx10.6.tar.gz
|
|
||||||
ENV DIST_OSX_32 http://golang.org/dl/go1.3.darwin-386-osx10.6.tar.gz
|
|
||||||
ENV DIST_WIN_64 http://golang.org/dl/go1.3.windows-amd64.zip
|
|
||||||
ENV DIST_WIN_32 http://golang.org/dl/go1.3.windows-386.zip
|
|
||||||
|
|
||||||
# Download all the Go packages, install the core Linux package, inject and
|
|
||||||
# bootstrap the others
|
|
||||||
RUN \
|
|
||||||
$FETCH $DIST_LINUX_64 b6b154933039987056ac307e20c25fa508a06ba6 && \
|
|
||||||
$FETCH $DIST_LINUX_32 22db33b0c4e242ed18a77b03a60582f8014fd8a6 && \
|
|
||||||
$FETCH $DIST_LINUX_ARM fc059c970a059757778b157b1140a3c56eb1a069 && \
|
|
||||||
$FETCH $DIST_OSX_64 82ffcfb7962ca7114a1ee0a96cac51c53061ea05 && \
|
|
||||||
$FETCH $DIST_OSX_32 159d2797bee603a80b829c4404c1fb2ee089cc00 && \
|
|
||||||
$FETCH $DIST_WIN_64 1e4888e1494aed7f6934acb5c4a1ffb0e9a022b1 && \
|
|
||||||
$FETCH $DIST_WIN_32 e4e5279ce7d8cafdf210a522a70677d5b9c7589d && \
|
|
||||||
\
|
|
||||||
tar -C /usr/local -xzf `basename $DIST_LINUX_64` && \
|
|
||||||
rm -rf /usr/local/go/pkg/linux_amd64_race && \
|
|
||||||
\
|
|
||||||
tar -C /usr/local --wildcards -xzf `basename $DIST_LINUX_32` go/pkg/linux_386 && \
|
|
||||||
GOOS=linux GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap && \
|
|
||||||
tar -C /usr/local --wildcards -xzf `basename $DIST_LINUX_ARM` go/pkg/linux_arm && \
|
|
||||||
GOOS=linux GOARCH=arm /usr/local/go/pkg/tool/linux_amd64/dist bootstrap && \
|
|
||||||
\
|
|
||||||
tar -C /usr/local --wildcards -xzf `basename $DIST_OSX_64` go/pkg/darwin_amd64 && \
|
|
||||||
GOOS=darwin GOARCH=amd64 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap && \
|
|
||||||
tar -C /usr/local --wildcards -xzf `basename $DIST_OSX_32` go/pkg/darwin_386 && \
|
|
||||||
GOOS=darwin GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap && \
|
|
||||||
\
|
|
||||||
unzip -d /usr/local -q `basename $DIST_WIN_64` go/pkg/windows_amd64/* && \
|
|
||||||
GOOS=windows GOARCH=amd64 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap && \
|
|
||||||
unzip -d /usr/local -q `basename $DIST_WIN_32` go/pkg/windows_386/* && \
|
|
||||||
GOOS=windows GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap && \
|
|
||||||
\
|
|
||||||
rm -f `basename $DIST_LINUX_64` `basename $DIST_LINUX_32` `basename $DIST_LINUX_ARM` \
|
|
||||||
`basename $DIST_OSX_64` `basename $DIST_OSX_32` `basename $DIST_WIN_64` `basename $DIST_WIN_32`
|
|
||||||
|
|
||||||
ENV PATH /usr/local/go/bin:$PATH
|
|
||||||
ENV GOPATH /go
|
|
||||||
|
|
||||||
|
|
||||||
# Create a small script to go get a package and cross compile it
|
|
||||||
ENV BUILD ./build.sh
|
|
||||||
RUN \
|
|
||||||
echo '#!/bin/bash' > $BUILD && \
|
|
||||||
echo 'set -e' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Fetching $1...' >> $BUILD && \
|
|
||||||
echo 'go get $1' >> $BUILD && \
|
|
||||||
echo 'cd $GOPATH/src/$1' >> $BUILD && \
|
|
||||||
echo 'pack=`basename $1`' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for linux/amd64...' >> $BUILD && \
|
|
||||||
echo 'GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o $pack-linux-amd64' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for linux/386...' >> $BUILD && \
|
|
||||||
echo 'GOOS=linux GOARCH=386 CGO_ENABLED=1 go build -o $pack-linux-386' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for linux/arm...' >> $BUILD && \
|
|
||||||
echo 'CC=arm-linux-gnueabi-gcc \\' >> $BUILD && \
|
|
||||||
echo ' GOOS=linux GOARCH=arm CGO_ENABLED=1 go build -o $pack-linux-arm' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for windows/amd64...' >> $BUILD && \
|
|
||||||
echo 'CC=x86_64-w64-mingw32-gcc \\' >> $BUILD && \
|
|
||||||
echo ' GOOS=windows GOARCH=amd64 CGO_ENABLED=1 go build -o $pack-windows-amd64.exe' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for windows/386...' >> $BUILD && \
|
|
||||||
echo 'CC=i686-w64-mingw32-gcc \\' >> $BUILD && \
|
|
||||||
echo ' GOOS=windows GOARCH=386 CGO_ENABLED=1 go build -o $pack-windows-386.exe' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for darwin/amd64...' >> $BUILD && \
|
|
||||||
echo '`/osxcross/target/bin/osxcross-env`' >> $BUILD && \
|
|
||||||
echo 'CC=o64-clang \\' >> $BUILD && \
|
|
||||||
echo ' GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build -o $pack-darwin-amd64' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Compiling for darwin/386...' >> $BUILD && \
|
|
||||||
echo 'CC=o32-clang \\' >> $BUILD && \
|
|
||||||
echo ' GOOS=darwin GOARCH=386 CGO_ENABLED=1 go build -o $pack-darwin-386' >> $BUILD && \
|
|
||||||
echo >> $BUILD && \
|
|
||||||
echo 'echo Moving binaries to host...' >> $BUILD && \
|
|
||||||
echo 'cp `ls -t | head -n 7` /build' >> $BUILD && \
|
|
||||||
chmod +x $BUILD
|
|
||||||
|
|
||||||
ENTRYPOINT ["./build.sh"]
|
|
38
README.md
38
README.md
|
@ -1,5 +1,4 @@
|
||||||
xgo - Go CGO cross compiler
|
# xgo - Go CGO cross compiler
|
||||||
===========================
|
|
||||||
|
|
||||||
Although Go strives to be a cross platform language, cross compilation from one
|
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
|
platform to another is not as simple as it could be, as you need the Go sources
|
||||||
|
@ -26,8 +25,7 @@ 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
|
OS specific functionality (e.g. query the CPU load), but need to configure and
|
||||||
maintain separate build environments to do it.
|
maintain separate build environments to do it.
|
||||||
|
|
||||||
Enter xgo
|
## Enter xgo
|
||||||
---------
|
|
||||||
|
|
||||||
My solution to the challenge of cross compiling Go code with embedded C snippets
|
My solution to the challenge of cross compiling Go code with embedded C snippets
|
||||||
(i.e. CGO_ENABLED=1) is based on the concept of [lightweight Linux containers](http://en.wikipedia.org/wiki/LXC).
|
(i.e. CGO_ENABLED=1) is based on the concept of [lightweight Linux containers](http://en.wikipedia.org/wiki/LXC).
|
||||||
|
@ -35,21 +33,19 @@ All the necessary Go tool-chains, C cross compilers and platform headers/librari
|
||||||
have been assembled into a single Docker container, which can then be called as if
|
have been assembled into a single Docker container, which can then be called as if
|
||||||
a single command to compile a Go package to various platforms and architectures.
|
a single command to compile a Go package to various platforms and architectures.
|
||||||
|
|
||||||
Installation
|
## Installation
|
||||||
------------
|
|
||||||
|
|
||||||
Although you could build the container manually, it is available as an automatic
|
Although you could build the container manually, it is available as an automatic
|
||||||
trusted build from Docker's container registry (67MB base + 472MB xgo):
|
trusted build from Docker's container registry (~530MB):
|
||||||
|
|
||||||
docker pull karalabe/xgo
|
docker pull karalabe/xgo-latest
|
||||||
|
|
||||||
To prevent having to remember a potentially complex Docker command every time,
|
To prevent having to remember a potentially complex Docker command every time,
|
||||||
a lightweight Go wrapper was written on top of it.
|
a lightweight Go wrapper was written on top of it.
|
||||||
|
|
||||||
go get github.com/karalabe/xgo
|
go get github.com/karalabe/xgo
|
||||||
|
|
||||||
Usage
|
## Usage
|
||||||
-----
|
|
||||||
|
|
||||||
Simply specify the import path you want to build, and xgo will do the rest:
|
Simply specify the import path you want to build, and xgo will do the rest:
|
||||||
|
|
||||||
|
@ -64,3 +60,25 @@ Simply specify the import path you want to build, and xgo will do the rest:
|
||||||
-rwxr-xr-x 1 root root 4151688 Aug 7 10:01 iris-linux-arm
|
-rwxr-xr-x 1 root root 4151688 Aug 7 10:01 iris-linux-arm
|
||||||
-rwxr-xr-x 1 root root 4228608 Aug 7 10:01 iris-windows-386.exe
|
-rwxr-xr-x 1 root root 4228608 Aug 7 10:01 iris-windows-386.exe
|
||||||
-rwxr-xr-x 1 root root 5243904 Aug 7 10:01 iris-windows-amd64.exe
|
-rwxr-xr-x 1 root root 5243904 Aug 7 10:01 iris-windows-amd64.exe
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
$ xgo -go 1.3.0 github.com/project-iris/iris
|
||||||
|
...
|
||||||
|
|
||||||
|
Since xgo depends on not only the official releases, but also on Dave Cheney's
|
||||||
|
ARM packages, there will be a slight delay between official Go updates and the
|
||||||
|
xgo updates.
|
||||||
|
|
||||||
|
Additionally, a few wildcard release strings are also supported:
|
||||||
|
|
||||||
|
- `-go latest` will use the latest Go release
|
||||||
|
- `-go 1.3.x` will use the latest point release of a specific Go version
|
||||||
|
|
82
xgo.go
82
xgo.go
|
@ -7,6 +7,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -14,31 +16,81 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Docker container configured for cross compilation.
|
// Cross compilation docker containers
|
||||||
var container = "karalabe/xgo"
|
var dockerBase = "karalabe/xgo-base"
|
||||||
|
var dockerDist = "karalabe/xgo-"
|
||||||
|
|
||||||
|
// Command line arguments to fine tune the compilation
|
||||||
|
var goVersion = flag.String("go", "latest", "Go release to use for cross compilation")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Make sure docker is actually available on the system
|
flag.Parse()
|
||||||
fmt.Println("Checking docker installation...")
|
|
||||||
if err := run(exec.Command("docker", "version")); err != nil {
|
// Ensure docker is available
|
||||||
|
if err := checkDocker(); err != nil {
|
||||||
log.Fatalf("Failed to check docker installation: %v.", err)
|
log.Fatalf("Failed to check docker installation: %v.", err)
|
||||||
}
|
}
|
||||||
fmt.Println()
|
// Validate the command line arguments
|
||||||
|
if len(flag.Args()) != 1 {
|
||||||
// Fetch and configure the compilation settings
|
log.Fatalf("Usage: %s [options] <go import path>", os.Args[0])
|
||||||
if len(os.Args) != 2 {
|
|
||||||
log.Fatalf("Usage: %s <go import path>", os.Args[0])
|
|
||||||
}
|
}
|
||||||
path := os.Args[1]
|
// Check that all required images are available
|
||||||
pwd, err := os.Getwd()
|
found, err := checkDockerImage(dockerDist + *goVersion)
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
log.Fatalf("Failed to check docker image availability: %v.", err)
|
||||||
|
case !found:
|
||||||
|
fmt.Println("not found!")
|
||||||
|
if err := pullDockerImage(dockerDist + *goVersion); err != nil {
|
||||||
|
log.Fatalf("Failed to pull docker image from the registry: %v.", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Println("found.")
|
||||||
|
}
|
||||||
|
// Cross compile the requested package into the local folder
|
||||||
|
if err := compile(flag.Args()[0]); err != nil {
|
||||||
|
log.Fatalf("Failed to cross compile package: %v.", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether a docker installation can be found and is functional.
|
||||||
|
func checkDocker() error {
|
||||||
|
fmt.Println("Checking docker installation...")
|
||||||
|
if err := run(exec.Command("docker", "version")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether a required docker image is available locally.
|
||||||
|
func checkDockerImage(image string) (bool, error) {
|
||||||
|
fmt.Printf("Checking for required docker image %s... ", image)
|
||||||
|
out, err := exec.Command("docker", "images", "--no-trunc").Output()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return bytes.Contains(out, []byte(image)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pulls an image from the docker registry.
|
||||||
|
func pullDockerImage(image string) error {
|
||||||
|
fmt.Printf("Pulling %s from docker registry...\n", image)
|
||||||
|
fmt.Printf("Note, this may take some time, but due to a docker bug, progress cannot be displayed.\n")
|
||||||
|
return run(exec.Command("docker", "pull", image))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cross compiles a requested package into the current working directory.
|
||||||
|
func compile(path string) error {
|
||||||
|
folder, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to retrieve the working directory: %v.", err)
|
log.Fatalf("Failed to retrieve the working directory: %v.", err)
|
||||||
}
|
}
|
||||||
// Cross compile the requested package into the local folder
|
|
||||||
fmt.Printf("Cross compiling %s...\n", path)
|
fmt.Printf("Cross compiling %s...\n", path)
|
||||||
if err := run(exec.Command("docker", "run", "-v", pwd+":/build", container, path)); err != nil {
|
if err := run(exec.Command("docker", "run", "-v", folder+":/build", dockerDist+*goVersion, path)); err != nil {
|
||||||
log.Fatalf("Failed to cross compile package: %v.", err)
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes a command synchronously, redirecting its output to stdout.
|
// Executes a command synchronously, redirecting its output to stdout.
|
||||||
|
|
Loading…
Reference in New Issue