Compile for Windows on Linux


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.

Cross-World Hello

  1. Go to the MinGW-w64 download page. We need two toolchains – one for targeting win32 and another for targeting win64.Open “Toolchains targetting Win32” , followed by “Automated Builds”, “mingw-builds” and a recent version (e.g. mingw-w64-bin_x86_64-linux_20131228.tar.bz2).

    Now do the same for “Toolchains targetting Win64” (e.g. mingw-w64-bin_x86_64-linux_20131228.tar.bz2).

    There are some notes on the package naming convention below to help you pick the right one. Also note that the direct links above might be to older versions when you read this — so please check the directory structure for updates.

  2. Unpack the first archive to /opt/mingw32 and the second to /opt/mingw64.
  3. 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;
  4. 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
  5. 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 binaries 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.

This entry was posted in GCC Windows and tagged , , , , , , , , , . Bookmark the permalink.

47 Responses to Compile for Windows on Linux

  1. Pingback: gcc for Windows | Techblog

  2. Pingback: OpenSSL for Windows | BlogCompiler

  3. Divine says:

    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.
    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.

  4. Divine says:

    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.
    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.

    • author says:


      Are you using a 64-bit Linux distribution?
      You can check this with

      $ uname -m

      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

      Also see the Package Naming Conventions above, especially the HOST part of it.

      Hope this helps!

  5. Keinstein says:


    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.

  6. Anu says:

    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.


    • author says:

      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:

      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.

    • author says:


      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:


  7. Anu says:


    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!

  8. Jon says:

    /opt/W32_180676/bin/../libexec/gcc/i686-w64-mingw32/4.5.4/cc1: error while loading shared libraries: cannot open shared object file: No such file or directory

    I only find a in my system.

    • Jon says:

      Sorry for wasting your time. I `ldd’ and ‘ln’ until I got all libraries needed by the MinGW-64 gcc.

      • author says:

        No worries Jon, glad that you got it working!

      • guy says:

        I have the same issue, can you detail how you resolved this? Thanks.

        • guy says:

          where did you create the symbolic links to?

          • Guy says:

            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/ /usr/lib/x86_64-linux-gnu/
            ln -s /usr/lib/x86_64-linux-gnu/ /usr/lib/x86_64-linux-gnu/

  9. Mike C says:

    “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.

    • author says:

      Hi Mike,

      Thanks for pointing this out. My observation was that a mingw compilation run on Linux was several times faster than if you ran it on Windows.
      This was done on Windows XP, and I have indeed not tested the newer Windows versions.
      I will adjust the claim to limit it to mingw. I think you would agree then?

    • bob says:

      Ubuntu is smaller (10+ GB) thus it WILL run faster.

      Also, Linux is a MUCH more stable and better overall kernel

  10. Pingback: Working on Linux to compile for Windows

  11. Zee says:

    As far as I use simple hello world c program it works perfectly fine and generates a proper exe file for Windows 64 bit.But when I use some code which requires lib and include files to be added in the command then it generated the following error.
    If I use simple gcc command this works perfectly fine.
    Command Executed.
    myroot@ubuntu:/home/mysystem/Desktop# /opt/mingw64/bin/x86_64-w64-mingw32-gcc /home/mysystem/Desktop/hello.c -I /home/mysystem/Desktop/oracle/include/ -L /opt/Db//lib/ -L /opt/Db/9/lib -ldld -o /home/zainabmasood/mystem/testme.exe
    Error :(
    /opt/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.5.4/../../../../x86_64-w64-mingw32/bin/ld: cannot find -ldld
    collect2: ld returned 1 exit status
    Need Help Plz.

    • Spork Schivago says:

      I know this is an old post but I thought I would reply in case someone else has similar issues. I don’t know if this is the solution to your problem or not, however, when I compile, I don’t put a space between -L and -I I have something like gcc -L/home/spork/src/project1/lib -I/home/spork/src/project1/include main.c -o main

      If removing the spaces after the -L’s and the -I’s don’t help, try putting all the options before the source code and -o you know, something like:

      /opt/mingw64/bin/x86_64-w64-mingw32-gcc -I/home/mysystem/Desktop/oracle/include/ -L/opt/Db//lib/ -L/opt/Db/9/lib -ldld /home/mysystem/Desktop/hello.c -o /home/zainabmasood/mystem/testme.exe

      The error message implies that it cannot find the library libdld. Are you sure it’s in the /opt/Db/9/lib or the /opt/Db/lib directory? If so, perhaps the spaces where the problem after all.

  12. Chris says:

    Thanks for this, I’ve got a simple foo.c compiling to foo.exe and running on windows.

    How would you go about compiling a windows executable that will depend on a library (libSDL2 in my case)?

    If I try:
    /opt/mingw64/bin/x86_64-w64-mingw32-gcc foo.c -o win64/foo.exe -lSDL2
    I get:
    foo.c:2:22: fatal error: SDL2/SDL.h: No such file or directory

    The linux version works (and runs):
    gcc foo.c -o linux64/foo -lSDL2

    Do I need to get the headers from a (pre-compiled) windows version of the library?

    Where should I put said headers? (i.e. where does /opt/mingw64/bin/x86_64-w64-mingw32-gcc look for headers, because it’s not getting the linux SDL2/SDL.h (which probably wouldn’t work anyway).)

    Can you compile a windows executable on linux without the windows DLL libraries being present on the linux box?

  13. Vinay says:


    Nice information. Can you please provide the same for running a windows executable on linux platform?
    I have some code snippets, that runs on windows. But i want to run the same code on Linux. Please let me know how to do it.

    Thanks in advance,

    • author says:

      Hi Vinay,

      If I understand you correctly, you want to compile the executable on Windows and run it on Linux? There are generally two ways:

      * Compile it as a Windows .exe (e.g. with Visual Studio) and run it on Linux under Wine – please see the section about Wine above

      * Compile it as a Linux executable on Windows and run it natively on Linux. I do not have much experience with this, but you can create a Linux build environment on Windows with cygwin.

      Hope that helps.

  14. Vinay says:

    Thanks For your reply.
    Yes, I want to run a windows binary file on Ubuntu(Linux). But Wine software is having too many bugs, I tried it. But it was not successful. Any other options to compile windows binary on linux?

    • author says:


      Unfortunately, there is no great solution for running Windows binaries on Linux. They are inherently very different OSes. Wine is the most popular and likely your best bet for this.

      What you need to do to get a “proper” version is to port your project so that it support Linux as well as Windows. But this might be a bit of work for you, depending on the size of your project.

      There are lots of APIs that are different from Windows and Linux (e.g. ZeroMemory(), fork(), ..). You would have to track down all of those and find the corresponding API for Linux.

  15. Pingback: Ubuntu-Server + VirtualBox Notes | tfw

  16. David says:

    I was wondering if you ever tried to cross compile the openssl-fips module? I have been attempting it doing the same thing you are doing for openssl, but I cant seem to get it to compile with Mingw. Do you have any idea on how I might do this? Or maybe the environmental variables I need to setup to do it correctly? After hours of research I still seem unable to find what the environmental variables are supposed to be set to correctly.

    Either way I wanted to comment and say thank you for the blog it has been helpful.

    • author says:

      Hi David,

      Unfortunately I have not tried to cross-compile compile the Fips module. Perhaps some of the other readers have?

      I am glad you found the blog helpful, and good luck resolving this!

  17. Spork Schivago says:

    Hi, this is such a great article. However, is the information still correct? I notice if I follow the directions, going into the Home / Toolchains targetting Win32 / Automated Builds directory, the latest build is from 2013-12-27. If, however, I go into Home / Toolchains targetting Win32 / Personal Builds / mingw-builds, we get builds from 2015-08-04. Ver 5.2.0, 5.1.0, 4.9.3, etc. Should we still be using the Automated Builds? It seems they haven’t been updated in a quite some time. What’s the difference? Thanks again for writing such a great article by the way!

    • author says:

      Hi Spork,

      I’m glad you found the post useful!

      You are indeed correct that the builds are getting a little old, even though I try to update the links. Like you, I am also a bit confused by the directory structure (partly why I wrote this article to explain it).

      I have been in touch with a maintainer of mingw-w64 and he recommended to get distribution-specific packages at

      Perhaps you have more success with that? If so, please let me know and I’ll look to update the article using those.

  18. Pingback: Help picking a good Windows compiler that supports Linux code.

  19. Pingback: Unix/Linux:Compile Linux Application for Windows – Unix Questions

  20. Lucas says:

    Hi there! How are you?
    I’m trying to compile the latest version of BCI2000. This is a software to make brain computer interfaces, is and open source code for students.

    But considering that linux is by far better than windows, I want to compile the last version on my lunix distribution (ubuntu gnome 15.04), and make the .exe on my linux.

    My questions is, it is possible generate the .exe using the mingw32 or mingw64?
    The BCI2000 software, has a lot of .cpp and .cmake files in order to build the complete distribution, it is possible compile all this files like a “project”?
    Here a quick guide how compile in windows or linux.

    Thank so much!

    Best regards from Argentina!


  21. assayyed says:

    thanks for you i installed all the tools but when compiling i see this errors:
    assayyed@assayyed-VirtualBox:~/test4$ /opt/mingw64/bin/x86_64-w64-mingw32-gcc mkbootimg.c -o test2.exe
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xa7f): undefined reference to `SHA_init’
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xa9a): undefined reference to `SHA_update’
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xab4): undefined reference to `SHA_update’
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xacf): undefined reference to `SHA_update’
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xae9): undefined reference to `SHA_update’
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xb04): undefined reference to `SHA_update’
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xb1e): more undefined references to `SHA_update’ follow
    /tmp/ccMWIkgk.o:mkbootimg.c:(.text+0xb69): undefined reference to `SHA_final’
    /opt/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.9.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/ccMWIkgk.o: bad reloc address 0x0 in section `.pdata’
    collect2: error: ld returned 1 exit status

    • author says:


      It seems like you are trying to compile an application that depends on libraries that you either have not installed or do not tell the compiler/linker about.

      In particular, you need the OpenSSL library installed to resolve these specific issues. I have a post on that here:

      After installing the OpenSSL library, try to run this command to compile:

      /opt/mingw64/bin/x86_64-w64-mingw32-gcc -I/opt/mingw64/include -L/opt/mingw64/lib -Wall mkbootimg.c -lcrypto -o test2.exe

  22. Garry says:

    Just for you to know, there’s a nice project to build mingw toolchain (and a bunch of libraries):

    It’s up-to-date and distribution agnostic (also works on BSD, and iOS…).

    The only problem I’m struggling with is to build a linux hosted gdb for the mingw target, but it should be just a matter of a few tweaks and tricks to succeed.


  23. Tim says:

    I have a autotools project with tests written in C in the tests/ directory.
    With mingw cross compiling on Linux, I have a bunch of tests/*.exe, but ‘make check’ can’t execute them. This needs binfmt support which is (of course) disabled for security reasons.
    How can I convince ‘make check’ to start the tests with wine ? Any idea ?

  24. Francois Baret says:

    I compiled your example on Ubuntu 15.10 and I got an exe which works fine on Windows 8. Now, I would like to do the same with an application I wrote using a framework for streaming media called GStreamer. For Linux I compile it with the following:
    gcc -Wall helloworld.c -o helloworld $(pkg-config –cflags –libs gstreamer-1.0),
    If I try to compile the same c file with your:
    /opt/mingw32/bin/i686-w64-mingw32-gcc /tmp/helloworld.c -o /tmp/helloworld-w32.exe
    I get the following error:
    fatal error: glib.h: No such file or directory
    If instead I use:
    /opt/mingw32/bin/i686-w64-mingw32-gcc -Wall /tmp/receiver.c -o /tmp/receiver-w32.exe $(pkg-config –cflags –libs gstreamer-1.0)
    I get an other error:
    fatal error: pthread.h: No such file or directory
    Do you have any idea how I can get my way out of this?
    Thanks and regards!

  25. Pingback: 5 Reasons Why Linux OS Is A Hot Favorite Among Coders - Dunia IT

  26. Pingback: When "ASLR" Is Not Really ASLR - The Case of Incorrect Assumptions and Bad Defaults

  27. Pingback: When “ASLR” Is Not Really ASLR – The Case of Incorrect Assumptions and Bad Defaults – TerabitWeb Blog

Leave a Reply to assayyed Cancel reply

Your email address will not be published. Required fields are marked *

2 + one =