如何为从 Linux 到 Windows 目标的交叉编译配置 Qt?

我想使用 Linux x86 _ 64主机为 Windows x86 _ 64目标交叉编译 Qt 库(最终是我的应用程序)。我觉得我已经很接近了,但是我可能对这个过程的某些部分有一些根本性的误解。

我首先在我的 Fedora 机器上安装所有 Mingw 包,然后修改 win32-g++ qmake.conf 文件以适应我的环境。然而,我似乎陷入了一些似乎显而易见的配置选项 Qt: -platform-xplatform。Qt 文档说,-platform应该是主机架构(您正在编译的地方) ,而 -xplatform应该是您希望部署的目标平台。在我的例子中,我设置了 -platform linux-g++-64-xplatform linux-win32-g++,其中 linux-win32-g + + 是我修改过的 win32-g + + 配置。

我的问题是,在使用这些选项执行 configure 之后,我发现它调用的是系统的编译器,而不是交叉编译器(x86 _ 64-w64-mingw32-gcc)。如果我省略了 -xplatform选项并将 -platform设置为我的目标规范(linux-win32-g + +) ,它将调用交叉编译器,但是当它发现一些与 Unix 相关的函数没有定义时,就会出错。

下面是我最新尝试的一些输出: http://pastebin.com/QCpKSNev

问题:

  1. 当从 Linux 主机交叉编译诸如 Qt for Windows 之类的东西时,应该调用本机编译器 永远不会吗?也就是说,在交叉编译过程中,我们不应该使用 只有交叉编译器吗?我不明白为什么当我指定 -xplatform选项时,Qt 的配置脚本会试图调用我的系统的本机编译器。

  2. 如果我使用 Mingw 交叉编译器,那么什么时候需要处理 specs 文件?GCC 的规格文件对我来说仍然是一个谜,所以我想知道这里的一些背景知识是否能帮助我。

  3. 一般来说,除了在 qmake.conf 中指定交叉编译器之外,我还需要考虑什么?

93183 次浏览

Just use M cross environment (MXE). It takes the pain out of the whole process:

  • Get it:

    $ git clone https://github.com/mxe/mxe.git
    
  • Install build dependencies

  • Build Qt for Windows, its dependencies, and the cross-build tools; this will take about an hour on a fast machine with decent internet access; the download is about 500MB:

    $ cd mxe && make qt
    
  • Go to the directory of your app and add the cross-build tools to the PATH environment variable:

    $ export PATH=<mxe root>/usr/bin:$PATH
    
  • Run the Qt Makefile generator tool then build:

    $ <mxe root>/usr/i686-pc-mingw32/qt/bin/qmake && make
    
  • You should find the binary in the ./release directory:

    $ wine release/foo.exe
    

Some notes:

  • Use the master branch of the MXE repository; it appears to get a lot more love from the development team.

  • The output is a 32-bit static binary, which will work well on 64-bit Windows.

Ok I think I've got it figured out.

Based in part on https://github.com/mxe/mxe/blob/master/src/qt.mk and https://www.videolan.org/developers/vlc/contrib/src/qt4/rules.mak

It appears that "initially" when you run configure (with -xtarget, etc.), it configures then runs your "hosts" gcc to build the local binary file ./bin/qmake

 ./configure -xplatform win32-g++ -device-option CROSS_COMPILE=$cross_prefix_here -nomake examples ...

then you run normal "make" and it builds it for mingw

  make
make install

so

  1. yes

  2. only if you need to use something other than msvcrt.dll (its default). Though I have never used anything else so I don't know for certain.

  3. https://stackoverflow.com/a/18792925/32453 lists some configure params.

(This is an update of @Tshepang's answer, as MXE has evolved since his answer)

Building Qt

Rather than using make qt to build Qt, you can use MXE_TARGETS to control your target machine and toolchain (32- or 64-bit). MXE started using .static and .shared as a part of the target name to show which type of lib you want to build.

# The following is the same as `make qt`, see explanation on default settings after the code block.
make qt MXE_TARGETS=i686-w64-mingw32.static   # MinGW-w64, 32-bit, static libs


# Other targets you can use:
make qt MXE_TARGETS=x86_64-w64-mingw32.static # MinGW-w64, 64-bit, static libs
make qt MXE_TARGETS=i686-w64-mingw32.shared   # MinGW-w64, 32-bit, shared libs


# You can even specify two targets, and they are built in one run:
# (And that's why it is MXE_TARGET**S**, not MXE_TARGET ;)
# MinGW-w64, both 32- and 64-bit, static libs
make qt MXE_TARGETS='i686-w64-mingw32.static x86_64-w64-mingw32.static'

In @Tshepang's original answer, he did not specify an MXE_TARGETS, and the default is used. At the time he wrote his answer, the default was i686-pc-mingw32, now it's i686-w64-mingw32.static. If you explicitly set MXE_TARGETS to i686-w64-mingw32, omitting .static, a warning is printed because this syntax is now deprecated. If you try to set the target to i686-pc-mingw32, it will show an error as MXE has removed support for MinGW.org (i.e. i686-pc-mingw32).

Running qmake

As we changed the MXE_TARGETS, the <mxe root>/usr/i686-pc-mingw32/qt/bin/qmake command will no longer work. Now, what you need to do is:

<mxe root>/usr/<TARGET>/qt/bin/qmake

If you didn't specify MXE_TARGETS, do this:

<mxe root>/usr/i686-w64-mingw32.static/qt/bin/qmake

Update: The new default is now i686-w64-mingw32.static

In order to compile Qt, one must run it's configure script, specifying the host platform with -platform (e.g. -platform linux-g++-64 if you're building on a 64-bit linux with the g++ compiler) and the target platform with -xplatform (e.g. -xplatform win32-g++ if you're cross compiling to windows).

I've also added this flag: -device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- which specifies the prefix of the toolchain I'm using, which will get prepended to 'gcc' or 'g++' in all the makefiles that are building binaries for windows.

Finally, you might get problems while building icd, which apparently is something that is used to add ActiveX support to Qt. You can avoid that by passing the flag -skip qtactiveqt to the configure script. I've got this one out of this bug report: https://bugreports.qt.io/browse/QTBUG-38223

Here's the whole configure command I've used:

    cd qt_source_directory
mkdir my_build
cd my_build
../configure \
-release \
-opensource \
-no-compile-examples \
-platform linux-g++-64 \
-xplatform win32-g++ \
-device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32- \
-skip qtactiveqt \
-v

As for yout questions:

1 - Yes. The native compiler will be called in order to build some tools that are needed in the build process. Maybe things like qconfig or qmake, but I'm not entirely sure which tools, exactly.

2 - Sorry. I have no idea what specs files are in the context of compilers =/ . But as far as I know, you wouldn't have to deal with that.

3 - You can specify the cross compiler prefix in the configure command line instead of doing it in the qmake.conf file, as mentioned above. And there's also that problem with idc, whose workaround I've mentioned as well.

Another way to cross-compile software for Windows on Linux is the MinGW-w64 toolchain on Archlinux. It is easy to use and maintain, and it provides recent versions of the compiler and many libraries. I personally find it easier than MXE and it seems to adopt newer versions of libraries faster.

First, you will need an arch-based machine (virtual machine or docker container will suffice). It does not have to be Arch Linux, derivatives will do as well. I used Manjaro Linux. Most of the MinGW-w64 packages are not available at the official Arch repositories, but there is plenty in AUR. The default package manager for Arch (Pacman) does not support installation directly from AUR, so you will need to install and use an AUR wrapper like yay or yaourt. Then installing MinGW-w64 version of Qt5 and Boost libraries is as easy as:

yay -Sy mingw-w64-qt5-base mingw-w64-boost
#yaourt -Sy mingw-w64-qt5-base mingw-w64-qt5-boost #if you use yaourt

This will also install the MinGW-w64 toolchain (mingw-w64-gcc) and other dependencies. Cross-compiling a Qt project for windows (x64) is then as simple as:

x86_64-w64-mingw32-qmake-qt5
make

To deploy your program you will need to copy corresponding dlls from /usr/x86_64-w64-mingw32/bin/. For example, you will typically need to copy /usr/x86_64-w64-mingw32/lib/qt/plugins/platforms/qwindows.dll to program.exe_dir/platforms/qwindows.dll.

To get a 32bit version you simply need to use i686-w64-mingw32-qmake-qt5 instead. Cmake-based projects work just as easily with x86_64-w64-mingw32-cmake. This approach worked extremely well for me, was the easiest to set-up, maintain, and extend. It also goes well with continuous integration services. There are docker images available too.

For example, let's say I want to build QNapi subtitle downloader GUI. I could do it in two steps:

  1. Start the docker container:
sudo docker run -it burningdaylight/mingw-arch:qt /bin/bash
  1. Clone and compile QNapi
git clone --recursive 'https://github.com/QNapi/qnapi.git'
cd qnapi/
x86_64-w64-mingw32-qmake-qt5
make

That's it! In many cases, it will be that easy. Adding your own libraries to the package repository (AUR) is also straightforward. You would need to write a PKBUILD file, which is as intuitive as it can get, see mingw-w64-rapidjson, for example.