我该如何配置Qt,从Linux交叉编译到Windows目标?

89

我想使用 Linux x86_64 主机机器交叉编译 Qt 库(以及最终的应用程序)为 Windows x86_64 目标平台。我感觉已经很接近了,但是可能有一些步骤我有基本的误解。

我开始在我的 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 主机交叉编译 Windows 平台上的 Qt 等内容时,本地编译器是否应该被调用?也就是说,在交叉编译过程中,我们不应该仅使用交叉编译器吗? 我不明白为什么 Qt 的 configure 脚本在我指定了 -xplatform 选项后仍然试图调用系统的本地编译器。

  2. 如果我使用mingw的交叉编译器,什么时候需要处理规格文件(specs file)?GCC的规格文件对我来说仍然有些神秘,因此我想知道这里是否需要一些背景知识。

  3. 通常情况下,在我的qmake.conf中指定交叉编译器之外,还有什么需要考虑的吗?


2
我认为需要本地构建qmake来引导其余的构建过程。另请参阅https://dev59.com/MkjSa4cB1Zd3GeqPChpp中的链接。 - Martin Beckett
好的,那很有道理。我现在发现另一个问题,似乎我正在混合使用本地和交叉工具链。我的pastebin输出中的错误似乎是由于调用了x86_64-w64-mingw32-as而不是本地的工具链引起的。 - Mr. Shickadance
2
我很少将一个SO问题标记为收藏,但这是一个独特而有趣的问题,并且有一个很棒的答案。 - jdi
5个回答

79

只需使用M交叉环境(MXE),它可以轻松完成整个过程:

  • 获取它:

$ git clone https://github.com/mxe/mxe.git
  • 安装构建依赖项

  • 为Windows构建Qt及其依赖项和交叉编译工具;对于配置良好、具有较快的互联网访问速度的计算机, 这将需要大约一小时;下载大小约为500MB:

  • $ cd mxe && make qt
    
  • 进入您的应用程序目录,并将交叉编译工具添加到PATH环境变量中:

  • $ export PATH=<mxe root>/usr/bin:$PATH
    
    运行Qt Makefile生成工具,然后构建:
    $ <mxe root>/usr/i686-pc-mingw32/qt/bin/qmake && make
    
    您应该在./release目录中找到二进制文件:
  • $ wine release/foo.exe
    
  • 一些注意事项:

    • 使用MXE存储库的主支; 该存储库似乎得到了开发团队更多的支持。

    • 输出是一个32位的静态二进制文件,在64位Windows上可以很好地工作。


    18
    注意:这些指令适用于Qt 4;有关Qt 5的信息,请参阅https://dev59.com/YGYq5IYBdhLWcg3w0T1y#14170591。 - tshepang
    在执行 $ cd mxe && make qt 命令之前,您应该安装必要的依赖项。对于 Debian 系统来说,这意味着需要运行 sudo apt-get install autoconf automake autopoint bash bison bzip2 cmake flex gettext git g++ gperf intltool libffi-dev libtool libltdl-dev libssl-dev libxml-parser-perl make openssl patch perl pkg-config python ruby scons sed unzip wget xz-utils 命令。对于其他系统,请参考 http://mxe.cc/#requirements。 - Martin Thoma
    现在是2023年,这些仍然是工作指示,只是在WSL Ubuntu 22.04上编译"qt"失败了,所以我不得不使用"qt5"代替,命令为cd mxe && make qt5 - Yılmaz Durmaz

    19

    构建Qt

    与其使用make qt来构建Qt,您可以使用MXE_TARGETS来控制目标机器和工具链(32位或64位)。 MXE开始使用.static.shared作为目标名称的一部分,以显示要构建的库类型。

    # 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'
    

    在 @Tshepang 原始答案中,他没有指定 MXE_TARGETS,默认会使用。当他写下这个答案的时候, 默认值是 i686-pc-mingw32,现在变成了 i686-w64-mingw32.static。 如果您将 MXE_TARGETS 显式设置为 i686-w64-mingw32,省略 .static,则会打印警告,因为此语法现已过时。如果您尝试将目标设置为 i686-pc-mingw32,则会显示错误,因为 MXE 已删除对 MinGW.org (即 i686-pc-mingw32) 的支持。

    运行 qmake

    由于我们更改了 MXE_TARGETS<mxe root>/usr/i686-pc-mingw32/qt/bin/qmake 命令将不再起作用。现在,您需要执行以下操作:
    <mxe root>/usr/<TARGET>/qt/bin/qmake
    

    如果您没有指定MXE_TARGETS,请执行以下操作:
    <mxe root>/usr/i686-w64-mingw32.static/qt/bin/qmake
    

    更新:新的默认设置现在是。

    非常感谢您的更新。有人直接在项目上工作并回应也是很好的。 - tshepang
    3
    这应该是对其他答案的编辑/更新,而不是一个新的答案。 - WhyNotHugo
    3
    编辑页面上写着: 如何编辑: ► 修正语法或拼写错误 ► 在不改变意思的情况下澄清含义 ► 纠正小错误 ► 添加相关资源或链接 ► 始终尊重原作者这并不属于以上任何一种。它是对Tshepang的回答的扩展。 - Timothy Gu
    我不理解这个答案,当我输入“make qt....”时,它只回应“没有规则可以制作目标qt”。 - Mine

    9
    另一种在Linux上为Windows交叉编译软件的方法是使用Archlinux上的MinGW-w64工具链。它易于使用和维护,并提供了编译器和许多库的最新版本。我个人认为它比MXE更容易,而且似乎更快地采用了较新版本的库。
    首先,您需要一个基于Arch的机器(虚拟机或docker容器都可以)。它不必是Arch Linux,衍生版本也可以。我使用了Manjaro Linux。 大多数MinGW-w64包不在官方Arch存储库中,但在 AUR中有很多。Arch的默认包管理器(Pacman)不支持直接从AUR安装,因此您需要安装和使用AUR包装器,如yay或yaourt。然后安装MinGW-w64版本的Qt5和Boost库就像这样简单:
    yay -Sy mingw-w64-qt5-base mingw-w64-boost
    #yaourt -Sy mingw-w64-qt5-base mingw-w64-qt5-boost #if you use yaourt
    

    这也会安装MinGW-w64工具链(mingw-w64-gcc)和其他依赖项。 为Windows(x64)交叉编译Qt项目就像这样简单:
    x86_64-w64-mingw32-qmake-qt5
    make
    

    要部署您的程序,您需要从/usr/x86_64-w64-mingw32/bin/复制相应的dll文件。例如,通常需要将/usr/x86_64-w64-mingw32/lib/qt/plugins/platforms/qwindows.dll复制到program.exe_dir/platforms/qwindows.dll
    要获取32位版本,只需使用i686-w64-mingw32-qmake-qt5即可。基于Cmake的项目也同样易于使用x86_64-w64-mingw32-cmake。 这种方法非常适合我,设置、维护和扩展都非常容易。 它还可以与持续集成服务很好地配合使用。也有docker镜像可用。
    例如,假设我想构建QNapi字幕下载器GUI。我可以分两步完成:
    sudo docker run -it burningdaylight/mingw-arch:qt /bin/bash
    
    1. 克隆并编译QNapi
    git clone --recursive 'https://github.com/QNapi/qnapi.git' 
    cd qnapi/ 
    x86_64-w64-mingw32-qmake-qt5
    make
    

    就是这样!在许多情况下,这将会非常简单。将自己的库添加到软件包仓库(AUR)也很简单。您需要编写一个PKBUILD文件,这是尽可能直观的,例如mingw-w64-rapidjson


    部署时,您必须复制所有所需的Qt DLL(或http://doc.qt.io/qt-5/windows-deployment.html)。确保将/mingw64/share/qt5/plugins/platforms/qwindows.dll复制到platforms/qwindows.dll中。 - develCuy

    4

    好的,我想我已经弄清楚了。

    部分基于https://github.com/mxe/mxe/blob/master/src/qt.mkhttps://www.videolan.org/developers/vlc/contrib/src/qt4/rules.mak

    看起来,“最初”在您运行配置(带有-xtarget等)时,它会进行配置然后运行“主机”gcc以构建本地二进制文件./bin/qmake。

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

    然后你运行普通的“make”,它将为mingw构建它。
      make
      make install
    

    因此

    1. 是的

    2. 只有在您需要使用除msvcrt.dll(默认)之外的其他内容时才需要。尽管我从未使用过其他任何东西,所以我不确定。

    3. https://stackoverflow.com/a/18792925/32453列出了一些配置参数。


    4
    为了编译Qt,必须运行其configure脚本,并使用-platform 参数指定主机平台(例如,在64位Linux上使用g++编译器构建时,可以使用-platform linux-g++-64),并使用-xplatform参数指定目标平台(例如,交叉编译到Windows时,可以使用-xplatform win32-g++)。
    我还添加了以下标志:-device-option CROSS_COMPILE=/usr/bin/x86_64-w64-mingw32-,它指定了我正在使用的工具链的前缀,该前缀将被添加到为Windows构建二进制文件的所有makefile中的'gcc'或'g++'之前。

    最后,您在构建idc时可能会遇到问题,这显然是用于为Qt添加ActiveX支持的内容。您可以通过将标志-skip qtactiveqt传递给配置脚本来避免此问题。我从这个错误报告中得到了这个建议:https://bugreports.qt.io/browse/QTBUG-38223

    以下是我使用的完整配置命令:

        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
    

    关于你的问题:
    1 - 是的。原生编译器将被调用以构建一些在构建过程中所需的工具。可能是像 qconfig 或 qmake 这样的工具,但我不完全确定具体是哪些工具。
    2 - 抱歉。在编译器的上下文中,我不知道规格文件是什么 =/ 。但据我所知,你不需要处理那个。
    3 - 你可以在配置命令行中指定交叉编译器前缀,而不是在 qmake.conf 文件中进行设置,正如上面提到的。还有一个关于 idc 的问题,我也提到了解决方法。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接