Search code examples
linuxdockergcccross-compilingalpine-linux

How to build gcc+tools for cross-compiling inside Alpine Docker container?


For one of my Github projects I'm releasing multi-arch container images for linux/amd64 and linux/arm64. One stage builds a Go fully standalone binary, but it absolutely needs CGO to do so. For the moment, this stage thus cannot be always running as a runner "native" stage, such as amd64 on Github. Instead, it is painfully slow due to the QEMU arm64 emulation on amd64 -- albeit part of the slowness is due to the free Github runners for public projects. On my personal 10yr-old i7 things go by much faster.

Typically, the first search engine result when searching for installing a cross-compiling tool chain on alpine with musl support is either Cross-compiling with musl Toolchains (ariya.io) or musl.cc itself. The big issue with this "solution" is that first, the packages from musl.cc are terribly outdated (11/2021), and second, are not a version pinnable package source either. Not least on a public project offering container images musl.cc is an absolute no-go. (Discussions about pinning issues with Alpine in general aside.)

Another high ranking hit is xentec/setup-cross-cc.sh, which I simply cannot get to work inside a Docker Alpine container, due to still unresolved does errors. I've seen the issues and the solution is allegedly a newer Docker, runc, and libseccomp -- which I all fulfill on my host system. So this obviously still isn't fixed correctly or has regressed.

I'm also aware of Golang cross compiling with CGO inside docker image -- without any helpful answer. In fact, some of the answers while on the surface looking legit are in their contents not really matching what has been questioned.

How can I build a cross-compiler toolchain of gcc + friends for Alpine-musl inside a (recent) Alpine Docker container?

Please note that I don't want to build (cross) apk Alpine packages. My ultimate Goal is to build Go binaries using cgo.


Solution

  • Happens that there actually already is a neat and clean solution: @tonistiigi/xx. However, this doesn't use gcc but clang/llvm instead. As it turns out, gcc and multi-arch are somewhat not best friends, as gcc comes from a time where the expectation was to have a single gcc that either builds for its host platform, or cross-compiles to exactly one other platform. But while this answer doesn't solve my original question, it solves my underlying need for cross-compilation in a different, but much easier way.

    xx's documentation explicitly mentions Alpine and shows examples, not least for using Go / Cgo. See also my (canonical) answer here on SO, so I'm not duplicating everything here.

    The gist is as follows:

    FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
    
    FROM --platform=$BUILDPLATFORM golang:alpine
    RUN apk add clang lld
    COPY --from=xx / /
    ARG TARGETPLATFORM
    RUN xx-apk add musl-dev gcc
    ENV CGO_ENABLED=1
    RUN xx-go build -o hello ./hello.go && \
        xx-verify hello