Cross-compile native mingw compilers for windows

Now that I successfully built the linux version of the mingw compilers for win64 and win32, I figured out the next logical step would be to try to build the native version of those compilers to run on windows. So here we go!

Gathering informations

Starting from those official (but old ?) instructions from mingw wiki pages:

It makes sense: we should just be able to use the same compiler from the same sources, but to run on a different host…

First iteration

  • Building binutils: OK
  • The instructions mention creating a 'winsup' folder: disregarding this step
  • Installing the headers: OK
  • Building gcc stage 1: getting error:
    The directory that should contain system headers does not exist:
    make[1]: * [stmp-fixinc] Error 1
    • This error could be related to the previous step we just skipped… let's reconsider that. Adding this section in our build script just before gcc stage 1:
        # Create the winsup folder if required:
        if [ "$flavor" == "win" ]; then
          mkdir -p $__gcc/winsup/mingw
          ln -s $idir/$tgt/include $__gcc/winsup/mingw/include
    • same error
    • Trying instead to provide the cross-compiler include and lib paths when building gcc and building it completely instead of only stage 1: same error, but keeping this change.
    • Now trying to simply add the missing required folder /mingw/include: OK

⇒ So it turns out that when building the native compilers we use the libs created for the cross compilers. Thus, gcc canbe compiled in a single stage.

⇒ Also, we don't bother compiler the CRT libraries for the native compilers, instead we simply copy them from the cross-compiler folder.

Now testing our new native win64 compiler on windows: Error: pthreads headers are not found, so we should build pthread too for the native compiler: OK after this change everything is fine :-)

Also testing building the win32 native compiler and testing on windows: OK ! (which is nice because the precompiled win32 compiler I tried before was not working !)


So, this was far less complicated than the cross-compiler build described in my previous post: in the process I updated my build script to support building both linux and windows versions of the mingw32 and mingw64 compilers. The only important requirement one should keep in mind if trying to use those scripts is that the linux version of the compilers should be built before trying to build the native version, because in the native build pipeline we will simply copy some files that where previously generated in the linux hosted version.

The current scripts I use are:

# Helper method used to build a compiler from sources given its target architecture (either '64' or '32')
#arg1: target architecture
#arg2: host version to build: "linux" or "win"
  local arch="$1"
  local flavor="$2"

  local sdir="/mnt/array1/dev/compilers" # source file directory
  local bdir="/mnt/array1/dev/build/mingw${arch}" # Build directory
  local compdir="/mnt/array1/dev/compilers"
  local idir="$compdir/$flavor-mingw${arch}" # installation directory
  local tgt="x86_64-w64-mingw32"
  if [ "$arch" == "32" ]; then

  local build="x86_64-linux-gnu"
  local host="$build"
  if [ "$flavor" == "win" ]; then

  local srcfile="mingw64_sources" # archive file base name
  local __binutils="binutils-2.28"
  local __gmp="gmp-6.1.2"
  local __headers="mingw-w64/mingw-w64-headers"
  local __crt="mingw-w64/mingw-w64-crt"
  local __pthreads="mingw-w64/mingw-w64-libraries/winpthreads"
  local __mpfr="mpfr-3.1.5"
  local __mpc="mpc-1.0.3"
  local __isl="isl-0.18"
  local __gcc="gcc-7.1.0"

  local cpus=$(grep -c processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu | tr -d "\n" 2>/dev/null)
  echo "Using $cpus CPUs"

  # Remove previous stuff:
  echo "Removing previous install folder $idir..."
  rm -Rf "$idir"

  echo "Removing previous build folder $bdir..."
  rm -Rf "$bdir"

  echo "Extracting source archive $srcfile"
  mkdir -p "$bdir"
  cd "$bdir"
  7za x "${sdir}/${srcfile}.7z" 

  # Setup the directories:
  local srcdir="$bdir/src"
  cd "$srcdir"

  # Build the binutils:
  nv_std_build $__binutils "--host=$host --target=$tgt --prefix=$idir --with-sysroot=$idir --disable-shared --enable-static --disable-multilib --disable-nls" || { echo "=> Error in binutils build"; return 1; }

  # We should ensure here our path contains our new compiler location:
  # (this is the case for me so I don't need this)
  # if [[ `echo $PATH | grep $idir/bin` == "" ]]; then
  # 	echo "Adding new compiler location to path: $idir/bin"
  # 	export PATH="$idir/bin:$PATH"
  # fi

  # Install the headers:
  nv_std_build $__headers "--host=$tgt --build=$host --prefix=$idir/$tgt --enable-secure-api" || { echo "=> Error in mingw64 headers build"; return 1; }

  # Create the symlinks:
  cd $idir
  ln -s $tgt mingw

  cd "$srcdir"

  # Move dependencies into GCC folder:
  mv $__gmp $__gcc/gmp
  mv $__mpfr $__gcc/mpfr
  mv $__mpc $__gcc/mpc
  mv $__isl $__gcc/isl

  # Check if we can build gcc completely:
  local gccstage="gcc"
  if [ "$flavor" == "win" ]; then
    local cdir="$compdir/linux-mingw${arch}"
    export CFLAGS="-I$cdir/include -L$cdir/lib"
    gccstage="" # Build gcc completely in one step.

  # Build GCC, pass 1
  nv_std_build $__gcc "--host=$host --target=$tgt --prefix=$idir --enable-languages=c,c++ --disable-multilib --disable-shared --enable-static --disable-nls --enable-threads=posix --enable-sjlj-exceptions --enable-fully-dynamic-string" "$gccstage" || { echo "=> Error in gcc build"; return 1; }

  # Reset the CFLAGS
  export CFLAGS=""

  if [ "$flavor" == "win" ]; then
    # We should be done building gcc, and we can retrieve the CRT previously compiled with the cross compiler:
    local cdir="$compdir/linux-mingw${arch}"
    mkdir -p $idir/$tgt/lib/
    cp $cdir/$tgt/lib/* $idir/$tgt/lib/
    # Build the crt
    nv_std_build $__crt "--host=$tgt --build=$build --prefix=$idir/$tgt --with-sysroot=$idir/$tgt" || { echo "=> Error in mingw64 CRT build"; return 1; }

  # Build the winpthread library:
  cd "$srcdir"
  nv_std_build $__pthreads "--host=$tgt --build=$build --prefix=$idir/$tgt --with-sysroot=$idir/$tgt --disable-shared --enable-static" || { echo "=> Error in mingw64 winpthreads build"; return 1; }

  if [ "$flavor" != "win" ]; then
    # Finish building GCC:
    cd "$srcdir/$__gcc/build"
    make || { echo "Building gcc pass 2 FAILED."; return 1; }
    make install || { echo "Installing gcc pass 2 FAILED."; return 1; }
    cd ..
    rm -Rf build

  # Go into the compiler folder and remove the build folder:
  cd "$sdir"
  rm -Rf "$bdir"

  echo "=> Compiler build SUCCESSFUL."

  # nv_build_mingw_compiler "64"
  nv_build_mingw_compiler "64" "linux"

  # nv_build_mingw_compiler "32"
  nv_build_mingw_compiler "32" "linux"

  nv_build_mingw_compiler "64" "win"

  nv_build_mingw_compiler "32" "win"

In the script above I use my custom mingw64_sources.7z package: this is simply a zip of an src folder, containing all the libraries at the expected version (cf. the script itself) which I created after manually downloading/extracting the library official packages to ensure I always have a copy of those packages, and I can extract everything I need quickly without redownloading [you know, just in case one day the Internet would go completely down (… as if our main problem in that case would be to have a copy of the gcc sources ;-)…)]
  • blog/2017/0924_build_native_mingw64_compiler.txt
  • Last modified: 2021/09/02 13:38
  • by manu