To cross compile a binary for a different OS and CPU architecture, using Docker, follow these simple steps:
1) Finding the right docker image
Since each docker image is built against a specific CPU architecture, the first step is to find a docker image that combines both the OS and CPU architecture you want to cross compile for.
You can see the CPU architecture an image was built for on Docker Hub by scanning the "OS/ARCH" column:
The most popular docker images tend to offer multiple builds, each targeting a different CPU architecture. The following shows the latest tag of ubuntu
. As you can see, it offers builds for multiple CPU architectures:
Let's assume we want to build an ImageMagick binary for Ubuntu (ARM64) on our MacBook (x86, aka AMD64). Since the above shows ubuntu
supports linux/arm64/v8
, we're ready to move on to step 2!
2) Running the docker image
By default docker run
will pick the image that matches your host machine's CPU architecture. This is for performance reasons, since the emulation adds overhead.
We can see docker picking the x86 image by default:
$ docker run ubuntu uname -p
x86_64
To force docker into selecting (and emulating the hardware for) the ARM64 version of the ubuntu
image, we simply add the --platform
flag:
$ docker run --platform linux/arm64/v8 ubuntu uname -p
aarch64
Excellent! We can now boot-up an Ubuntu ARM64 machine to build our native binaries on!
3) Building your native binaries
The rest is easy: just compile your binaries inside the docker container we launched above. Remember: the --platform
flag is crucial! (You can always run uname -p
inside your container to make sure you are really being emulated.)
Be warned: CPU architecture emulation adds significant overhead. In our experience, compile times can take up to 5x longer when emulating via the--platform
tag. Maybe go grab a coffee after startingmake
!