Windows 32/64 cross GCC with C++11 threads support
5 Apr 2015
These instructions were tested on Debian 7.0 (Wheezy) on an amd64 system.
You will need the following packages:
For the following instructions, we'll assume that you have these packages collected somewhere in a directory of their own, which will also be the root build directory.
You need to choose an installation prefix, and make sure that that prefix is in your path. We'll use the environment variable
$MINGW to designate this installation prefix. Set it before starting, or substitute it by hand in the commands that follow. For example:
You'll also need to ensure that:
You have write access to
$MINGWfor installation purposes. If you're building as a regular user, it would be best to create the directory owned by that user, and then change ownership to root later.
You have the subdirectory
$MINGW/binin your path. Otherwise, some of the steps after building binutils will fail.
You have build dependencies that GCC normally requires.
Building the compiler
The first step is to build and install binutils:
tar xfj binutils-2.25.tar.bz2 mkdir binutils-build cd binutils-build ../binutils-2.25/configure \ --target=x86_64-w64-mingw32 \ --enable-targets=x86_64-w64-mingw32,i686-w64-mingw32 \ --prefix=$MINGW \ --with-sysroot=$MINGW make && make install cd ..
Double-check before proceeding that binutils is in your
Creating necessary symlinks
Before the next step, create the following directories and symbolic links in your installation prefix:
mkdir -p $MINGW/x86_64-w64-mingw32/lib32 ln -s x86_64-w64-mingw32 $MINGW/mingw ln -s lib $MINGW/mingw/lib64
Installing MinGW-w64 headers
Unpack, configure, and install MinGW-w64 headers for the Windows API and C runtime:
tar xfj mingw-w64-v4.0.1.tar.bz2 mkdir mingw-headers-build cd mingw-headers-build ../mingw-w64-v4.0.1/mingw-w64-headers/configure \ --prefix=$MINGW/x86_64-w64-mingw32 \ --host=x86_64-w64-mingw32 \ --build=$(gcc -dumpmachine) make install cd ..
Building the compiler
Next we unpack, configure and build GCC -- but only the core compiler. We can't build libgcc and the C++ library yet:
tar xfj gcc-4.9.2.tar.bz2 mkdir gcc-build cd gcc-build ../gcc-4.9.2/configure \ --target=x86_64-w64-mingw32 \ --enable-targets=all \ --prefix=$MINGW \ --with-sysroot=$MINGW \ --enable-threads=posix make all-gcc && make install-gcc cd ..
Building the C runtime
We've already unpacked the MinGW-w64 package. Now we use it to build and install the C runtime:
mkdir mingw-crt-build cd mingw-crt-build ../mingw-w64-v4.0.1/mingw-w64-crt/configure \ --prefix=$MINGW/x86_64-w64-mingw32 \ --with-sysroot=$MINGW \ --enable-lib32 \ --enable-lib64 \ --host=x86_64-w64-mingw32 \ --build=$(gcc -dumpmachine) make && make install cd ..
Building the winpthreads library
First, build and install a 64-bit version. We need to move the DLL after installation so that it's not clobbered by the 32-bit version later:
mkdir mingw-wpth-build64 cd mingw-wpth-build64 ../mingw-w64-v4.0.1/mingw-w64-libraries/winpthreads/configure \ --prefix=$MINGW/x86_64-w64-mingw32 \ --host=x86_64-w64-mingw32 \ --build=$(gcc -dumpmachine) make # At this point, the build will fail, due to the fact that we # enabled POSIX threads in the compiler, but libpthread.a doesn't # exist yet. Work around it and try again: cp fakelib/libgcc.a fakelib/libpthread.a make && make install # Move the created DLL mv $MINGW/x86_64-w64-mingw32/bin/libwinpthread-1.dll \ $MINGW/x86_64-w64-mingw32/lib64/ cd ..
Now build the 32-bit version. This is almost the same, except for the configure arguments and the final destination for the DLL:
mkdir mingw-wpth-build32 cd mingw-wpth-build32 ../mingw-w64-v4.0.1/mingw-w64-libraries/winpthreads/configure \ --prefix=$MINGW/x86_64-w64-mingw32 \ --host=x86_64-w64-mingw32 \ --build=$(gcc -dumpmachine) \ --libdir=$MINGW/x86_64-w64-mingw32/lib32 \ CC='x86_64-w64-mingw32-gcc -m32' \ CCAS='x86_64-w64-mingw32-gcc -m32' \ DLLTOOL='x86_64-w64-mingw32-dlltool -m i386' \ RC='x86_64-w64-mingw32-windres -F pe-i386' make cp fakelib/libgcc.a fakelib/libpthread.a make && make install mv $MINGW/x86_64-w64-mingw32/bin/libwinpthread-1.dll \ $MINGW/x86_64-w64-mingw32/lib32/ cd ..
Building the compiler runtime
Now, we can finish the GCC build:
cd gcc-build make && make install cd ..
This step takes quite a while, but after that, it's all done -- you should have a working Windows cross-compiler.
Building libraries with the cross-compiler (optional)
To avoid problems arising from a lack of package multilib support, I'd suggest using
$MINGW/local32 as installation prefixes for 64 and 32 bit libraries. In this section, I'll show how to compile two libraries for 32-bit Windows, in a way that minimizes distribution dependencies.
There's nothing special about the choice of these libraries in particular -- they're just two that I've happened to need so far.
Building libusb 1.0 is fairly straightforward, once configured correctly:
tar xfz libusb-1.0.19.tar.bz2 mkdir libusb-build32 cd libusb-build32 ../libusb-1.0.19/configure \ --prefix=$MINGW/local32 \ --host=x86_64-w64-mingw32 \ CC='x86_64-w64-mingw32-gcc -m32' \ DLLTOOL=true \ RC='x86_64-w64-mingw32-windres -F pe-i386'
We provide a dummy
DLLTOOL option because gcc already builds a functional import library. If you let libusb try to build its own, it doesn't work (you'll see warnings from gcc about skipping an incompatible libusb-1.0.dll.a if you try to link against it).
One minor annoyance if you're trying to build a minimize dependencies is that libtool builds shared libraries with shared dependencies. To enforce static dependencies for a library and avoid the need to distribute libgcc with your binary, edit
libusb/Makefile prior to the
make command, and edit the line that specifies
LDFLAGS = -Wc,-static
You can't specify these when giving the configure command, because they cause autoconf tests to fail. Specifying
-static on its own wouldn't cause the tests to fail, but libtool interprets this as an instruction not to build a shared library at all. Specifying
-Wc tells libtool to pass the flag to the compiler without trying to interpret it.
Build and install the library with:
make && make install cd ..
Note that you can use pkg-config to obtain the necessary compiler and linker flags for this (and many other) libraries when cross-compiling:
PKG_CONFIG_PATH=$MINGW/local32/lib/pkgconfig pkg-config --cflags libusb-1.0 pkg-config --libs libusb-1.0
wxWidgets for 32-bit is similarly straight-forward, although one minor fix-up is required after installation, as the libraries get installed with incorrect names:
tar xfj wxWidgets-3.0.2.tar.bz2 mkdir wxwidgets-build32 cd wxwidgets-build32 ../wxWidgets-3.0.2/configure \ --prefix=$MINGW/local32 \ --host=x86_64-w64-mingw32 \ --disable-shared \ CXX='x86_64-w64-mingw32-g++ -m32' \ CC='x86_64-w64-mingw32-gcc -m32' \ WINDRES='x86_64-w64-mingw32-windres -F pe-i386' make && make install # The library names don't match what wx-config reports. Fix this: for x in /opt/mingw64/local32/lib/libwx_*.a; do y=$(echo "$x" | sed 's/-x86_64-w64-mingw32.a$/.a/') mv "$x" "$y" done
Above, I've built a static library. Remove the
--disable-shared argument to configure if you want a shared library instead.
Notes on linking
If you want to minimize distribution dependencies, link with
-static. This will avoid the need to distribute the libgcc and winpthread DLLs with your binary.
If you're trying to build a mostly-static binary and want to link dynamically against one or two libraries (e.g. libusb, which has an LGPL license), link your binary as follows, wrapping the exceptional library flags with these
x86_64-w64-mingw32-g++ -m32 -static -o binfile.exe <dependencies> \ -Wl,-Bdynamic <dynamic dependencies> -Wl,-Bstatic
You can do this for any subset of libraries you want to link against.