Uncannier Software

It's not enough to just be uncanny

Cross Compile Qt – MinGW Windows Applications on a Linux Host

In my view, the cross-platform power of Qt is not fully realized if you need a different build host for every target platform. It’s only natural to want to have one build machine that can deliver multiple targets. And if we’re talking about a CI server for a team to use in a cross-platform application development, then it’s a very worthwhile investment.

Accordingly, the aim of this article is to document how to create a cross-compilation environment that allows you to build Windows applications on a Linux host. Specifically, Qt-based applications.

Wilful Ignorance

When it comes to this topic, the internet is populated with naysayers. They will tell you that it’s too hard to setup, that it will take you days (if ever) to setup, that a Windows virtual box is easier, so on and so forth. I can only think such people have never done it, because it really isn’t that hard.

How To

The notes here have been prepared using Qt 5.11.1 (Open Source) and Ubuntu 18.04 LTS 64-bit, as a working example.

MinGW

The cornerstone of this exercise is MinGW. This is the cross-platform compiler you will need to use instead of the vanilla GCC in your distribution.

sudo apt install mingw-w64

Qt Source

You need to download the Qt source code from https://download.qt.io/official_releases/qt/.

You have two major approaches:

  1. Download the base source package ( https://download.qt.io/official_releases/qt/5.11/5.11.1/single/ ) and desired individual modules ( https://download.qt.io/official_releases/qt/5.11/5.11.1/submodules/ ).
  2. Include the source when you install Qt.

In my case, I took the second option, and installed Qt as follows:

chmod +x qt-opensource-linux-x64-5.11.1.run ./qt-opensource-linux-x64-5.11.1.run

Prerequisities

Depending on what optional Qt modules you want to include, your prerequisites will likely be different. For example, if you want to build Qt WebEngine, you need flex, bison and more. In my case, the only sub-modules I wanted to add to qtbase were qtserialport, qtsvg and qttools. Hence the only prerequisites were:

sudo apt install build-essential libgl1-mesa-dev python

Configuring Qt

The Qt build then needs to be configured for cross-compilation using MinGW. The following command configures for creation of a 64-bit Qt development kit. You can instead use i686-w64-mingw32- for 32-bit.

The -prefix clauses specifies the destination directory for the resultant Qt development kit.

As I installed the entire Qt source, and only wanted to build a handful of optional sub-modules, I needed many -skip clauses. YMMV; if you download only the source of sub-modules you want to build, you won’t need any -skip clauses. If the size of the build is not reduced one way or another, the build time will be very much greater, as will be the number of prerequisite packages.

./configure 
-xplatform win32-g++ 
-device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- 
-prefix /home/foobar/Qt5.11.1/5.11.1/mingw_64 
-opensource 
-no-compile-examples 
-opengl desktop
-skip qtactiveqt -skip qtcharts -skip qtdoc -skip qtlocation 
-skip qtremoteobjects -skip qtserialbus -skip qtwebchannel 
-skip qtwebview -skip qtandroidextras -skip qtconnectivity 
-skip qtgamepad -skip qtmacextras -skip qtpurchasing -skip qtscript 
-skip qttranslations -skip qtwebengine -skip qtwinextras 
-skip qtdatavis3d -skip qtgraphicaleffects -skip qtmultimedia 
-skip qtquickcontrols -skip qtscxml -skip qtspeech 
-skip qtvirtualkeyboard -skip qtwebglplugin -skip qtx11extras 
-skip qt3d -skip qtcanvas3d -skip qtdeclarative 
-skip qtimageformats -skip qtnetworkauth -skip qtquickcontrols2 
-skip qtsensors -skip qtwayland -skip qtwebsockets -skip qtxmlpattern

Make

OK, now you have to settle in for a long build. In my case, it was just over an hour.

make

Installation

You know it.

make install

Qt Creator

If you’ve made it here, you now have a 64-bit MinGW development kit for Qt, installed side-by-side with your native vanilla GCC development kit. Now we need to configure Qt Creator to use it. If you’re a Qt developer, this part is probably trivial.

Add The Compiler

Add The Qt Version

Note that the warning is because there’s no qmlscene installed – this is not needed for merely making Windows-targeted builds for QA and production.

Add The Development Kit

Add a new Kit that references the new Compiler and new Qt Version. Note that the warning is because there’s no Debugger configured for this kit; we didn’t install the MinGW GDB as you would not use it to debug a Windows build on a Linux host. Instead you would debug using the native GCC and GDB.

Conclusion

So in reality, it’s not hard. The actual building of Qt is long, but the level of challenge is low.

The only real challenge lies in the relative dearth of clear information available on the web. Maybe I’m just bad at Googling, but it surprises me that this isn’t front and centre at qt.org.

References

The steps presented here were pieced together with the help of the following links, and a few hours of trial and error:

Tagged , , , ,

9 thoughts on “Cross Compile Qt – MinGW Windows Applications on a Linux Host

  • Hey,
    thanks for your post. Worked fine with Qt 5.11.2.
    Only thing to mention is that you will have to add a few .dll-files after the cross compile before you can run the resulting .exe in windows. In my test case I took the calculator example that comes with QtCreator an had to add libgcc_s_seh-1.dll, libstdc++-6.dll, qt5core.dll, qt5gui.dll, qt5widgets.dll and qwindows.dll (in subfolder “platforms”). They all come with the MinGW installation and you just need to copy them to your release.
    Afterwards I could run the calculator in windows 🙂

    1. Thanks Roger.

      I didn’t cover that because it’s not related to the cross-compilation per se, but yes the DLLs need to be packaged with the EXE.

      Ideally we could use the windeployqt utility (as we would on Windows), but it doesn’t seem to work. It reports:

      Unable to find dependent libraries of foobar.exe :Not implemented.

      I think that is a limitation of windeployqt itself, which seemingly does not support parsing of the PE format when built on a Linux system (QT_OS_WIN is not defined):

      https://code.woboq.org/qt5/qttools/src/shared/winutils/utils.cpp.html#_Z16readPeExecutableRK7QStringPS_P11QStringListPjPbb

      So I think we are forced to make our own custom script to package DLLs. At least that is what I did. A minor disappointment.

  • I tried to add -static option into this build but got errors asking for win10 sdk and msvc2017 header files. Is it possible to make this a static build?

  • I didn’t try it yet but if it works, this is the easiest solution on the internet as of 26/3/2019. I found this solution after 4 hours of googling (phew!). More than 2 solutions stated that i need to install some “mxe”. But i dont want to install any thing except qt and the dependencies like mingw. cheers! 🙂

  • Nope the build fails.

    The mingw install went perfectly. It’s in /usr/bin
    I downloaded and installed only the base Qt 5.14.2, no submodules.
    I wanted a 32-bit target, so I followed your clear instructions, substituting Qt release 5.14.2 instead, CROSS_COMPILE=/usr/bin/i686-w64-mingw32-
    and substituting the install path to /opt/Qt5.14.2/5.14.2/mingw_64.
    ./configure completed ok.
    make failed after about 15 minutes giving
    tools/qsimd.cpp: In fucntion ‘qsizetype qRandomCpu(void*, qsizetype)’:
    tools/qsimd.cpp:657:1: internal compiler error: in ix86_compute_frame_layout, at config/i386/i386.c:12821
    }
    ^
    ……..recipe failed

    For the last three months for several hours each day I’ve been trying to compile Dream DRM for Windows 7 as their newest version is for W10 and the developers seem stuck, so I’ve been trying to build it myself using various tricks and environments on both windows 7 and Ubuntu 18.04 LTS Bionic x86_64.

    I’ve been in & out of programming since 1989, but I don’t care to learn any of it anymore as it never made me any money, just costed money for school.

    Furthermore they keep changing it and none of what I learn about this today will be relevant in a year. The links / repositories / what have you will somehow be broken in a year. Documentation will no longer apply and will not be updated. No one will use Python or Ruby or Qt but will instead have you install a whole entire New Thing and hunt for the correct versions and doo-dads to get to (maybe) work. Then it’s off to the next big thing. Rinse, repeat.

    I’m tired of trying to keep up. Why should I install hundreds of gigs of libraries every year or so just to compile one 500k program? It’s asinine. This is broke, that is broke, I can’t keep up with all the versions….

    So this is what I have to say to your comment above about ‘Willful Ignorance’. This individual has been successful only with Cygwin. But it doesn’t work this time for what I’m trying to do. Not for lack of trying. I’m not very good at a lot of things, but I am patient, I explore new methods, I do things myself, and I persevere, I give up, and I come back to it.
    So with all that being said, you must have unlimited time to sit there and keep up. I don’t, so in that way, I guess I could look here and let you call me ‘willfully ignorant’. I have reached the point where I need to cut my losses and put out other fires. This human only has so many days on this old earth, and I can think of about a dozen other things that I would like my legacy to be, other than having memorized a lot of code. There is never always an easy answer to Linux. If it works once, it’ll be broken soon.

    So give me credit. I tried what you said and it didn’t work either.

    1. Hey James. Apologies for the slow reply.

      I’m sorry to hear it’s been such a frustrating experience. I agree that if it burns a ton of hours, it’s not worth it. Particularly for those of us at an age where, as you say, not so many days left on this earth.

      I have been through the process with Qt 5.11 and 5.12, and it was trouble free (well there was a bug in QtSerial in 5.12, but the build was trouble free). I haven’t tried 5.14. Since it’s not working for you under Windows/Cygwin either, I suspect the problem is not really with the process I’ve documented in this post. You are inspiring me to give it a crack. I will have weigh it up against my days remaining on earth …

      1. I tried the steps above on a Ubuntu 20.04 LTS 64-bit with Qt Creator 4.14.2 and Qt 5.12.0. Build and install went fine and installed the toolchain. Configured Kit, Compiler etc as per instructions above. But when I start compile a project, QGroundControl, it says “Unspported Windows toolchain, only VIsual Studio 2017 64bit supported”
        My whole reason of going down this route was to get QGC compie for Windows from Linux

    2. Hi, I just ran into the same error message you did. I solved it by editing the file qtbase/src/corelib/tools/qsimd.cpp

      Replace the following line:

      #if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)

      With:

      #if 0

      For your reference, I was using Qt 5.12.9, with the i686-mingw64 version that is in the ubuntu 16.04 repositories, and was running with ubuntu 16.04 32-bit. The following was what I used for my configure command:

      ./configure -xplatform win32-g++ -device-option CROSS_COMPILE=/usr/bin/i686-w64-mingw32- -prefix /usr/local/Qt5.12.9-win32 -static -optimize-size -release -nomake examples -nomake tests -skip qtconnectivity -skip qtserialbus -skip qtserialport -skip qtsvg -skip qtwebengine -skip qtdeclarative -skip qtlocation -no-opengl -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2 -no-avx -no-avx2 -no-avx512 -opensource -confirm-license -no-sql-db2 -no-sql-ibase -no-sql-mysql -no-sql-oci -no-sql-odbc -no-sql-psql -no-sql-sqlite2 -no-sql-tds -no-sqlite -no-gif -no-ico -no-libpng -no-libjpeg -no-tslib -no-mtdev -no-libinput -no-imf -no-evdev -no-xcb -no-mirclient -no-linuxfb -no-kms -no-gbm -no-eglfs -no-directfb -no-direct2d -no-xcb-xlib -no-combined-angle-lib -no-angle -no-opengles3 -no-opengl -no-lgmon -no-cups -no-harfbuzz -no-fontconfig -no-freetype -no-libproxy -no-sctp -no-journald -no-syslog -no-slog2 -no-zlib -no-pps -no-icu -no-iconv -no-inotify -no-eventfd -no-glib -no-dbus -skip qtconnectivity -skip qtsensors -skip qtwebchannel -skip qtwebview -skip qtserialbus -skip qtserialport -skip qtsvg -skip qtmultimedia -skip qtdatavis3d -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtvirtualkeyboard -skip qtxmlpatterns -skip qtwebsockets -skip qtmultimedia -skip qtcharts -skip qtcanvas3d -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtmacextras -skip qtwinextras -skip qtspeech -skip qtdeclarative -no-sql-sqlite -skip qtquickcontrols -skip qtquickcontrols2 -skip qtpurchasing -skip qtscript -skip qtscxml -skip qtgraphicaleffects -skip qtwebglplugin -no-sse2

Leave a Reply

Your email address will not be published. Required fields are marked *