Cross-compiling QtWebKit for Windows on Linux using MinGW
The first question which might arise when reading the title:
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).
I had some issues with the newer version of the MinGW GCC compiler, that's why I compiled 4.4.0.
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.
$ 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:
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
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).
$ 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.