crazy-max / goxx

Go CGO cross-compiler Docker image
MIT License
44 stars 4 forks source link
cgo cross-compiler docker golang

GitHub release Build Status Test Status Docker Stars Docker Pulls

Become a sponsor Donate Paypal


About

This repo contains a Dockerfile for building an image which can be used as a base for building your Go project using CGO. All the necessary Go tool-chains, C/C++ cross-compilers and platform headers/libraries can be installed with the specially crafted wrappers. This project is heavily inspired by xx project.

Projects using goxx

Docker image

Registry Image
Docker Hub crazymax/goxx
GitHub Container Registry ghcr.io/crazy-max/goxx
$ docker run --rm mplatform/mquery crazymax/goxx:latest
Image: crazymax/goxx:latest
 * Manifest List: Yes
 * Supported platforms:
   - linux/amd64
   - linux/arm64

Supported platforms

Platform CC CXX
darwin/amd64¹ o64-clang o64-clang++
darwin/arm64¹ o64-clang o64-clang++
linux/386 i686-linux-gnu-gcc i686-linux-gnu-g++
linux/amd64 x86_64-linux-gnu-gcc x86_64-linux-gnu-g++
linux/arm64 aarch64-linux-gnu-gcc aarch64-linux-gnu-g++
linux/arm/v5 arm-linux-gnueabi-gcc arm-linux-gnueabi-g++
linux/arm/v6 arm-linux-gnueabi-gcc arm-linux-gnueabi-g++
linux/arm/v7 arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++
linux/mips² mips-linux-gnu-gcc mips-linux-gnu-g++
linux/mipsle² mipsel-linux-gnu-gcc mipsel-linux-gnu-g++
linux/mips64² mips64-linux-gnuabi64-gcc mips64-linux-gnuabi64-g++
linux/mips64le² mips64el-linux-gnuabi64-gcc mips64el-linux-gnuabi64-g++
linux/ppc64le powerpc64le-linux-gnu-gcc powerpc64le-linux-gnu-g++
linux/riscv64 riscv64-linux-gnu-gcc riscv64-linux-gnu-g++
linux/s390x s390x-linux-gnu-gcc s390x-linux-gnu-g++
windows/386 i686-w64-mingw32-gcc i686-w64-mingw32-g++
windows/amd64 x86_64-w64-mingw32-gcc x86_64-w64-mingw32-g++

¹ darwin* platform requires the MacOSX cross toolchain if using CGO.

² compilers for mips* archs are not available with linux/arm64 image.

Usage

In order to use this image effectively, we will use the docker buildx command. Buildx is a Docker component that enables many powerful build features. All builds executed via buildx run with Moby BuildKit builder engine.

# syntax=docker/dockerfile:1

FROM --platform=$BUILDPLATFORM crazymax/goxx:1.17 AS base
ENV GO111MODULE=auto
ENV CGO_ENABLED=1
WORKDIR /go/src/hello

FROM base AS build
ARG TARGETPLATFORM
RUN --mount=type=cache,sharing=private,target=/var/cache/apt \
  --mount=type=cache,sharing=private,target=/var/lib/apt/lists \
  goxx-apt-get install -y binutils gcc g++ pkg-config
RUN --mount=type=bind,source=. \
  --mount=type=cache,target=/root/.cache \
  --mount=type=cache,target=/go/pkg/mod \
  goxx-go build -o /out/hello ./hello.go

FROM scratch AS artifact
COPY --from=build /out /

FROM scratch
COPY --from=build /out/hello /hello
ENTRYPOINT [ "/hello" ]

More details about multi-platform builds in this blog post.

Let's run a simple build against the artifact target in our Dockerfile:

# build and output content of the artifact stage that contains the binaries in ./dist
docker buildx build \
  --platform "linux/amd64,linux/arm64,linux/arm/v7,darwin/amd64" \
  --output "./dist" \
  --target "artifact" .

$ tree ./dist
./dist
├── darwin_amd64
│ ├── hello
├── linux_amd64
│ ├── hello
├── linux_arm64
│ ├── hello
├── linux_arm_v7
│ ├── hello

You can also create a multi-platform image in addition to the artifacts:

docker buildx build \
  --platform "linux/amd64,linux/arm64,linux/arm/v7" \
  --tag "hello:latest" \
  --push .

More examples can be found in the examples folder.

Build

Build goxx yourself using Docker buildx bake:

git clone https://github.com/crazy-max/goxx.git goxx
cd goxx

# create docker container builder
docker buildx create --name goxx --use

# build goxx image and output to docker with goxx:local tag (default)
docker buildx bake image-local

# examples
(cd ./examples/c ; docker buildx bake artifact-all)
(cd ./examples/cpp ; docker buildx bake artifact-all)
(cd ./examples/echo ; docker buildx bake artifact-all)
(cd ./examples/gorm ; docker buildx bake artifact-all)
(cd ./examples/jq ; docker buildx bake artifact-all)

Notes

MacOSX cross toolchain

You can use the MacOSX cross toolchain provided by crazymax/osxcross image to build against the darwin platform with CGO.

Using the COPY command:

FROM --platform=$BUILDPLATFORM crazymax/osxcross:11.3 AS osxcross
FROM base AS build
COPY --from=osxcross /osxcross /osxcross
ARG TARGETPLATFORM
RUN --mount=type=bind,source=. \
  --mount=type=cache,target=/root/.cache \
  --mount=type=cache,target=/go/pkg/mod \
  goxx-go build -o /out/hello ./hello.go

Or a RUN mount:

FROM --platform=$BUILDPLATFORM crazymax/osxcross:11.3 AS osxcross
FROM base AS build
ARG TARGETPLATFORM
RUN --mount=type=bind,source=. \
  --mount=from=osxcross,target=/osxcross,src=/osxcross,rw \
  --mount=type=cache,target=/root/.cache \
  --mount=type=cache,target=/go/pkg/mod \
  goxx-go build -o /out/hello ./hello.go

Wrappers

Wrappers are a significant part of this repo to dynamically handle the build process with a go wrapper named goxx-go which will automatically sets values for GOOS, GOARCH, GOARM, GOMIPS, etc. but also AR, CC, CXX if building with CGO based on defined ARGs in the global scope like TARGETPLATFORM.

It also manages debian packages for cross-compiling for non-native architectures with goxx-apt-get and goxx-macports to install MacPorts packages.

CGO

By default, CGO is enabled in Go when compiling for native architecture and disabled when cross-compiling. It's therefore recommended to always set CGO_ENABLED=0 or CGO_ENABLED=1 when cross-compiling depending on whether you need to use CGO or not.

Install cross-compilers for all platforms

In some case you may want to install cross-compilers for all supported platforms into a fat image:

# syntax=docker/dockerfile:1-labs

ARG PLATFORMS="linux/386 linux/amd64 linux/arm64 linux/arm/v5 linux/arm/v6 linux/arm/v7 linux/mips linux/mipsle linux/mips64 linux/mips64le linux/ppc64le linux/riscv64 linux/s390x windows/386 windows/amd64"

FROM --platform=$BUILDPLATFORM crazymax/goxx:1.17 AS base
ARG PLATFORMS
RUN <<EOT
export GOXX_SKIP_APT_PORTS=1
goxx-apt-get update
for p in $PLATFORMS; do
  TARGETPLATFORM=$p goxx-apt-get install -y binutils gcc g++ pkg-config
done
EOT

Note: This is not recommended for production use.

Contributing

Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. You can also support this project by becoming a sponsor on GitHub or by making a Paypal donation to ensure this journey continues indefinitely!

Thanks again for your support, it is much appreciated! :pray:

License

MIT. See LICENSE for more details.