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.

musl-cross-make

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.

homebrew-musl-cross

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 x86_64-linux-musl-gcc.

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 --with-mips.

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-gcc and x86_64-linux-musl-g++ (or corresponding), on top of the usual GOOS and GOARCH.

To use this toolchain as the target linker for Rust cross-compilation, add lines like these to your .cargo/config:

[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"

A more complete guide to Rust cross-compilation is here.

mingw-w64

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 x86_64-w64-mingw32- and i686-w64-mingw32-.

If you find cross-compilation more fun than it probably is, you might want to follow me on Twitter.