之前写过一篇 VS2017 编译 Qt 5.7.1 文章介绍了 Qt 的编译方式。为了支持 XP 系统,不得不使用 VS2017 来编译,这带来一个问题:无法享受 C++ 20 以后的现代式编程。
好在有 YY-Thunks 这个神器可以解决 XP 缺失一些 API 的问题。
总体的编译流程和之前差不多,只是一些配置细节不同。
准备
Qt 5.7.1:https://download.qt.io/new_archive/qt/5.7/5.7.1/submodules/
VC-LTL5 v5.2.2:https://github.com/Chuyu-Team/VC-LTL5/releases/tag/v5.2.2
其中 VC-LTL5 是可选的,用了它后可以让 Qt 和应用程序共享 crt 了,这样可以减少程序的体积。
不过要注意的是,引入 VC-LTL5 后如果模块(DLL)之间存在互相访问 C++ 数据类型的话,则双方都要引入 VC-LTL5,否则会引发内存访问异常。
编译 qtbase
我不喜欢下载完整的源码编译,太笨重了,我更喜欢按需编译,只编译用到的部分。
下载 qtbase-opensource-src-5.7.1.7z 并解压。
编辑 msvc-desktop.conf
在DEFINES
后追加_WIN32_WINNT=0x0501
,避免使用 Vista 系统后才有的 Win32 API
1 | DEFINES += UNICODE WIN32 _UNICODE _WIN32_WINNT=0x0501 |
要在 XP 系统上运行,则必须将子系统版本改为5.01
,在任意位置插入QMAKE_SUBSYSTEM_SUFFIX=,5.01
1 | QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE |
-MD
改为-MT
,这样编译出的 Qt DLL 文件就不依赖VC运行库了
1 | QMAKE_CFLAGS_RELEASE = -O2 -MT |
如果不希望产生 .pdb 文件,则可以将-Zi
去掉,并找到QMAKE_LFLAGS_DEBUG
1 | QMAKE_LFLAGS_DEBUG = /DEBUG |
改为
1 | QMAKE_LFLAGS_DEBUG = /DEBUG:NONE |
编译
启动 VS2022 32位命令行工具
1 | "%programfiles%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars32.bat" x86 |
_FILE_ID_128 类型重定义
这是第1个错误
1 | C:\Qt\qtbase-opensource-src-5.7.1\src\corelib\io\qfilesystemengine_win.cpp(629): error C2011: “_FILE_ID_128”:“struct”类型重定义 |
找到qfilesystemengine_win.cpp
第629
行:
1 | // MinGW-64 defines FILE_ID_128 as of gcc-4.8.1 along with FILE_SUPPORTS_INTEGRITY_STREAMS |
因为新SDK中已经有定义了,所以会提示重定义错误,直接删除这一段即可。
“binary_function”: 不是 “std” 的成员
这是第2个错误
1 | C:\Qt\qtbase-opensource-src-5.7.1\src\tools\qlalr\compress.cpp(40): error C2039: "binary_function": 不是 "std" 的成员 |
解决方法:在compress.cpp
中添加头文件#include <functional>
。
缺少 tmschema.h
这是第3个错误
1 | C:\Qt\qtbase-opensource-src-5.7.1\src\widgets\styles\qwindowsxpstyle_p_p.h(64): fatal error C1083: 无法打开包括文件: “tmschema.h”: No such file or directory |
这个头文件仅在 SDK v7.1A 中才有。可以从 v7.1A SDK 中提取出这个头文件,或从这里下载 https://github.com/tpn/winsdk-7/raw/refs/heads/master/v7.1A/Include/Tmschema.h 文件,将它放build\include
目录中即可。
“NIIF_USER”: 未声明的标识符
这是第4个错误
1 | C:\Qt\qtbase-opensource-src-5.7.1\src\widgets\util\qsystemtrayicon_win.cpp(262): error C2065: “NIIF_USER”: 未声明的标识符 |
这3个宏是 Vista 后才有的,在qsystemtrayicon_win.cpp
文件中追加即可:
1 |
缺少 RtlCaptureStackBackTrace
这是第5个错误
1 | C:\Qt\qtbase-opensource-src-5.7.1\src\testlib\qtestcase.cpp(1578): error C3861: “RtlCaptureStackBackTrace”: 找不到标识符 |
这个错误在以前的文章中提到过,在qtestcase.cpp
文件中加入以下声明:
1 | extern "C" __declspec(dllimport) USHORT WINAPI RtlCaptureStackBackTrace( |
编译其他模块
qtbase
只够满足编译最基础的 Qt 程序,缺少了设计师、预言家等工具,一般至少还需要编译配套工具和多语言:
编译模块的方法:进到模块根目录后依次执行
1 | "%programfiles%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars32.bat" x86 |
分发
使用configure -prefix "C:\qt5.7.1-vc144-i386" ...
命令来配置Qt的编译时,这个绝对路径会被硬编码到编译出来的多个关键文件中,其中最重要的就是 qmake.exe。
当其他人将这个编译好的Qt包解压到其他路径(例如 D:\Qt\)下,然后尝试在Qt Creator中添加这个Qt时,Qt Creator会执行 D:\Qt\bin\qmake.exe 来查询Qt的配置信息。然而,qmake.exe 内部记录的路径仍然是编译时的 “C:\qt5.7.1-vc144-i386”。
Qt Creator发现 qmake 报告的路径和 qmake 自身的实际路径不符,并且在报告的路径下找不到必需的文件,因此判断这是一个损坏或无效的Qt版本,从而给出 “Invalid Qt version” 的错误。
解决方法,手动创建一个qt.conf
文件放到bin
目录下,文件内容是:
1 | [Paths] |
这个配置文件会告诉bin
目录中的所有Qt工具(如 qmake.exe, moc.exe, windeployqt.exe 等),Qt的根目录(Prefix)不再是编译时硬编码的绝对路径,而是当前目录的上一级目录。