Saturday, June 18, 2011

Choosing gcc for building wxWidgets under Windows

There are a lot of possibilities for building wxWidgets under Windows using gcc. First of all, you can choose to use traditional makefile in build/msw/makefile.gcc. This binds you to using a MinGW version of the compiler in Windows command prompt (i.e. cmd.exe as hopefully nobody uses systems with command.com any more) as the makefiles use DOS/Windows style paths and commands. Second, you can use the traditional Unix configure-and-make approach. Then you have a subchoice between using MSYS which is a minimalistic environment developed by MinGW project or a full-blown Cygwin one. In the former case you would use MinGW compilers too, of course, and in the latter one the natural idea is to use Cygwin compilers. This however means that the generated programs would depend on Cygwin DLL and would require installing it for them to run. As this can be undesirable, there is also a possibility of using a MinGW cross-compiler from Cygwin environment which combines the advantages of being able to use Cygwin on the build machine while not requiring anything special for the deployment.

Let's summarize the choices in a concise list:
  1. Use makefiles: implies the use of MinGW compiler in DOS prompt.
  2. Use configure+make; then choose between
    1. Using MSYS and MinGW compiler
    2. Using Cygwin and Cygwin compiler
    3. Using Cygwin and MinGW cross-compiler

The choice (1a) is probably the simplest one if you want to install as few things as possible. However, it doesn't allow you to easily specify many compilation options (you need to edit setup.h file instead of just passing options to configure on command line) and, worse, it doesn't produce a wx-config script as part of the build -- and even if it did, there would be no way to use it without some kind of Unix-like shell.

Because of this, I always recommended using the second approach to building wxWidgets. Moreover, personally I've always favoured using Cygwin because I use zsh all day long anyhow. However traditionally you had to use Cygwin compiler which was the worst of the lot. Not only did it always lag a version or two (and sometimes more) behind the latest available MinGW one, but it also was significantly slower than MinGW version. And, of course, the binaries created by it depended on cygwin1.dll. Because of this, people fond of Cygwin (or, alternatively, not fond of many MSYS problems), also tried to use native MinGW compilers under Cygwin and this could be made to work but was so painful because you had to painstakingly ensure that both MinGW compiler and Cygwin tools could understand the paths you used (which basically meant that only relative paths could be really used as absolute paths take different forms for Windows-based MinGW compiler and Cygwin-based tools) that I could never wholeheartedly recommend it.

So I was very pleasantly surprised when I learnt that Cygwin now provides recent versions of MinGW cross-compiler or, rather, several of them. As Charles Wilson explains here, there is a cross-compiler for Win64 from MinGW64 project, another cross-compiler for Win32 from the same project and also a Win32 cross-compiler from "traditional" MinGW. Hence now you have yet another choice to make in case (2c).

Obviously, if you need to target Win64 the choice is easy to make, as there is only one of them. I recommend using MinGW64 version of Win32 cross-compiler as well for two reasons: first, it seems quite likely that you will need to target Win64 later even if you don't need it now, so why not use the same compiler that would allow you to build for Win64 later. And second, MinGW64 uses the so-called SJLJ exceptions which can propagate through the code not compiled with gcc, e.g. all Windows system DLLs. And in practice this is needed to be able to catch any exceptions thrown by your wxWidgets event handlers. So while DW2 exceptions used by MinGW version do have their advantages (in particular they are much more speed-efficient), SJLJ ones are preferable for wxWidgets GUI applications.

To summarize, my recommendation for building wxWidgets under Windows using gcc is now straightforward and unambiguous: use MinGW64 compiler under Cygwin. To be more precise, you need to install Cygwin (if you don't have it yet) and its mingw64-i686-gcc-g++ package (you shouldn't download this file directly though, use Cygwin setup program to install it with all its dependencies). Then you simply need to run wxWidgets configure with the following options:


$ /path/to/wx/configure --host=i686-w64-mingw32 --build=i686-pc-cygwin ...


and run make as usual. You can also use wx-config script and, in general, things are almost as nice as under Unix. Just don't forget to use i686-w64-mingw32-g++ compiler instead of plain g++ if you write it manually instead of using `wx-config --cxx` output.

Another good news is that the speed of the compiler seems to have improved dramatically since the bad old gcc3 days: building the entire wxWidgets takes less than 4 minutes here with make -j8 in default shared library build. Running configure itself is still painfully slow the first time but reasonably fast afterwards if you use -C option to cache the tests results.

Good luck building your applications using wxWidgets using Cygwin cross-compilers and thanks for Cygwin and MinGW(64) folks for making it faster and easier than ever!

15 comments:

Erwin said...

I've not found any reason to use gcc under Windows. I prefer Microsoft Visual Studio and like its debugger.

For the build system, I use either cmake or premake4 to build wxWidgets as a static library and my app. cmake is more widely used, but premake4 can generate projectfile that you can ship to others, and is Lua based.

Both cmake and premake4 can also generate makefiles, including MinGW/cygwin but I didn't try that myself.

smartmobili said...

When you talk about Mingw64 I think there is a mistake because from what I remember they have implemented SEH exceptions (native SEHexceptions used by Visual).

VZ said...

I don't think there is support for C++ exceptions using SEH in any version of MinGW, AFAIK there are only plans to do it. I'd be glad to be proved wrong, of course, as this is something that it would be really nice to have.

smartmobili said...

I think you are mistaken then because during a period I was regularly on mingw-w64 irc and I even provided some technical information about SEH to one main mingw-w64 contributor (K.Tietz). I will try to find you references

Anonymous said...

Hi, Thanks for posting this article. I spent ages struggling to find the right magic between MinGW/MSYS/Cygwin and this article finally put me on track.

However I'm wondering what hardware you used to achieve compile time of <4 minutes.

With an Intel Core2 Duo @ 2GHz, 4GB RAM, and SSD, the best I can do is ~16 minutes for a Cygwin build with make -j4 (I tried all of -j2 to -j8).

By contrast MinGW/MSYS takes ~11 minutes to build on the same machine.

Either you have a super fast machine there or I'm still doing something wrong:

$ time ../configure --host=i686-w64-mingw32 --build=i686-pc-cygwin
...
real 7m12.727s
user 6m59.782s
sys 4m56.239s

$ time make -j4
...
real 16m13.889s
user 27m21.066s
sys 9m17.848s

$ time make samples -j4
...
real 13m13.224s
user 15m30.581s
sys 3m27.320s

VZ said...

I do have a fast machine but far from the highest end (i7 860, 8GB of RAM) so I'm a bit surprised your numbers are so different. Have you looked at how much RAM does it take while compiling? My guess would be that 4GB is not enough for strongly parallel builds (I do use "make -j8").

Anonymous said...

Hi,

Not sure how to check process memory usage in Win XP, but the PF Usage in Windows task manager goes from ~1.1GB while idle, to ~1.3GB while make -j8 is running.

Also for the record the times quoted were for building wxWidgets v2.9.2 from SVN sources, using GCC 4.5.2.

You did not mention processor speed for your box. I also failed to mention that I'm running Win XP (I assume you have Windows 7) so in reality only 3GB physical RAM is available. Also I have the page file turned off, which may or may not be a factor.

Overall then the speed difference seems reasonable, given 32-bit with 3GB RAM vs. 64-bit with 8GB RAM. (?)

VZ said...

I'm surprised it consumes so little RAM while building, usually compilation is a memory hog.

As for i7 860, it runs at 2.8GHz (see http://ark.intel.com/products/41316), although it can turbo for more. And I do use 64 bit Windows 7, although I'd be again surprised if Windows 7 were markedly faster than XP for this. OTOH maybe we also use different versions of Cygwin (I use 1.7) and they might have optimized things since 1.5.

Richard Powell said...

Hi,
I just tried building for win7 on Cygwin using the config:
../configure --host=i686-w64-mingw32 --build=i686-pc-cygwin --with-msw --enable-debug --enable-debug_gdb --disable-shared

I built and ran one of the samples and found the system was missing:

libstdc++-6.dll is missing
libgcc_s_sjlj-1.dll is missing

It looks like these are from the minGW: http://rawtherapee.com/forum/viewtopic.php?p=11501. I found that by adding '-static-libgcc -static-libstdc++' I resolved that. But I had the '--disable-shared' option in the config. I wonder if this isn't enough...

VZ said...

Richard, I don't know which version of the compiler did you use but these DLLs are definitely included into it, no need to download anything else, the files are in $CYGWIN_ROOT/usr/i686-{w64,pc}-mingw32/sys-root/mingw/bin.

Also, if you use --disable-static with wxWidgets configure (which is the default anyhow) you just disable building static wxWidgets libraries, this doesn't change anything else.

Serhat Şevki Dinçer said...

On a recent Ubuntu/Debian Linux, you can install the package gcc-mingw32 and cross-compile wx for windoze..

tttony said...

I'm trying to configure wxWidgets 2.9.2 on Win 7 x64 with cygwin/i686-w64-mingw32 but the wxWidgets configure file does not detect that is for a AMD64 configuration:


../configure --host=i686-w64-mingw32 --build=i686-pc-cygwin --with-msw --disable-debug --enable-unicode --disable-universal --disable-monolithic --enable-gui --disable-shared --enable-exceptions --without-odbc --without-opengl --enable-xrc --enable-html --with-regex=builtin --enable-richtext --disable-mediactrl --disable-aui --enable-ribbon --enable-propgrid --enable-stc --enable-std_string --enable-std_iostreams --enable-stl --silent --enable-stc CXX='i686-w64-mingw32-g++.exe' CC='i686-w64-mingw32-gcc.exe' LD='i686-w64-mingw32-g++.exe'


The content of this file lib\wx\include\i686-w64-mingw32-msw-unicode-static-2.9\wx\msw\rcdefs.h is:


#ifndef _WX_RCDEFS_H
#define _WX_RCDEFS_H

#define WX_CPU_X86

#endif


As you can see wxWidgets is configured with WX_CPU_X86 intead of WX_CPU_AMD64

I teste compiling a app and is not 64bit native in the task manager says *32

tttony said...

Sorry my bad...

I was using: i686-w64-mingw32 and I must use x86_64-w64-mingw32 also you have to specify additional flags:

../configure CFLAGS=-m64 CPPFLAGS=-m64 LDFLAGS=-m64 --define WX_CPU_AMD64 --host=x86_64-w64-mingw32 --build=x86_64-pc-cygwin [YOUR_CONFIG_HERE] CXX='x86_64-w64-mingw32-g++.exe' CC='x86_64-w64-mingw32-gcc.exe' LD='x86_64-w64-mingw32-g++.exe'

The: CFLAGS=-m64 CPPFLAGS=-m64 LDFLAGS=-m64 --define WX_CPU_AMD64 is to tell to the compiler to compile the executable in 64bit architecture

Thanks.. and thanks to the wxWidgets IRC users

csh said...

Thanks for this very useful post.
Has anyone tried to build wxPython with MinGW64 on cygwin?

Anonymous said...

I'm trying to compile wx 2.8.12 with mingw-w64-i686 on debian unstable. According to http://predef.sf.net the macro __MINGW64__ is defined only on 64bit builds. Thus the compiler is not detected correctly and the build fails due to some wrong decitions in filefn.h.

The Compiler must be detected using
__MINGW64_VERSION_MAJOR or
__MINGW64_VERSION_MINOR.