Cross-compiling QtWebKit for Windows on Linux using MinGW

The first question which might arise when reading the title:
Why would you want to do that?

The answer is simple

Consider a situation where you have a build farm consisting of high performance Linux servers and you have to build QtWebKit for Windows. Of course you can use virtual machines, but you'll waste energy, time and precious resources of your build farm. Besides that, you can't use tools like distcc for example, to speed up things. So if these issues matter to you, cross-compiling with MinGW is the solution.

I assume you have all the basic development tools installed on your Linux machine (meta-packages may be called build-essential or base-devel, depending on your distribution).

Prerequisites

I had some issues with the newer version of the MinGW GCC compiler, that's why I compiled 4.4.0.
We need the following MinGW packages:

Additionally we need to compile zlib with the MinGW toolchain (zlib-1.2.5.tar.gz).

I'll give you a detailed how-to explaining the steps of preparing the toolchain.

Building the cross-compiler toolchain

First, we need a compiler which can produce exe files but runs on Linux, so we have to compile mingw-gcc with the system compiler. I used GCC 4.5.0 to compile the toolchain, but all this should work with other versions too.

As first configure, build and install binutils (binutils-2.20.1-src.tar.gz):

$ ./configure \
    --target=i486-mingw32 \
    --prefix=/usr \
    --disable-nls \
    --enable-shared
[...]
$ make -j24
[...]
$ make install

Extract gcc-4.4.0-src.tar.bz2 and create a directory called build into the extracted tree. We need a C and a C++ compiler so use the following commands to configure mingw-gcc.

$ mkdir build && cd build
$ unset CFLAGS CXXFLAGS
$ ../configure --enable-languages=c,c++ \
             --target=i486-mingw32 \
             --disable-sjlj-exceptions \
             --enable-shared \
             --with-dwarf2 \
             --disable-win32-registry \
             --enable-version-specific-runtime-libs \
             --prefix=/usr

Now you need to set your PATH to contain the new toolchain.
If the configuration succeeds, you are ready to build, if not your system probably misses some development libraries. After a successful build you can install the compiler.

$ make -j24
[...]
$ make install

Next is the MinGW runtime (mingwrt-3.18-mingw32-src.tar.gz), which is a bit tricky. After extraction we need to change the line endings to Unix and set the correct include path:

$ sed -i "s%\r%%g" `find . -type f`
$ sed -i -e "s%^W32API_INCLUDE=.*%W32API_INCLUDE=-I/usr/i486-mingw32/include%" \ 
  `find -type f -name 'configure'`

Then export the -mms-bitfields flag which is essential because we want our application to actually run on win32:

$ export CFLAGS="-mms-bitfields"

Configure, then make and make install as usual:

$ ./configure \
    --prefix=/usr/i486-mingw32 \
    --target=i486-mingw32 \
    --host=i486-mingw32
[...]
$ make -j24
[...]
$ make install

Now comes the win32 API (w32api-3.14-mingw32-src.tar.gz):

$ export CFLAGS="-mms-bitfields"
$ ./configure \
    --prefix=/usr/i486-mingw32 \
    --target=i486-mingw32 \
    --host=i486-mingw32
[...]
$ make -j24
[...]
$ make install

And as last prerequisite we build a static zlib using the MinGW toolchain:

$ ./configure --static
[...]
$ make MKDIR="mkdir -p" \
     ASM=i486-mingw32-as \
     CP=install \
     RM=rm \
     MKLIB="i486-mingw32-ar r" \
     CC=i486-mingw32-gcc \
     RANLIB=i486-mingw32-ranlib \
     AR="i486-mingw32-ar r" \
     LD="i486-mingw32-ld"
[...]
$ make install

After that we have all the needed tools and libs we need to cross-compile the Qt framework and then QtWebKit.

Building the Qt framework

Because Qt is a cross-paltform framework you would expect cross-compiling to be fairly straightforward. Nonetheless I experienced some issues using the current stable release (4.6.3), which didn't allow me to cross compile Qt, so finally I tried to build it from the git repository (qt.gitorious.org/qt/qt) and succeeded without major issues, which indicates that the Qt guys are doing a good job in Oslo.

First, clone the Qt repository from Gitorious:

$ git clone git://gitorious.org/qt/qt.git

The main changes you need to apply to the Qt source tree are needed because of the custom MinGW compiler. Beneath you can find the patches and configuration file attached.

To make things easier I use the following script to automate the process. (Let's call this build.sh.)

#!/bin/bash

find . -name '.gitignore'|xargs rm
git clean -xdf
git reset --hard a98bda4b42b068c9c3220ae2aded41a263387ac2

test -f ../buildfix.diff \
   && git apply ../buildfix.diff \
   && test -f ../crossqt_patch.diff \
   && git apply ../crossqt_patch.diff \
   && test -f ../crossqt_config.txt \
   && echo yes|./configure $(cat ../crossqt_config.txt) \
   && make -j24

You can also use this if you want to make a clean build. It will clean up the repository, check out the revision which I built, apply the patches, configure and build Qt.

The configuration I used was (crossqt_config.txt):

-xplatform win32-g++

-no-phonon
-nomake examples
-nomake demos
-nomake docs
-make tools
-no-exceptions
-no-webkit
-opensource
-no-qt3support
-little-endian
-host-little-endian

-prefix /usr/local/Trolltech/mingw-cross-qt-4.7

Feel free to adjust these to your needs.

The crossqt_patch.diff patch changes the following files:

mkspecs/features/debug_and_release.prf
mkspecs/win32-g++/qmake.conf

These changes are needed, so that qmake uses the MinGW toolchain and correctly creates dll files.

The other patch (buildfix_patch.diff) is only needed if you want to use the build.sh script, it applies some changes which fix the build of the revision I succeeded with.

If you use the script, building Qt is really simple (given that you downloaded the patches and the configuration file from below).

$ cd qt
$ sh ../build.sh

That's all, you just have to install it afterwards.

Before building QtWebKit, you have to copy the qmake binary to the install directory, because - for some reason - make install doesn't do that.

$ make install
[...]
$ cp bin/qmake /usr/local/Trolltech/mingw-cross-qt-4.7/bin

Building QtWebKit

At this point you have everything you need to cross-compile the Qt port of WebKit, since the only change needed to be able to do that has already landed in the trunk (Changeset 63203).
First, set the needed environment variables:

$ export QTDIR=/usr/local/Trolltech/mingw-cross-qt-4.7
$ export PATH=$QTDIR/bin:$PATH

Clone the WebKit repository and build it:

$ git clone git://git.webkit.org/WebKit.git WebKit
$ cd WebKit
$ WebKitTools/Scripts/build-webkit --qt -spec win32-g++ --makeargs=-j24

Now copy the Qt and MinGW dll files next to the binaries:

$ cp /usr/local/Trolltech/mingw-cross-qt-4.7/lib/*.dll WebKitBuild/Release/bin/
$ cp /usr/lib/gcc/i486-mingw32/4.4.0/libgcc_s_dw2-1.dll WebKitBuild/Release/bin/
$ cp /usr/i486-mingw32/lib/mingwm10.dll WebKitBuild/Release/bin/

And finally, you are able to test the binaries on a Windows machine.

AttachmentSize
crossqt_config.txt227 bytes
buildfix_patch.diff3.2 KB
crossqt_patch.diff3.19 KB

İsmail Dönmez (not verified) - 07/25/2010 - 20:54

Neato!

Lothar (not verified) - 10/19/2010 - 10:51

I tried to cross compile Qt 4.7 (official release) but it failed. When using some older gcc, it fails because of some include order issue which is fixed in a more recent gcc. When using latest mingw-w64 cross compiler, then mmx stuff fails and if this is disabled, some things which are only for Linux are suddenly compiled.

Is cross compiling Qt for Windows no longer possible? Did you try with the official version? It seems that your buildbot actually uses Windows systems at the moment.

andras.becsi - 10/19/2010 - 12:49

Hi, Lothar,

I just finished to build the official Qt-4.7.0 release with 32bit mingw-gcc-4.5.0 and to cross-compile a correctly working QtWebKit (with previous git versions we experienced a jpeg plugin issue). We plan to substitute our Windows virtual machine bots with the cross buildbots this week (new bots can currently be found here).

To answer your question: We did not try to build Qt with 64bit mingw, so maybe your issues are related to that. However previously I also experienced the include order issue, you mentioned, with 32bit mingw which I fixed by substituting the two float.h headers, back then. Also, we have no plans to try the 64bit mingw in the near future.

If I manage to get some spare time I'll update this blog post with more recent information.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • No HTML tags allowed
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Fill in the blank