In an earlier post, we saw how to obtain gcc on windows, using the MinGW-w64 suite. However, users familiar to gcc are often using one of the operating systems of the Unix family, such as Linux. As amazing as it may first seem, the MinGW-w64 project allows users to compile native Windows binaries on Linux. This concept of targeting a different platform than the compiler is running on is however not new, and is known as cross-compilation.
Cross-compiling Windows binaries on Linux may have many benefits to it.
- Increased compilation speed. Linux is generally faster than Windows with the mingw toolchain.
- Reduced operating system complexity. On cross-platform projects that are also built on Linux, we can get one less operating system to maintain.
- Access to Unix build tools. Build tools such as make, autoconf, automake and Unix utilities as grep, sed, and cat, to mention a few, become available for use in Windows builds as well. Even though projects such as MSYS port a few of these utilities to Windows, the performance is generally lower, and the versions are older and less supported than the native Unix counterparts. Also, if you already have a build environment set up under Linux, you don’t have to set it up again on Windows, but just use the existing one.
- Lower license costs. As we know, Windows costs in terms of license fees. Building on Linux, developers do not need to have a Windows installation on their machines, but maybe just a central Windows installation for testing purposes.
How It Works
On a Linux build environment, a gcc that compiles native binaries is usually installed in “/usr/bin”. Native headers and libraries are in turn found in “/usr/include” and “/usr/lib”, respectively. We can see that all these directories are rooted in “/usr”.
Any number of cross-compiler environments can be installed on the same system, as long as they are rooted in different directories. In our example, we will use “/opt/mingw32″ and “/opt/mingw64″ as root directories for the new build environments. Now, we would perhaps expect to find “/opt/mingw32/bin/gcc” and “/opt/mingw64/bin/gcc”, but we instead see “/opt/mingw32/bin/i686-w64-mingw32-gcc” and “/opt/mingw64/bin/x86_64-w64-mingw32-gcc”. The reason for this is that we (and configure scripts) should be able to pick the “right” gcc, even if we have multiple compilers in the PATH environment variable. If they were all named gcc, cross-compiling would easily become messy.
- Go to the MinGW-w64 download page. We need two toolchains – one for targeting win32 and another for targeting win64. New packages are frequently uploaded, but we just pick the newest personal build (I had some bad experiences with the automated builds). Open “Toolchains targetting Win32″ and “Toolchains targetting Win64″, followed by “Personal Builds”. At the time of writing, we can open for example “sezero_4.5_20111101″, and pick mingw-w32-bin_x86_64-linux_20111101_sezero.tar.gz and mingw-w64-bin_x86_64-linux_20111101_sezero.tar.gz to compile from a 64-bit Linux distribution. There are some notes on the package naming convention below to help you pick the right one.
- Unpack the first archive to /opt/mingw32 and the second to /opt/mingw64.
- In a text editor (e.g. gedit or nano), paste in the little greeting-code and save it to /tmp/hello.c
- Compile it for both 32- and 64-bit Windows with the following commands.
/opt/mingw32/cross_win32/bin/i686-w64-mingw32-gcc /tmp/hello.c -o /tmp/hello-w32.exe /opt/mingw64/cross_win64/bin/x86_64-w64-mingw32-gcc /tmp/hello.c -o /tmp/hello-w64.exe
If you get errors loading shared libraries like “libmpfr.so.1″, you probably have newer versions of those libraries and you might want to softlink them to the older version, e.g.
ln -s /usr/lib/x86_64-linux-gnu/libmpfr.so.4 /usr/lib/x86_64-linux-gnu/libmpfr.so.1 ln -s /usr/lib/x86_64-linux-gnu/libgmp.so.10 /usr/lib/x86_64-linux-gnu/libgmp.so.3
Thanks to Jon and Guy for pointing this out (see their comments below).
- Run “hello-w32.exe” on 32-bit Windows, and “hello-w64.exe” on 64-bit Windows.
In order to build useful applications, it is convenient to use existing libraries such as the OpenSSL library on Windows.
Package Naming Conventions
As we saw on the MinGW-w64 download page, there are a lot of available packages with only subtle and perhaps confusing name differences. The automatically built packages have the following generic naming pattern.
- TARGET states which platform we want the compiled binaries to run, and can be either “w32″ (32-bit Windows) or “w64″ (64-bit Windows).
- HOST gives the host system, that is, the system on which the compiler binaries themselves are run. Thus, we are cross-compiling if HOST is different from TARGET. If we have a Intel 32-bit Linux distribution, we can pick a HOST value of “i686-linux”, from a 64-bit Linux host we would choose “x86_64-linux”, and from 32-bit Windows we can choose “i686-mingw”.
- DATE is the date, in the form YYYYMMDD, when the automatic build was created.
- PKG is the compressed archive format, such as “zip”, “tar.bz2″ and such. Generally, zip archives contain binaries that run on Windows, all other archives contains binarie that run on Linux.
Running the Binaries
Using Wine, we can even test the binaries directly from Linux. However, this only works on 32-bit Windows binaries and is not perfect due to bugs and missing features in Wine itself. After downloading and installing Wine for our distribution, we can test our program above by running “wine hello-w32.exe”.
Note that 64-bit Windows can run 32-bit binaries due to an emulation layer called Windows 32-bit On Windows 64-bit, but native binaries are more efficient.