About Talks Articles

Cross-compiling with musl Toolchains

3 min read

When working on command-line utilities which can be useful for various platforms, from Windows on x86 to Linux on MIPS, the existence of a cross-compilation is highly attractive. A number of different binaries can be constructed conveniently from a single, typically powerful host system.

Alpine Linux popularizes the use of musl a no-frills C standard library for Linux. According to its website:

musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety.

In addition, thanks to Zach van Rijn, we have a collection of static toolchains based on musl at at our disposal. The number of supported systems is rather mind blowing, you got everything from the usual i686 to MIPS to Microblaze and many others.

As I search for a viable alternative to the cross-compilation method based on Dockcross (see my previous blog post: Cross Compiling with Docker on WSL 2), fits the requirements nicely. I am in the process of migrating the continuous integration of FastLZ, my implementation of byte-aligned LZ77 compression algorithm, to be completely based on

Here is a quick walkthrough. As long as you are on Linux x86-64, you can follow along easily (and yes, this also works great on WSL, Windows Subsystems for Linux). As a reference, we will use the simplest ANSI C/C90 program available at

Cross compilation with musl Toolchains

First and foremost, we need QEMU so we can test our binaries not native to x86-64. For convenience, GNU Make is also necessary.

$ sudo apt install -y qemu-users make

After that, let us grab the Hello C90 program:

$ git clone
$ cd hello-c90

For a start, let us try to produce MIPS64 binary of our little Hello C90 program. Thus, we ought to grab the toolchains first, weighing at about 90 MB.

$ curl -O
$ tar xzf mips64-linux-musl-cross.tgz

To ensure that this fresh cross-compiler works, do a quick sanity check:

$ ./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc --version
mips64-linux-musl-gcc (GCC) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO

This looks good! Now we can compile our Hello C90 program statically:

$ make CC=./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc LDFLAGS=-static
./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc -O -Wall -std=c90 -c hello.c
./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc -static -o hello hello.o

Checking the resulting binary should give the following:

$ file ./hello
./hello: ELF 64-bit MSB executable, MIPS, MIPS-III version 1 (SYSV), statically linked, not stripped

It is exactly what we want! To run the executable:

$ qemu-mips64 ./hello
Hello, world! From C90 with love...

Now, if you are doing this on WSL, or generally have a Windows machine available elsewhere, there is this fun activity of cross-compiling the above app for Windows, without the need for any Windows compiler and SDK. Same steps as before:

$ curl -O
$ tar xzf x86_64-w64-mingw32-cross.tgz
$ make CC=./x86_64-w64-mingw32-cross/bin/x86_64-w64-mingw32-gcc LDFLAGS=-static
$ file ./hello.exe
./hello.exe: PE32+ executable (console) x86-64, for MS Windows

To really test it, just bring hello.exe to Windows and it is going to run as expected.

For more details and elaborated examples, check the collection of workflows YAML files of this Hello C program.

Combined with the continuous integration system of your choice, whether it is DIY via Jenkins or using one of the many services out there (GitHub Actions, Azure Pipelines, Travis CI), creating binaries for various operating systems becomes easier than ever!

Related posts:

♡ this article? Explore more articles and follow me Twitter.

Share this on Twitter Facebook