不完美制作交叉 Qt 5.7.1 for Windows
2025-08-10 10:23:34

在之前的文章中学会了如何制作 GCC 交叉编译器,有了交叉编译器后,就可以用交叉编译器来编译第三方库,比如 Qt。
本次的最终任务是制作 Windows 上使用的 Qt linux x86_64 库。

为什么不完美

可能是因为 Qt 5.7.1 版本太老的原因,最初尝试在 msys2 环境下制作,但是无法生成配置程序,大概是因为这个版本的 qmake 总是认为自身运行 Windows 原生环境下,导致一些代码逻辑在 msys2 下失败了,不知道新版本 Qt 情况如何。
正因为这样我们就只能在 Windows 下编译,但在 Windows 下又无法用configure来配置,只能用configure.bat,但用configure.bat时就不会有 Linux 下的一些编译选项和检测,这样就无法编译制作一些 Linux Qt 依赖的插件库。
所以只能编译 Qt 的基础库,比如Qt5CoreQt5Gui等等,当最终编译出的项目要部署时就会缺少一些插件库,这就是我说的“不完美”。


如何解决呢?
一个曲线救国的方法,在目标 Linux 系统上用相同的编译器,Qt版本、编译参数编译一份 Qt 库,这样我们在部署自己的项目时就不用 Windows 的 Qt 库了,只用拷贝自己的项目文件到目标 Linux 系统上即可,实际运行时 Qt 库用的是 Linux 下编译的那套。
这就要求两边的编译器、Qt版本、编译参数完全一致,否则可能因为 ABI 问题引起崩溃之类的问题。

准备工作

本机编译器

本机编译器的职责是编译qmake.exemoc.exeuic.exe等运行在 Windows 上的工具。
编译器使用 winlibs 家的 winlibs-x86_64-posix-seh-gcc-15.1.0-mingw-w64ucrt-13.0.0-r4

1
set PATH=C:\winlibs-gcc15.1.0\mingw64\bin;%PATH%

确保命令行中可以找到gccmingw32-make命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
C:\>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/winlibs-gcc15.1.0/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/15.1.0/lto-wrapper.exe
OFFLOAD_TARGET_NAMES=nvptx-none
Target: x86_64-w64-mingw32
Configured with: ../configure --prefix=/R/winlibs_staging_ucrt64/inst_gcc-15.1.0/share/gcc --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --enable-offload-targets=nvptx-none --with-pkgversion='MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r4' --with-tune=generic --enable-checking=release --enable-threads=posix --disable-sjlj-exceptions --disable-libunwind-exceptions --disable-serial-configure --disable-bootstrap --enable-host-shared --enable-plugin --disable-default-ssp --disable-rpath --disable-libstdcxx-debug --disable-version-specific-runtime-libs --disable-symvers --enable-languages=c,c++,fortran,lto,objc,obj-c++ --disable-gold --disable-nls --disable-stage1-checking --disable-win32-registry --disable-multilib --enable-ld --enable-libquadmath --enable-libada --enable-libssp --enable-libstdcxx --enable-lto --enable-fully-dynamic-string --enable-libgomp --enable-graphite --enable-mingw-wildcard --enable-libstdcxx-time --enable-libstdcxx-pch --with-mpc=/c/Prog/winlibs_staging_ucrt/custombuilt64 --with-mpfr=/c/Prog/winlibs_staging_ucrt/custombuilt64 --with-gmp=/c/Prog/winlibs_staging_ucrt/custombuilt64 --with-isl=/c/Prog/winlibs_staging_ucrt/custombuilt64 --disable-libstdcxx-backtrace --enable-install-libiberty --enable-__cxa_atexit --without-included-gettext --with-diagnostics-color=auto --enable-clocale=generic --enable-libgdiagnostics --with-libiconv --with-system-zlib --with-build-sysroot=/R/winlibs_staging_ucrt64/gcc-15.1.0/build_mingw/mingw-w64 CFLAGS='-I/c/Prog/winlibs_staging_ucrt/custombuilt64/include/libdl-win32 -march=nocona -msahf -mtune=generic -O2 -Wno-error=format' CXXFLAGS='-Wno-int-conversion -march=nocona -msahf -mtune=generic -O2' LDFLAGS='-pthread -Wl,--no-insert-timestamp -Wl,--dynamicbase -Wl,--high-entropy-va -Wl,--nxcompat -Wl,--tsaware' LD=/c/Prog/winlibs_staging_ucrt/custombuilt64/share/binutils/bin/ld.exe
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 15.1.0 (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r4)

C:\>mingw32-make -v
GNU Make 4.4.1
Built for x86_64-w64-mingw32
Copyright (C) 1988-2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

交叉编译器

交叉编译器的职责是编译 Qt 动态库项目,以便生成目标平台的.so文件。
这里假设你已经准备好了一个 GCC 15.1.0 的交叉编译器,同样将其bin目录加入到环境变量PATH中,确保能找到x86_64-linux-gnu-gcc命令。

1
2
3
4
5
6
7
8
9
10
11
set PATH=C:\cross-toolchain\Linux-x86_64\bin;%PATH%

C:\>x86_64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=x86_64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=C:/cross-toolchain/Linux-x86_64/bin/../libexec/gcc/x86_64-linux-gnu/15.1.0/lto-wrapper.exe
Target: x86_64-linux-gnu
Configured with: ../configure --prefix=/opt/cross --with-sysroot=/opt/cross/x86_64-linux-gnu --enable-languages=c,c++ --enable-shared --disable-multilib --disable-werror --disable-checking --build=x86_64-linux-gnu --host=x86_64-w64-mingw32 --target=x86_64-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 15.1.0 (GCC)

准备sysroot

准备好目标 Linux 系统的 sysroot,需要在 Windows 上远程访问它的根文件系统。
我这里使用的是 Ubuntu 16 x86_64 虚拟机,打开 ssh 服务,并打开root远程访问权限。
还要安装 Qt 依赖的库

1
sudo apt-get install -y libgl1-mesa-dev

可能有人会想到使用局域网共享的方式,但是实测不行,因为通过共享文件夹方式访问时对于符号文件兼容性不好,会存在无法访问文件的情况。
这里我找到了一个 ssh 挂载神器:https://github.com/winfsp/sshfs-win
Windows 打开此电脑,右键选择映射网络驱动器

1
\\sshfs.r\root@192.168.27.101

这里一定要用root用户,因为稍后制作的 Qt 库会写入到 Linux 的根目录/下面,必须要有最高权限。

msys2

https://www.msys2.org/docs/installer 下载安装 msys2。
为什么需要它?我们并不是要使用 msys2,只是需要它自带的一些 linux 的工具,如cprm等等,因为稍后 Qt 编译脚本会调用这些命令。

1
2
3
4
5
set PATH=C:\msys64\usr\bin;%PATH%

C:\>cp -v
cp: missing file operand
Try 'cp --help' for more information.

开始编译

我使用的 Qt 版本是 5.7.1:qtbase-opensource-src-5.7.1.7z
解压后需要先编辑mkspecs\linux-g++-64\qmake.conf文件,在末尾追加:

1
2
3
4
5
6
7
8
9
10
11
12
QMAKE_CC                = x86_64-linux-gnu-gcc
QMAKE_CXX = x86_64-linux-gnu-g++
QMAKE_LINK = x86_64-linux-gnu-g++
QMAKE_LINK_SHLIB = x86_64-linux-gnu-g++
QMAKE_AR = x86_64-linux-gnu-ar cqs
QMAKE_OBJCOPY = x86_64-linux-gnu-objcopy
QMAKE_STRIP = x86_64-linux-gnu-strip
QMAKE_NM = x86_64-linux-gnu-nm -P
QMAKE_RANLIB = x86_64-linux-gnu-ranlib

DEFINES += QT_HAVE_POLL
QMAKE_LFLAGS += -L Z:/usr/lib/x86_64-linux-gnu

好了,开始编译吧!

1
2
3
4
5
6
7
cd C:\Qt\qtbase-opensource-src-5.7.1
mkdir build
cd build

..\configure.bat -prefix \qt-5.7.1 -platform win32-g++ -xplatform linux-g++-64 -sysroot Z:\ -confirm-license -opensource -release -opengl desktop -nomake examples -nomake tests
mingw32-make -j
mingw32-make install

几个参数的解释:

  • -sysroot:指定了远程 Linux 根文件路径,在编译 Qt 过程中,Qt 库会在其中查找依赖库的头文件和库文件。
  • -prefix:指定最终 Qt 库的安装位置,它会和-sysroot拼接起来,在上面的命令中,最后 Qt 库会创建在Z:\qt-5.7.1下,这就是为什么必须要用root用户的原因。
  • -platform:指定本机编译器。
  • -xplatform:指定交叉编译器。


编译完成后会安装到Z:\qt-5.7.1下,拷贝到本机磁盘上即可。

善后工作

恢复 qmake.conf

恢复前面修改的mkspecs\linux-g++-64\qmake.conf文件内容,避免污染设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 这些仍然保留
QMAKE_CC = x86_64-linux-gnu-gcc
QMAKE_CXX = x86_64-linux-gnu-g++
QMAKE_LINK = x86_64-linux-gnu-g++
QMAKE_LINK_SHLIB = x86_64-linux-gnu-g++
QMAKE_AR = x86_64-linux-gnu-ar cqs
QMAKE_OBJCOPY = x86_64-linux-gnu-objcopy
QMAKE_STRIP = x86_64-linux-gnu-strip
QMAKE_NM = x86_64-linux-gnu-nm -P
QMAKE_RANLIB = x86_64-linux-gnu-ranlib

# 移除以下两行
DEFINES += QT_HAVE_POLL
QMAKE_LFLAGS += -L Z:/usr/lib/x86_64-linux-gnu

只保留工具链的设置即可。

qt.conf

在编译好的 Qt 库bin目录下创建名为qt.conf的文本文件,内容如下:

1
2
[Paths]
Prefix=..

这样才能正常在 QtCreator 中添加,否则会因为路径问题添加失败。

拷贝 GCC 运行时

moc.exeuic.exe等工具依赖 GCC 运行时,需要将 mingw32 的几个 DLL 文件拷贝到 Qt bin 目录下

  1. libgcc_s_seh-1.dll
  2. libstdc++-6.dll
  3. libwinpthread-1.dll

拷贝编译所需的 so 文件

编译项目时会发生符号链接错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: warning: libpthread.so.0, needed by C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Widgets.so.5.7.1, not found (try using -rpath or -rpath-link)
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: warning: libGL.so.1, needed by C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Widgets.so.5.7.1, not found (try using -rpath or -rpath-link)
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: warning: libdl.so.2, needed by C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1, not found (try using -rpath or -rpath-link)
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Gui.so.5.7.1: undefined reference to `glLoadIdentity'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_attr_setstacksize@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_setspecific@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_cancel@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `dlclose@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_create@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_key_create@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_key_delete@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `dlerror@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `dlopen@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Gui.so.5.7.1: undefined reference to `glMatrixMode'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_testcancel@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Gui.so.5.7.1: undefined reference to `glOrtho'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_condattr_setclock@GLIBC_2.3.3'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `dlsym@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Core.so.5.7.1: undefined reference to `pthread_once@GLIBC_2.2.5'
C:/cross-toolchain/Linux-x86_64/bin/../lib/gcc/x86_64-linux-gnu/15.1.0/../../../../x86_64-linux-gnu/bin/ld.exe: C:/qt5.7.1-x86_64-linux-gnu/lib/libQt5Gui.so.5.7.1: undefined reference to `glLoadMatrixf'

根据编译 Qt 时的参数,缺少的文件会不同,总之报错提示缺少什么文件就从sysroot中将对应的文件拷贝到 Qt lib 目录下并重命名。
缺少的.so文件都在Z:\lib\x86_64-linux-gnuZ:\usr\lib\x86_64-linux-gnu目录下。


记得在CMakeLists.txt文件中加入 lib 库的搜索路径

1
2
3
4
5
# 将 Qt lib 目录加入到搜索路径中,用 QtCreator 编译时 CMAKE_PREFIX_PATH 指向的是 Qt 根目录
target_link_directories(untitled PRIVATE ${CMAKE_PREFIX_PATH}/lib)

# 根据报错提示链接指定的库
target_link_libraries(untitled PRIVATE Qt${QT_VERSION_MAJOR}::Widgets pthread GL)

注意一个细节,虽然警告信息中的文件名是libpthread.so.0,但是我们手动链接时要移除后缀.0或其他数字,重命名为原始名称libpthread.so,这样才能在target_link_libraries语句中使用。
不需要手动链接的库就保持源文件名,如libdl.so.2之类的。

运行测试

在文章开始时说过,部署程序时只用拷贝项目文件即可,这要求在 Linux 系统上部署好 C++ 运行时和对应的 Qt 库。

编译其他模块

qtserialport模块为例

1
2
3
4
5
set PATH=C:\winlibs-gcc15.1.0\mingw64\bin;C:\cross-toolchain\Linux-x86_64\bin;%PATH%
cd C:\Qt\qtserialport-opensource-src-5.7.1
C:\qt5.7.1-x86_64-linux-gnu\bin\qmake.exe -spec linux-g++-64 QMAKE_CXXFLAGS+=--sysroot=Z: QMAKE_LFLAGS+=--sysroot=Z:
mingw32-make -j
mingw32-make install

sysroot根据模块情况可选添加并改为自己的映射路径。
编译成功后会安装到 Qt lib 目录下。

总结

  • 最终 Qt 库要在哪个系统上使用,就必须在该系统上编译制作,因为制作的第一步就是创建qmake,而qmake必须是能运行的可执行文件,比如你无法在 Linux 上编译qmake.exe文件。
  • Windows 下编译应该使用 msys2 环境,原生 cmd 下无法编译 Linux 特有的插件等库。
上一页
2025-08-10 10:23:34
下一页