Skip to main content

Cross Building Mingw-w64 Toolchain on macOS

· 3 min read

In this blog, we will show the steps of building Mingw-w64 on macOS system. In fact, we can install mingw-w64 corss building toolchain by homebrew package manager. Here, we jsut analysis the building steps of mingw-w64 toolchain, and it can be easily migrated to linux system.

Overview

We need to build following tools/libraries:

  • binutils: "Binutils is a collection of binary programming tools used to assemble, link and manipulate binary and object files.", like gnu linker ld, gnu assembler as, nm, ar and strings. see more.
  • texinfo: Apple's makeinfo is old and has bugs. It be only used as building dependency.
  • gcc: compiler for c/c++/fortran language.
  • mingw-w64: "The mingw-w64 project is a complete runtime environment for gcc to support binaries native to Windows 64-bit and 32-bit operating systems.". Provide windows api headers, runtime and other tools.

Build texinfo

wget https://ftp.gnu.org/gnu/texinfo/texinfo-6.7.tar.gz
# wget https://mirrors.ustc.edu.cn/gnu/texinfo/texinfo-6.7.tar.gz
tar zxvf texinfo-6.7.tar.gz
cd texinfo-6.7
./configure --prefix=$HOME/.local/develop/mingw-w64/texinfo
make
make install

Then set PATH env to load this tool:

export PATH=$HOME/.local/develop/mingw-w64/texinfo/bin:$PATH

Build binutils

wget https://ftp.gnu.org/gnu/binutils/binutils-2.34.tar.xz
# wget https://mirrors.ustc.edu.cn/gnu/binutils/binutils-2.34.tar.gz
tar zxvf binutils-2.34.tar.gz
cd binutils-2.34
mkdir binutils-build && cd binutils-build
# in binutils-build directory
prefix=$HOME/.local/develop/mingw-w64/toolchain-x86_64
../configure --prefix=${prefix} \
--target=x86_64-w64-mingw32 --enable-targets=x86_64-w64-mingw32 \
--with-sysroot=${prefix} --disable-multilib
make
make install

Then set PATH env to load binutils tools:

export PATH=$prefix/bin:$PATH
ln -s $prefix/x86_64-w64-mingw32 $prefix/mingw

Copy mingw-w64 headers

wget https://downloads.sourceforge.net/project/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v7.0.0.tar.bz2
# or download from https://github.com/mirror/mingw-w64 release
tar xvjf mingw-w64-v7.0.0.tar.bz2
cd mingw-w64-7.0.0/mingw-w64-headers/
mkdir headers-build
cd headers-build
# in headers-build directory
../configure --prefix=$prefix/x86_64-w64-mingw32 --host=x86_64-w64-mingw32
make
make install

Build gcc

wget https://ftp.gnu.org/gnu/gcc/gcc-9.2.0/gcc-9.2.0.tar.gz
# wget https://mirrors.ustc.edu.cn/gnu/gcc/gcc-9.2.0/gcc-9.2.0.tar.gz
tar zxvf gcc-9.2.0.tar.gz
cd gcc-9.2.0
./contrib/download_prerequisites # download gmp mpfr mpc and isl, you can also edit this script to change base_url to use a mirror.
mkdir gcc-build
cd gcc-build
# in gcc-build directory
../configure --prefix=${prefix} \
--with-sysroot=${prefix} \
--target=x86_64-w64-mingw32 \
--enable-languages=c,c++,fortran \
--with-ld=${prefix}/bin/x86_64-w64-mingw32-ld
--with-as${prefix}/bin/x86_64-w64-mingw32-as
--disable-multilib \
--enable-threads=posix
make all-gcc -j 8
make install-gcc

If we run make all, then error pthread.h is not found will happen.
So winpthreads must be built befor finishing building gcc.

Build the mingw-w64 runtime

cd mingw-w64-7.0.0/mingw-w64-crt/
mkdir build-crt
cd build-crt
# in build-crt
../configure --prefix=$prefix/x86_64-w64-mingw32 \
--with-sysroot=$prefix/x86_64-w64-mingw32 \
--host=x86_64-w64-mingw32 \
--disable-lib32 \
--enable-lib64 \
CC=x86_64-w64-mingw32-gcc \
CXX=x86_64-w64-mingw32-g++ \
CPP=x86_64-w64-mingw32-cpp
make
make install

Build the winpthreads library

cd mingw-w64-7.0.0/mingw-w64-libraries/winpthreads/
mkdir winpthreads-build
cd winpthreads-build
# in winpthreads-build
../configure --prefix=$prefix/x86_64-w64-mingw32 \
--with-sysroot=$prefix/x86_64-w64-mingw32 \
--host=x86_64-w64-mingw32 \
CC=x86_64-w64-mingw32-gcc \
CXX=x86_64-w64-mingw32-g++ \
CPP=x86_64-w64-mingw32-cpp
make
make install

Finish building GCC (runtime libraries)

cd gcc-9.2.0/gcc-build
make -j 8
make install

Go for it

We have following source file, named main.cc

#include <stdio.h>
#include <windows.h>
int main() {
puts("Hello world!");
MessageBox(NULL, TEXT("Hello GUI!"), TEXT("HelloMsg"), 0);
return 0;
}

Build it:

x86_64-w64-mingw32-g++ main.cc # it will produce `a.exe` file.