XCPU Translate
A little Go static binary tool to convert Docker's buildx CPU architectures such as linux/arm/v7 to strings for other compilers.
Setup and usage
💡 It should be used with at least one of:
- Docker buildx builds
- BuildKit directly
- Docker builds running with
DOCKER_BUILDKIT=1
Docker platform translation
The following shows an example on how to use it to cross compile a Go program.
We compile for linux/arm/v7 on a linux/amd64 machine using:
docker build --platform linux/arm/v7 .# Note you cannot COPY directly from the image or it will duplicate instructions
# for each target platform. You need to FROM it and then COPY from the alias.
FROM --platform=${BUILDPLATFORM} qmcgaw/xcputranslate:v0.9.0 AS xcputranslate
# We use the builder native architecture to build the program
FROM --platform=${BUILDPLATFORM} golang:1.25-alpine3.22 AS build
# The build argument TARGETPLATFORM is automatically
# plugged in by docker build
ARG TARGETPLATFORM
# Setup additional build dependencies
RUN apk --update add git
ENV CGO_ENABLED=0
WORKDIR /tmp/gobuild
# Download your Go modules
COPY go.mod go.sum ./
RUN go mod download
# Copy your source code
COPY . .
# 📥 Install xcputranslate for your build architecture
COPY --from=xcputranslate /xcputranslate /usr/local/bin/xcputranslate
# 🦾 We cross build for linux/arm/v7
RUN GOARCH="$(xcputranslate translate -targetplatform ${TARGETPLATFORM} -language golang -field arch)" \
GOARM="$(xcputranslate translate -targetplatform ${TARGETPLATFORM} -language golang -field arm)" \
go build -o entrypoint main.go
# This is built on the target architecture (e.g. linux/arm/v7)
FROM alpine:3.22
# Run as user ID 1000, not the default root
USER 1000
ENTRYPOINT ["/usr/local/bin/entrypoint"]
COPY --from=build --chown=1000 /tmp/gobuild/entrypoint /usr/local/bin/entrypointNote that you can also specify a Docker tag to have the program matching a certain Github release. For example:
COPY --from=qmcgaw/xcputranslate:v0.9.0 /xcputranslate /usr/local/bin/xcputranslateSequential cross CPU Docker builds
For now, Buildkit will run all your target platform specific build instructions (such as go build) in parallel. This can be nice but can also cause out of memory errors, even on CIs such as Github Actions. I had the problem with a go build cross compiling for 5+ architectures in parallel. See moby/buildkit#1131 for more context.
To fix this temporay problem, xcputranslate extends its feature by adding a new command: xcputranslate sleep
It allows to sleep before building depending on the target platform and a list of target platforms.
For example:
ARG ALLTARGETPLATFORMS=linux/amd64,linux/386
RUN xcputranslate sleep -targetplatform=${TARGETPLATFORM} -order=${ALLTARGETPLATFORMS} && \
GOARCH="$(xcputranslate translate -targetplatform ${TARGETPLATFORM} -language golang -field arch)" \
GOARM="$(xcputranslate translate -targetplatform ${TARGETPLATFORM} -language golang -field arm)" \
go build -o entrypoint main.gowill sleep 0 for linux/amd64 and 3 seconds for linux/386.
The -order defaults to linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le,linux/s390x,linux/riscv64 which is an order sorted by popularity. It means that, for example, for -targetplatform=linux/arm/v7, it will sleep buildtime x 2 where 2 is the order index of the target platform.
The -buildtime flag allows to set the estimated build time.
If for example, your build takes 15 seconds and you want to target the platforms linux/arm64 and linux/s390x only, you should set -buildtime=15s -order=linux/arm64,linux/s390x to have the shortest sleep times possible and each build run sequentially.
Out of Docker
You can also run already built binaries out of Docker:
# Install
VERSION=v0.9.0
ARCH=amd64
wget -O xcputranslate "https://github.com/qdm12/xcputranslate/releases/download/$VERSION/xcputranslate_$VERSION_linux_$ARCH"
chmod +x xcputranslate
# Run
xcputranslate translate -targetplatform "linux/arm/v7" -language golang -field arch
# armDocker platforms supported
linux/amd64linux/386linux/arm64&linux/arm64/v8linux/arm/v6linux/arm/v7linux/s390xlinux/ppc64lelinux/riscv64
Languages supported
Golang
- Use the flag
-field archto obtain the value to use forGOARCH - Use the flag
-field armto obtain the value to use forGOARM
Uname
Not really a language, although it gives the same as uname -m on Linux OSes.
For example linux/arm64 gives aarch64. This is useful for Rust commands for example.
Use it using -language=uname.
Dashes
Not really a language, this is usually used for URLs of pre-made binaries such as https://github.com/moby/buildkit/releases/download/v0.8.3/buildkit-v0.8.3.linux-arm-v7.tar.gz.
For example linux/arm/v7 gives arm-v7.
Use it using -language=dashes.