Cross compiling
From qtnode
Cross Compiling Qt
ahigerd's steps to reproduce
These steps were performed on a Gentoo Linux machine, cross-compiling Qt 4.2.2, and are incomplete since I'm still working on it.
Download and extract the latest source for Qt4/Win. Here we'll refer to this path as $QTWIN. Also download and extract the source for Qt4/X11 because we'll need parts of it. Here we'll refer to this path as $QTX11. It's not a bad idea to actually export these as variables to the shell because you'll be using them a lot.
While the files are downloading, set up the cross-compiling environment:
- emerge qt (we need a native Linux Qt4)
- mkdir -p /usr/local/overlays/crossdev
- emerge crossdev
- crossdev mingw32
- Wait for toolchain to compile
Next, make a suitable makespec so we don't have to figure out how to bootstrap qmake:
- mkdir -p /usr/share/qt4/mkspecs/mingw32-g++
- Download MinGW qmake.conf and save as /usr/share/qt4/mkspecs/mingw32-g++/qmake.conf
- cp /usr/share/qt4/mkspecs/win32-g++/qplatformdefs.h /usr/share/qt4/mkspecs/mingw32-g++/
- Open qmake.conf in your favorite editor.
- Replace the blanks for QT_BUILD_TREE with $QTWIN.
- Replace the blanks for CROSS_PREFIX with your desired target installation path.
We can't run configure.exe but we need some files it creates, so...:
- cd $QTX11
- ./configure -fast -no-qdbus -prefix /usr/mingw32/usr/share/qt4 -bindir /usr/mingw32/usr/bin -libdir /usr/mingw32/usr/lib -headerdir /usr/mingw32/usr/include -qt-zlib
- Accept the GPL license agreement
- cp src/corelib/global/qconfig.* $QTWIN/src/corelib/global/
- cp include/QtCore/qconfig.h $QTWIN/include/QtCore/
- (Can someone give me a suitable build key from a real Windows configure.exe run?)
We don't need moc/uic/uic3/rcc because we have native versions of these and trying to build the .exe files is fruitless, and we don't need demos or examples either:
- cd $QTWIN
- rm -rf src/tools/moc/* src/tools/uic/* src/tools/uic3/* src/tools/rcc/* demos/* examples/*
- echo "TEMPLATE=subdirs" > src/tools/moc/moc.pro
- cp src/tools/moc/moc.pro src/tools/uic/uic.pro
- cp src/tools/moc/moc.pro src/tools/uic3/uic3.pro
- cp src/tools/moc/moc.pro src/tools/rcc/rcc.pro
- cp src/tools/moc/moc.pro demos/demos.pro
- cp src/tools/moc/moc.pro examples/examples.pro
A few things get confused during the build process due to the cross-compile so let's clarify things:
- Open $QTWIN/src/src.pro in your favorite editor.
- Find the line containing win32:SUBDIRS. Remove win32: but leave the rest of the line.
- Find all lines containing src_activeqt. Remove them.
- Save and close, then open $QTWIN/src/qbase.pri.
- There are two win32 { blocks. Remove the win32 { lines and the } lines corresponding to them.
- Find the win32|mac: line. Remove up to and including the last :.
- Find any line starting with win32: and remove win32: from the beginning of it.
- Find the line starting with CONFIG += qt and append create_prl to the end of it.
- Save and close, then open $QTWIN/src/winmain/winmain.pro.
- Find the line containing !win32. Remove that line.
- Save and close, then open $QTWIN/src/corelib/io/io.pri.
- Find the win32 { block. Remove that line.
- Find the } else:unix { block. Remove from that line to the end of the file.
- Save and close, then open $QTWIN/src/corelib/thread/thread.pri.
- Find the unix:SOURCES block. Remove from that line to just before win32:SOURCES.
- Remove win32: but leave the rest of the line.
- Save and close, then open $QTWIN/src/corelib/kernel/kernel.pri.
- Find the win32 { block. Remove that line.
- Find the } matching the { you just removed. Remove from that line to the end of the file.
- Save and close, then repeat the last three steps on $QTWIN/src/corelib/plugin/plugin.pri.
- Repeat this process for $QTWIN/src/gui/kernel/kernel.pri.
- Repeat this process for $QTWIN/src/gui/util/util.pri.
- Open $QTWIN/src/gui/text/text.pri.
- Find the win32 { block. Remove that line.
- Find the } matching the { you just removed. Remove from that line to the contains(QT_CONFIG, freetype) { (but don't delete that line).
- Save and close, then open $QTWIN/src/gui/gui.pro.
- Find the !win32: line. Remove that line.
- Find the x11: line. Remove that line.
- Find the win32: line. Remove win32: but leave the rest of the line.
- Save and close, then open $QTWIN/src/gui/image/image.pri.
- Find the win32:SOURCES line. Remove win32: from it. Remove the other lines in that small block.
- Find the win32:LIBS line. Remove win32: from it. Remove the unix: line above it.
- Save and close, then open $QTWIN/src/gui/inputmethod/inputmethod.pri.
- Find the x11 { line. Remove from that line to the matching }.
- Find the win32 { block. Remove that line.
- Find the } matching the { you just removed. Remove from that line to the end of the file.
- Save and close, then open $QTWIN/src/gui/painting/painting.pri. (This is going to be the tricky file.)
- Find the line starting with win32:. Remove win32: from it.
- Find the win32 { block. Remove that line and the } matching it.
- Find the unix:x11 { block. Remove from that line to the matching }.
- Find the unix:SOURCES line. Remove it.
- Find the x11|embedded { block. Remove from that line to the matching } else { and the } matching the else.
- Find win32-g++ and change it to mingw32-g++.
- Find the x11 { block inside the win32|x11|embedded { block. Remove from that line to the matching }.
- Save and close, then open $QTWIN/src/gui/dialogs/dialogs.pri.
- Find the win32 { block. Remove that line and the } matching it.
- Find the !mac:!embedded:unix { block. Remove from that line to the matching }.
- Save and close, then open $QTWIN/src/gui/accessible/accessible.pri.
- Find the mac { line. Remove from that line to the } else:win32 { line, including that line.
- Find the } else { line. Remove from that line to the } matching it.
- Save and close, then open $QTWIN/src/network/network.pro.
- Find the line starting with unix: and remove it.
- Find the line starting with win32:. Remove win32: from it.
- Save and close, then open $QTWIN/src/corelib/tools/tools.pri.
- Find the #zlib support comment. Remove the contains line below it.
- Find the line containing else:!contains. Remove from that line to the end of the file.
- Save and close, then open $QTWIN/src/plugins/styles/styles.pro.
- Find the win32: line. Remove everything up to and including the last :.
- Save and close, then open $QTWIN/src/winmain/winmain.pro.
- Find the win32 { line. Remove it and the } matching it.
- Find win32-g++: and change it to mingw32-g++.
- Save and close.
The other solution to this series of edits would be to instead hack on qmake's source to make it generate UNIX-style makefiles regardless of the mode, and then run it in -win32 mode instead of -unix mode. This is how I did it the first time, but I didn't document the specific modifications I made. Alternately, the hack would need to make qmake evaluate win32 as true and unix and x11 as false while running in -unix mode. Either way, it'll probably be less work overall; next time I set up this cross-compile I'll try that instead.
I encountered a couple of unexpected bugs during the compile, so let's fix them ahead of time: (Of course, these errors might be resolved in a future version of Qt, or they may actually compile successfully on a non-cross setup.)
- Open $QTWIN/src/corelib/kernel/qeventdispatcher_win.cpp in your favorite editor.
- Find the function qt_internal_proc and copy the function header.
- Paste the function header at the top of the file, below class QEventDispatcherWin32Private; and add a semicolon to make it a function prototype.
- Save and close, then open $QTWIN/src/gui/kernel/qkeymapper_win.cpp.
- Find MAKELCID. Change the call to GetKeyboardLayout(0) to *reinterpret_cast<int*>(GetKeyboardLayout(0)).
- Save and close, then open $QTWIN/src/gui/inputmethod/qwininputcontext_win.cpp.
- Add extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); to the top of the file, just below the #includes.
- Save and close.
Let's try to build this now!
- chdir $QTWIN
- qmake -recursive -spec mingw32-g++ -unix
- qmake -prl -recursive -spec mingw32-g++ -unix
- chdir to the library install path you selected earlier.
- for i in `ls *.prl`; do sed 's/-lQt.\{3,5\}4//g' $i > $i.out; mv $i.out $i; done
- chdir $QTWIN
- make sub-src
Current status: FAILED. Image plugins want _WinMain@16 but shouldn't.