Cross compiling

From qtnode

Jump to: navigation, search

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:

  1. emerge qt (we need a native Linux Qt4)
  2. mkdir -p /usr/local/overlays/crossdev
  3. emerge crossdev
  4. crossdev mingw32
  5. Wait for toolchain to compile

Next, make a suitable makespec so we don't have to figure out how to bootstrap qmake:

  1. mkdir -p /usr/share/qt4/mkspecs/mingw32-g++
  2. Download MinGW qmake.conf and save as /usr/share/qt4/mkspecs/mingw32-g++/qmake.conf
  3. cp /usr/share/qt4/mkspecs/win32-g++/qplatformdefs.h /usr/share/qt4/mkspecs/mingw32-g++/
  4. Open qmake.conf in your favorite editor.
  5. Replace the blanks for QT_BUILD_TREE with $QTWIN.
  6. 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...:

  1. cd $QTX11
  2. ./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
  3. Accept the GPL license agreement
  4. cp src/corelib/global/qconfig.* $QTWIN/src/corelib/global/
  5. cp include/QtCore/qconfig.h $QTWIN/include/QtCore/
  6. (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:

  1. cd $QTWIN
  2. rm -rf src/tools/moc/* src/tools/uic/* src/tools/uic3/* src/tools/rcc/* demos/* examples/*
  3. echo "TEMPLATE=subdirs" > src/tools/moc/moc.pro
  4. cp src/tools/moc/moc.pro src/tools/uic/uic.pro
  5. cp src/tools/moc/moc.pro src/tools/uic3/uic3.pro
  6. cp src/tools/moc/moc.pro src/tools/rcc/rcc.pro
  7. cp src/tools/moc/moc.pro demos/demos.pro
  8. 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:

  1. Open $QTWIN/src/src.pro in your favorite editor.
  2. Find the line containing win32:SUBDIRS. Remove win32: but leave the rest of the line.
  3. Find all lines containing src_activeqt. Remove them.
  4. Save and close, then open $QTWIN/src/qbase.pri.
  5. There are two win32 { blocks. Remove the win32 { lines and the } lines corresponding to them.
  6. Find the win32|mac: line. Remove up to and including the last :.
  7. Find any line starting with win32: and remove win32: from the beginning of it.
  8. Find the line starting with CONFIG += qt and append create_prl to the end of it.
  9. Save and close, then open $QTWIN/src/winmain/winmain.pro.
  10. Find the line containing !win32. Remove that line.
  11. Save and close, then open $QTWIN/src/corelib/io/io.pri.
  12. Find the win32 { block. Remove that line.
  13. Find the } else:unix { block. Remove from that line to the end of the file.
  14. Save and close, then open $QTWIN/src/corelib/thread/thread.pri.
  15. Find the unix:SOURCES block. Remove from that line to just before win32:SOURCES.
  16. Remove win32: but leave the rest of the line.
  17. Save and close, then open $QTWIN/src/corelib/kernel/kernel.pri.
  18. Find the win32 { block. Remove that line.
  19. Find the } matching the { you just removed. Remove from that line to the end of the file.
  20. Save and close, then repeat the last three steps on $QTWIN/src/corelib/plugin/plugin.pri.
  21. Repeat this process for $QTWIN/src/gui/kernel/kernel.pri.
  22. Repeat this process for $QTWIN/src/gui/util/util.pri.
  23. Open $QTWIN/src/gui/text/text.pri.
  24. Find the win32 { block. Remove that line.
  25. Find the } matching the { you just removed. Remove from that line to the contains(QT_CONFIG, freetype) { (but don't delete that line).
  26. Save and close, then open $QTWIN/src/gui/gui.pro.
  27. Find the !win32: line. Remove that line.
  28. Find the x11: line. Remove that line.
  29. Find the win32: line. Remove win32: but leave the rest of the line.
  30. Save and close, then open $QTWIN/src/gui/image/image.pri.
  31. Find the win32:SOURCES line. Remove win32: from it. Remove the other lines in that small block.
  32. Find the win32:LIBS line. Remove win32: from it. Remove the unix: line above it.
  33. Save and close, then open $QTWIN/src/gui/inputmethod/inputmethod.pri.
  34. Find the x11 { line. Remove from that line to the matching }.
  35. Find the win32 { block. Remove that line.
  36. Find the } matching the { you just removed. Remove from that line to the end of the file.
  37. Save and close, then open $QTWIN/src/gui/painting/painting.pri. (This is going to be the tricky file.)
  38. Find the line starting with win32:. Remove win32: from it.
  39. Find the win32 { block. Remove that line and the } matching it.
  40. Find the unix:x11 { block. Remove from that line to the matching }.
  41. Find the unix:SOURCES line. Remove it.
  42. Find the x11|embedded { block. Remove from that line to the matching } else { and the } matching the else.
  43. Find win32-g++ and change it to mingw32-g++.
  44. Find the x11 { block inside the win32|x11|embedded { block. Remove from that line to the matching }.
  45. Save and close, then open $QTWIN/src/gui/dialogs/dialogs.pri.
  46. Find the win32 { block. Remove that line and the } matching it.
  47. Find the !mac:!embedded:unix { block. Remove from that line to the matching }.
  48. Save and close, then open $QTWIN/src/gui/accessible/accessible.pri.
  49. Find the mac { line. Remove from that line to the } else:win32 { line, including that line.
  50. Find the } else { line. Remove from that line to the } matching it.
  51. Save and close, then open $QTWIN/src/network/network.pro.
  52. Find the line starting with unix: and remove it.
  53. Find the line starting with win32:. Remove win32: from it.
  54. Save and close, then open $QTWIN/src/corelib/tools/tools.pri.
  55. Find the #zlib support comment. Remove the contains line below it.
  56. Find the line containing else:!contains. Remove from that line to the end of the file.
  57. Save and close, then open $QTWIN/src/plugins/styles/styles.pro.
  58. Find the win32: line. Remove everything up to and including the last :.
  59. Save and close, then open $QTWIN/src/winmain/winmain.pro.
  60. Find the win32 { line. Remove it and the } matching it.
  61. Find win32-g++: and change it to mingw32-g++.
  62. 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.)

  1. Open $QTWIN/src/corelib/kernel/qeventdispatcher_win.cpp in your favorite editor.
  2. Find the function qt_internal_proc and copy the function header.
  3. Paste the function header at the top of the file, below class QEventDispatcherWin32Private; and add a semicolon to make it a function prototype.
  4. Save and close, then open $QTWIN/src/gui/kernel/qkeymapper_win.cpp.
  5. Find MAKELCID. Change the call to GetKeyboardLayout(0) to *reinterpret_cast<int*>(GetKeyboardLayout(0)).
  6. Save and close, then open $QTWIN/src/gui/inputmethod/qwininputcontext_win.cpp.
  7. Add extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); to the top of the file, just below the #includes.
  8. Save and close.

Let's try to build this now!

  1. chdir $QTWIN
  2. qmake -recursive -spec mingw32-g++ -unix
  3. qmake -prl -recursive -spec mingw32-g++ -unix
  4. chdir to the library install path you selected earlier.
  5. for i in `ls *.prl`; do sed 's/-lQt.\{3,5\}4//g' $i > $i.out; mv $i.out $i; done
  6. chdir $QTWIN
  7. make sub-src

Current status: FAILED. Image plugins want _WinMain@16 but shouldn't.

Personal tools