tl;dr: you can install cross-compiler toolchains to compile C/C++ for Windows or Linux from macOS with these two Homebrew Formulas.
brew install FiloSottile/musl-cross/musl-cross brew install mingw-w64
Cross-compiling C and C++ is dreadful.
While in Go you just need to set an environment variable, for C you need a whole separate toolchain, that might require an intermediate toolchain to build, and you need to know what you are targeting very well.
Thankfully, Rich Felker built a Makefile set to build musl-based cross-compilers, musl-cross-make. It took a few patches, but it runs well on macOS.
musl-cross-make builds beautifully self-contained cross-compilers, so you don't have to worry about pointing to the right libraries path or about where you keep the toolchain. Also, it can target Linux running on a number of different architectures.
Maybe most importantly, it's based on the musl C standard library. This means that the binaries will only run on a musl-based system, like Alpine. However, if you build them as static binaries by passing
-static as a LDFLAG they will run anywhere, including in scratch Docker containers. musl is specifically engineered to support fully static binaries, which is not recommended with glibc.
Still, I'm a big Homebrew fan. It lets you build software in a well defined sandbox, and only the binaries are linked into your PATH, GNU Stow style. Also, it manages resources and offers powerful dev tools.
So, I wrapped up musl-cross-make in a Homebrew Formula, FiloSottile/homebrew-musl-cross. It takes a long time to build, but it generates a full cross-compiler toolchain, and links into
/usr/local/bin just the prefixed binaries, like
brew install FiloSottile/musl-cross/musl-cross
It comes with a precompiled Homebrew Bottle for High Sierra, so if you want to build everything from source use
brew install --build-from-source.
Other architectures are supported. For example to get a Raspberry Pi cross-compiler use:
brew install FiloSottile/musl-cross/musl-cross --without-x86_64 --with-arm-hf
You can also use
--with-i486 (x86 32-bit),
--with-aarch64 (ARM 64-bit),
--with-arm (ARM soft-float) and
Using this with Go and Rust
To cross-compile cgo projects you can set the CC and CXX environment flags when building to
x86_64-linux-musl-g++ (or corresponding), on top of the usual
To use this toolchain as the target linker for Rust cross-compilation, add lines like these to your
[target.x86_64-unknown-linux-musl] linker = "x86_64-linux-musl-gcc"
A more complete guide to Rust cross-compilation is here.
For Windows, there is now a Mingw-w64 Formula directly in homebrew-core, so you can install it simply with
brew install mingw-w64.
The resulting GCC toolchain has prefixes
If you find cross-compilation more fun than it probably is, you might want to follow me on Twitter.