Qt 5.15.16手动编译全程指南:VS2019环境配置与nmake避坑
简介QT 5.15.16 Windows编译库专为Win10VS2019环境下C跨平台开发者准备解决自行编译耗时长、依赖配置繁琐的问题。该版本支持32位与64位应用程序构建覆盖桌面、移动及嵌入式等开发场景可快速搭建原型或集成大型项目。包内共2000个文件以1548个h头文件为主体辅以20个JSON配置与2个pri工程文件压缩包约753MBzip格式便于部署分发。目录结构清晰include提供全部声明头文件lib存放可链接库plugins和bin包含扩展插件与运行工具涵盖QtCore、QtGui、QtWidgets等核心模块。下载后可在VS2019中直接引用集成省去从源码构建的复杂流程也可作为团队统一基础依赖减少因编译器差异导致的兼容问题。目前已有866人学习/浏览适合需要稳定、完整QT开发基础库的Windows开发者。1. Qt 5.15.16 手动编译为什么我不用现成安装包Qt 5.15.16 编译这行字背后是很现实的取舍官方安装包通常只提供固定几个版本和对应二进制一旦你需要某个补丁级版本或者想把 Qt 静态链接进离线设备唯一可靠的路就是自己拉源码编一遍。win10 vs2019 是最常见的宿主环境我最近给某内部工具做配套开发时刚好完整走过一遍。这篇按实际操作顺序写先讲环境准备和目录规划再拆 configure 的每个参数然后落到 nmake 编译与日志定位最后是几个容易翻车的现场和部署验证。适合第一次手动编译 Qt或者半路卡住想查原因的从业者。配置里的大部分坑追根到底都是工具链不一致这一件事。2. 编译前环境准备VS2019 组件、Python、Perl 与路径规划2.1 VS2019 组件清单MSVC v142、Windows 10 SDK 与调试器Qt 5.15.16 对应的是 MSVC2019 工具集 v142源码里的 mkspec 认win32-msvc。理论上 VS2022 的 v143 也能编出新库但我在实际项目里还是优先用 VS2019 装组件原因是二进制 ABI 和 Qt 自身的测试预期更一致能省掉不少玄学的链接告警。安装时不需要整个 VS 全家桶主要勾选“使用 C 的桌面开发”工作负载再按下面这张表核对。组件版本建议负责内容MSVC v142 - VS 2019 C x64/x86 生成工具14.2x 即可cl.exe 编译器、link.exe 链接器Windows 10 SDK10.0.19041 或更新系统头文件、rc.exe 资源编译器Windows SDK 调试工具可选dumpbin.exe、tracelog 等C 的 MFC/ATL 工具不需要就不要装与 Qt 构建无直接关系装完组件后第一时间用一个命令窗口验证三个 exe 是否都在 PATH 里where cl where rc where dumpbin逻辑说明cl找不到说明 VC 工具集没装好rc找不到说明 Windows 10 SDK 缺了资源编译器dumpbin后面查库位数会用到。三个命令只要有一个没输出就回到 VS 安装器把对应打勾项补上不要带病编译后面 configure 阶段的报错会非常误导人。参数说明where是 Windows 下查找可执行文件的命令类似 Linux 的which它输出完整路径时才算通过。2.2 辅助工具链Python 3.8、Perl 5.x 与 PATH 顺序Qt 5.15 的构建脚本对两种解释器有依赖Perl 用于处理 Unicode 数据表、部分代码生成器Python 用于新引入的一些辅助脚本。我用的组合是 Python 3.8 x64 和 Strawberry Perl 5.32编译多台机器都没出过问题。Python 版本不必严格卡 3.8但建议用 3.8/3.9 这类发布较早、兼容面宽的版本并且安装时选择“Add Python to PATH”省去后面手动配环境。Perl 这一项要特别留意。机器上如果装过 Git for Windows它的/usr/bin/perl版本可能偏老如果之前跑过其他项目装了 ActivePerlPATH 里又残留一条configure 检测到的可能是那个旧副本。更稳妥的做法是只保留一个 Perl并把它的 bin 目录放到 PATH 的最前面set PATHC:\Python38;C:\Strawberry\perl\bin;%PATH% where perl where python逻辑说明第一行把 Python 和 Perl 的目录插到系统 PATH 前面避免被其他同名 exe 截胡第二行确认实际命中路径。很多报错“Perl version 5.x or later is required”就是典型的 PATH 截胡不是你装错版本是系统先用到了别处的旧文件。参数说明C:\Python38和C:\Strawberry\perl\bin按实际安装位置改如果只装了一个解释器也可以不设 PATH 前缀直接确认 where 输出即可。注意不要同时开着多个命令行窗口改 PATH某些窗口会继承旧环境变量导致 configure 检测结果一会儿对一会儿错。2.3 源码目录与构建目录shadow build 是默认习惯Qt 5.15.16 源码解压后是一大坨目录顶层带 qtbase、qtdeclarative、qtwebengine 等子模块。很多人习惯在源码目录里直接 configure这样做会生成一堆 Makefile、.obj、.pch把源头目录搞得很脏以后想换个编译选项只能重新解压。我一般按 shadow build 的习惯把源码和构建产物分开mkdir C:\QtBuild\src-5.15.16 mkdir C:\QtBuild\build-5.15.16 mkdir C:\Qt\5.15.16逻辑说明第一个目录放源码解压结果第二个目录放 configure 生成的构建产物第三个目录作为-prefix安装终点。这样源码是只读的任何一组编译都发生在独立目录里想再来一份 debug 版就再开一个 build-debug 目录不用下载第二份源码。空间上完整构建包括 QtWebEngine 时中间文件加安装结果能到 40GB 以上即使-skip qtwebengine一个全模块 release 构建也最好预留 25GB 以上。Windows 的链接器在生成大文件时需要临时空间磁盘低于 5GB 时经常出现莫名其妙的 C1083 和 LNK1103看起来像代码问题实际上是空间不够。路径规则是底线源码目录、构建目录、安装目录都不能有中文不能有空格。我之前把源码放在C:\Users\张三\下载\qtconfigure 第一行就报“The system cannot find the file specified”但目录明明存在属于 cmd 对非 ASCII 路径的解析问题。从工具链到源码树一条纯英文路径能避免大量让人抓狂的报错。3. configure 参数逐条拆最小命令、模块裁剪与静态开关3.1 最小可用 configure 命令与 cmd 续行符configure.bat 是编译入口运行位置必须在 build 目录而不是源码目录。一个够用的命令长这样REM 切换到独立的构建目录 cd /d C:\QtBuild\build-5.15.16 REM 用绝对路径调用源码里的 configure.bat^ 是 cmd 换行符 C:\QtBuild\src-5.15.16\configure.bat ^ -prefix C:\Qt\5.15.16\msvc2019_64 ^ -opensource -confirm-license ^ -release -shared ^ -platform win32-msvc ^ -mp ^ -skip qtwebengine ^ -nomake examples -nomake tests逻辑说明这段命令的核心是让 configure 在 build 目录里生成构建系统。cd /d里的/d是为了跨盘符切换比如从 C 盘切到 D 盘不加/d会失效。每行末尾的^是 cmd 的续行符复制时行尾不能带空格否则会被当成参数的一部分。参数说明逐个看-prefix指定安装目录最好用最终要部署的路径-opensource -confirm-license跳过许可证交互-release只编 release 库体积和调试复杂度都友好-shared生成动态库-platform win32-msvc明确使用 MSVC 的 mkspec-mp让 MSVC 编译器以多进程方式编译-skip qtwebengine跳过 Chromium 那个大头-nomake examples -nomake tests不构建示例和测试。首次编译的人最容易漏掉-platform win32-msvc不写的话 configure 会尝试自动检测检测错环境后生成的 Makefile 用的是 MinGW 的 g后面 nmake 直接翻车。configure 跑完不是立刻出现 qmake.exe它只是生成顶层 Makefile 和各模块的配置文件真正编译出 qmake 是在 qtbase 模块里。看输出时重点看三个位置末尾的模块清单、有没有“QtWebEngine”相关警告、是否出现 “Qt is now configured” 字样。没看到这句话说明前面某个检查和模块依赖处理失败了不要继续走 nmake。3.2 模块默认构建与 -skip 的裁剪粒度Qt 5.15.16 默认会启用大部分子模块顶层 configure 一次把 qtbase、qtdeclarative、qtmultimedia、qtserialport、qtwebengine 这些都纳入 Makefile。对你可能没用的模块成了时间黑洞。我列出常用的裁剪对象模块默认状态什么时候值得跳过qtbase必选不能跳Qt 核心qtdeclarative默认不需要 QML/Qt Quick 时可以跳qtwebengine默认绝大多数场景都建议跳qtmultimedia默认纯工具类界面可跳qtdoc默认本地文档跳了不影响编译qttranslations默认多语言资源面向单一语言可跳假设你只想做非 QML 的界面可以在前面命令里追加-skip qtdeclarative -skip qtmultimedia -skip qtserialport -skip qtwebengine。这样 configure 输出的模块列表会短一截后续 nmake 的编译时长能下降不少。注意-skip的语义是“跳过默认组里的某个模块”不是“只编这几个模块”所以不要在命令里写成类似-skip everything之类的形式。这里还有一个粒度的坑-nomake管的是“编了库但不编 examples/tests”-skip管的是“整个模块都不编”。两者叠加使用时要先想清楚比如-skip qtdeclarative -nomake examples里的-nomake examples只对仍参与构建的模块生效不会重新把 qtdeclarative 的示例带回来。3.3 静态链接参数-static 的适用场景与限制默认-shared出来的是一堆 Qt5Core.dll、Qt5Gui.dll运行时靠 PATH 或者程序目录下的 DLL 解析。如果你要把程序扔到一台完全没有 Qt 环境的 Windows 设备上静态链接把 Qt 代码直接编进 exe部署时干净许多。把上一节的-shared换成-staticconfigure 就会把 Qt 编成静态库。静态方案带来的三个现实约束要提前知道。第一是体积一个带界面的 release 小工具直接膨胀 5 到 8 倍启动速度通常不劣化但分发包大了第二是插件处理动态构建时 Qt 在运行时扫 plugins 目录静态构建时平台插件必须编进库或者显式用Q_IMPORT_PLUGIN引入否则程序启动报“could not find the Qt platform plugin”第三是许可证对外闭源发布时Qt 开源版静态链接的条款要自己先确认清楚内部工具和自用场景通常不受影响但我不替任何人做这个判断。静态构建和第三方库的恩怨更明显OpenSSL、ICU 这类库也需要先编出对应的静态版本Qt 的 configure 才认。如果你只是想要一个小体积工具不如先-shared跑通再用后面的 windeployqt 拉依赖只有确定要脱离 Qt 运行环境再切-static。4. nmake 编译与续跑并行控制、日志定位和失败恢复4.1 编译前先激活 VS2019 环境vcvars64.bat编译 Qt 5.15.16 不能直接在开始菜单里随便开个 cmd。VS2019 安装完会提供“x64 Native Tools Command Prompt for VS2019”快捷方式其实质是先执行了 vcvars64.bat。我习惯手动开普通 cmd再自己调用一次call C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat where nmake where cl逻辑说明call是必须的直接执行 vcvars64.bat 的话批处理结束后环境变量不会留在当前窗口。VC 的安装路径因人而异Community 会换成 Professional、Enterprise、BuildTools 等目录以你自己机器上的实际路径为准。where nmake和where cl用来确认 PATH 里已经能看到这两个工具如果没输出后面 configure 或 nmake 第一步就会报不是内部命令。提示这份环境只在当前窗口有效。你每新开一个编译窗口都要重新 call 一次。我见过有人第一次配置完环境第二天重开机直接跑 nmake然后花半小时排查环境变量其实只是忘了激活。4.2 并行度选择-mp、nmake 与 jomconfigure 命令里的-mp只是给编译器加了一个多进程编译的开关nmake 本身还是单条 job 顺序调度。想真正并行常见做法是装 Qt 官方配套的 jom它兼容 nmake 的 Makefile 语法能按依赖关系同时启动多个编译进程where jom jom -j 8逻辑说明jom是 Windows 下的并行 make 工具读取的 Makefile 和 nmake 相同。-j 8表示同时跑 8 个编译进程一般取 CPU 物理核心数。我 8 核 16 线程的机器-j 8比-j 16更稳因为 Qt 的某些模块链接阶段会再起多个 link.exe内存占用会在最后几分钟突然冲高超过安全水位就出现疑似编译器崩溃。如果没装 jom用 nmake 会慢一些但一样能完成。内存小于 16GB 的机器上我不建议用 jomnmake 顺序编译反而更可控慢半小时无所谓崩一次重来可能得多花两小时。16GB 内存用-j 432GB 再上-j 8这是个人经验值不是公式。还有一个小技巧可以只编 qtbase 模块确认工具链稳定后再全量编nmake module-qtbase逻辑说明module-qtbase是顶层 Makefile 提供的目标只构建核心模块。如果你的应用主要用 Widgetsqtbase 编完就能开始跑 qmake 编译项目了qtdeclarative 等模块可以并行之后再说也方便在长编译之前排查工具链问题。4.3 中断后怎么续跑日志定位与增量恢复编译超过一个小时是常事中间可能因为内存不足、杀毒软件扫描、人为 CtrlC 中断。Qt 的 Makefile 基于文件时间戳做增量重新执行同样的命令会跳过已完成的源文件nmake 1 build.log 21 findstr /i : error build.log逻辑说明第一行把标准输出和错误输出都写进 build.log避免信息在屏幕上滚屏太快。第二行用findstr过滤出真正的错误行格式里包含: error的行可能是 “xxx.cpp(10): error C2065”也可能是 “LNK1120: error” 或者链接阶段的 “fatal error LNK”。只看错误行能快速定位第一个失败点。这里要说清一个顺序nmake 默认遇到第一个错误就停下来不要用findstr把所以 error 全列出来后猜测哪一个先发生而是修日志里时间最早的那个。错误往往是因果链第一个修完后续一长串可能自己消失。只有当你明确知道某个模块坏了、想继续编译其他模块时才用/K参数nmake /K module-qtbase参数说明/K让 nmake 在单个目标失败后继续处理其他独立目标它的副作用是会生成很多连带错误日志不适合日常排查。增量续跑的大前提是 configure 参数没有变。如果中间改过-prefix或-skip旧 Makefile 不会自己清理直接续跑会得到一份“新配置、旧产物”的混合体这时删掉整个 build 目录重新 configure 是唯一可靠做法。5. 避坑Qt 5.15.16 编译中的五个翻车现场5.1 现象提示 “nmake 不是内部或外部命令”原因直接打开了普通 cmd 或 PowerShell没有加载 VS2019 的工具链环境变量PATH 里找不到 nmake.exe。很多人 configure 阶段用的是同一个窗口所以没问题第二天新开窗口重编第一步就翻车。解决用“x64 Native Tools Command Prompt for VS2019”快捷方式或在当前 cmd 里先执行 vcvars64.bat然后用where nmake确认能找到。配置、编译、install 三件事必须保持在同一种环境里别一会儿 cmd 一会儿 PowerShell 混用。5.2 现象configure 报错 “Could not find a Perl interpreter” 或提示 Perl 版本过低原因机器上根本没有 Perl或者 PATH 里先命中了 Git for Windows 自带的旧 Perl。我遇到过一种情况系统装了 Strawberry Perl但环境变量里还残留着 ActivePerl 的 5.8 路径configure 检测到 5.8 版本后直接拒跑。解决where perl看实际命中的路径确认是 Strawberry Perl 的C:\Strawberry\perl\bin\perl.exe再查perl -v版本号。多版本并存时不建议动系统 PATH在当前窗口用set PATH...强制指定等编译结束这个窗口一关系统原样恢复。5.3 现象链接阶段一堆 LNK2001 / LNK2019错误里带 Qt5 字符原因最常见的是 build 目录不是全新目录旧 configure 产物和新配置混在一起。比如第一次用-release -shared跑了半小时半路改主意加-skip后再 configure旧 .obj 没有同步清理链接时符号定义和引用对不上。另一种是手动把 debug 版的 .dll 拷进 release 目录导致 QtCore 和 QtGui 的运行时不一致。解决改 configure 参数后不要只删 *.obj直接把 build-5.15.16 目录整体删掉再重建源码目录保持不动。这是最省时间的做法看似重复劳动实际上比对着 LNK2019 逐条猜快得多。手动拷 Qt 的 DLL 时一定要区分 Qt5Core.dll 和 Qt5Cored.dll带 d 后缀的是 debug 版混用后链接器会给出类似 “Qt5Core.dll 与 Qt5Cored.dll 同时存在” 的提示这时候就该怀疑运行库被混了。5.4 现象configure 刚开始就说 “The system cannot find the file specified”目录看起来明明存在原因源码路径或构建路径里有中文、空格、特殊符号cmd 和 Qt 的某些脚本对这部分路径解析异常。我当时把源码解压在 “C:\Users\张三\下载\Qt 5.15.16” 下路径带中文又带空格configure.bat 自己都定位不到自己。解决把源码、build、install 三个目录全部放到纯英文且无空格的路径下例如C:\QtBuild\src-5.15.16。顺便检查环境变量里的临时目录 TEMP/TMP 是否含中文个别机器的用户名为中文还会连累 NDK 之外的其他工具链。5.5 现象QtWebEngine 编译几小时后失败或者整机卡死原因QtWebEngine 默认参与构建它会拉进 Chromium 的构建流程对磁盘、内存、源文件数量要求都很高。很多失败不是你的 VS2019 配置错了而是模块本身太重32GB 内存在它面前也只是勉强够用。解决如果不需要内置浏览器能力在 configure 里明确写-skip qtwebengine这一项能把整体编译时间缩短一大半。如果确实需要内嵌 WebView不推荐在同样的 build 目录里混编单独给 QtWebEngine 留一个构建目录并且接受它需要数小时更轻的替代方案是用系统自带的 WebView 控件而不是把 Chromium 塞进 Qt 里。这个选择不是技术上的高下纯粹看维护成本。6. 验证与部署编译成果qmake、windeployqt 和一份 configure 留档6.1 用 qmake 验证版本与目标架构编译加安装完成后第一件事不是急着建界面而是验证安装目录里这套东西确实是你要的 5.15.16。打开编译时用过的 VS 命令行执行set PATHC:\Qt\5.15.16\msvc2019_64\bin;%PATH% qmake -query QT_VERSION qmake -query QT_INSTALL_PREFIX逻辑说明第一行把安装目录的 bin 加进 PATH两条qmake -query分别输出 Qt 版本号和安装前缀。版本号应显示5.15.16安装前缀应等于C:\Qt\5.15.16\msvc2019_64。如果第二条输出的路径和 configure 时-prefix不一致说明编译安装目录被移动过qmake 读到了旧属性。再确认库位数dumpbin /headers C:\Qt\5.15.16\msvc2019_64\lib\Qt5Core.lib | findstr machine逻辑说明dumpbin /headers输出可执行文件头的机器类型findstr machine只保留架构字段。x64 库应显示machine (x64)如果显示 x86说明你明明装了 64 位工具链却编出了 32 位库这在 Qt 5.15.16 里 possível尤其当-platform写成win32-msvc时容易混淆它代表的是目标机器类型不是位数。6.2 用 windeployqt 把最小程序跑起来验证通过后我会建一个最小的控制台工程主函数里只输出qVersion()然后用 qmake 编译最后用 windeployqt 拉依赖set PATHC:\Qt\5.15.16\msvc2019_64\bin;%PATH% windeployqt.exe release\app.exe逻辑说明windeployqt 会从安装目录自动复制 app.exe 需要的 Qt DLL以及 plugins 目录里的 platforms/qwindows.dll、styles 等。复制完必须检查 release 目录下有没有 platforms 文件夹没有的话程序双击启动时会弹 “could not find or load the Qt platform plugin”。这一步是把动态构建的 Qt 变成可分发程序的关键不要等到交付才想起来。6.3 我现在的固定收尾动作我第一次编 Qt 时把 configure 命令写在临时记事本里三个月后要重编版本不记得参数也不记得只能对着源码反推。从那以后我每次编译都会在同一目录下留一个 README.txt里面写上 configure 参数、VS 工具集版本、Python 和 Perl 版本、以及编译时额外踩过的坑。重编时直接照着跑不重新试错。qmake 安装路径被移动时可以通过 qt.conf 重新指定 prefix但最稳的还是 configure 时一锤定音编完不搬目录。希望帮到你。本文还有配套的精品资源点击获取