Introduction
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, especially on process management. Compiling larger projects often involves starting processes to e.g. search through and modify text files, check for headers and run the compiler binaries themselves. Also, Linux does not need anti-virus scanners to intervene the operations of the compilation process.
- 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.
Cross-World Hello
- 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_20110510″, and pick “mingw-w32-bin_x86_64-linux_20110510_sezero.tar.gz” and “mingw-w64-bin_x86_64-linux_20110510_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
#include <stdio.h>
int main()
{
printf(“Hello World!\n”);
return 0;
} - Compile it for both 32- and 64-bit Windows with the following commands.
/opt/mingw32/bin/i686-w64-mingw32-gcc /tmp/hello.c -o /tmp/hello-w32.exe
/opt/mingw64/bin/x86_64-w64-mingw32-gcc /tmp/hello.c -o /tmp/hello-w64.exe
- 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.
mingw-TARGET-bin_HOST_DATE.PKG
- 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.
Pingback: gcc for Windows | Techblog
Pingback: OpenSSL for Windows | BlogCompiler
I downloaded the package mingw-w32-bin_x86_64-linux_20110510_sezero.tar.gz
and with the help of the following commands, i extrated and install the package.
commands
1.su
2.tar xvfz mingw-w32-bin_x86_64-linux_20110510_sezero.tar.gz -C /opt
I further wrote a temporal c program saved to /tmp/hello.c
On trying to compile using the command below,
/opt/mingw32/bin/i686-w64-mingw32-gcc /tmp/hello.c -o /tmp/hello-w32.exe
I get report that binary file cannot be excuted.When I try to remove bin from the path ,the report is no such file or directory.
Please help me.
I downloaded the package mingw-w32-bin_x86_64-linux_20110510_sezero.tar.gz
and with the help of the following commands, i extrated and install the package.
A:commands
1.su
2.tar xvfz mingw-w32-bin_x86_64-linux_20110510_sezero.tar.gz -C /opt
I further wrote a temporal c program saved to /tmp/hello.c
On trying to compile using the command below,
/opt/mingw32/bin/i686-w64-mingw32-gcc /tmp/hello.c -o /tmp/hello-w32.exe
I get the report that binary file cannot be excuted.When I try to remove bin from the path ,the report is no such file or directory.
Please any help will be greatly appreciated.
Hi,
Are you using a 64-bit Linux distribution?
You can check this with
$ uname -m
x86_64
The above would indicate a 64-bit distribution, which is required for running the gcc command I linked directly to. If you are on a 32-bit distribution, please try packages that have “i686-linux” instead of “x86_64-linux” in the middle of their name.
For example, try
mingw-w32-bin_i686-linux_20110510_sezero.tar.gz.
Also see the Package Naming Conventions above, especially the HOST part of it.
Hope this helps!
Hi,
if you have an apropriate windows installation and binfmt support installed you can configure any autoconf based project to use mingw if you add the following two parameters to configure:
–host=i686-w64-mingw32 –build=i686-w64-mingw32
for 64bit use x86_64-w64-mingw32. Thus you can convince configure that you are not on linux. It will fail if you don’t set up binfmt support (on debian just install wine and binfmt-support) as it concludes that the executables are broken if they cannot be run.
Keinstein,
Thanks for the insight!
Hi,
compiler works great! But these packages don’t contain an rc compiler, which is available in standard MinGW. Any help on how to get an rc compiler to work would be greatly appreciated.
TIA
Hi Anu,
I have just used the rc compiler to generate event-logging dll’s. I then used the mc and rc compilers from Windows SDK and link from Visual Studio (natively from Windows). The event definitions almost never change, so this worked quite well for me.
What I did was this:
mc myevents.mc
rc myevents.rc
link -dll -noentry myevents.res /MACHINE:X86 # or X64
This was probably not an answer to your question, but perhaps it helped a bit.
Anu,
Did you try the windres command (e.g. /opt/mingw64/bin/x86_64-w64-mingw32-windres)?
This seems to be doing what you are looking for. It is described briefly on the “standard” MinGW web pages: http://www.mingw.org/wiki/MS_resource_compiler
Thanks.
Hi,
I tried to build a rubenvb 4.6.3-1 on Linux. First, the linker said:
ld: unrecognised emulation mode: i386pe
when trying to link the g++ binary. I found that it gets the idea to use a Windows mode from the gcc/gcc/specs file which is created from the newly built xgcc. So i removed ${SPECS} target from the makefile. Now it links nicely, but when I try to run the resulting binaries, I get:
$ i686-w64-mingw32-g++ --version
i686-w64-mingw32-g++: fatal error: switch 'no' does not start with '-'
compilation terminated.
The compiler I am using is gcc-4.6.3 and binutils 2.22. GnuMake is 3.81. System is x86_64 GNU/Linux.
Any idea? Many thanks in advance!
/opt/W32_180676/bin/../libexec/gcc/i686-w64-mingw32/4.5.4/cc1: error while loading shared libraries: libmpfr.so.1: cannot open shared object file: No such file or directory
I only find a libmpfr.so.4 in my system.
Sorry for wasting your time. I `ldd’ and ‘ln’ until I got all libraries needed by the MinGW-64 gcc.
No worries Jon, glad that you got it working!
I have the same issue, can you detail how you resolved this? Thanks.
where did you create the symbolic links to?
The toolchains expect to find these libraries in their paths:
gmp library
mpfr library
mpc library
I only got complaints about the first 2 missing on Ubuntu 12.04.
Ubuntu happens to have later major versions installed, symbolically link the mismatched library versions
and hope for library API backwards compatibility. Otherwise you’ll have to install the exact versions (use ldd on the binary to find the dependency version as suggested).
i.e. linking these versions has worked for me:
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
“Linux is generally faster than Windows”
Uh, not really. This may be true for very old Windows versions. Modern versions of the Windows kernel are extremely fast. One can be somewhat faster than the other sometimes depending on the hardware in the machine running, but generally speaking there will not be any substantial performance discrepancies. You should set up a test machine with Windows 7 and Linux dual boot, and compile something on both to benchmark the performance, and you will see that it’s about the same speed.