VS2017 配 Qt5.14 这件事,听起来像是"装个插件、指一下 qmake 路径"就能收工的活,真动手做的时候,八成时间都花在跟版本号较劲上:装完插件菜单没出来、工程建好了死活找不到头文件、链接阶段一片 LNK2019、编译过了双击 exe 又弹"缺少 Qt5Cored.dll"。这些问题单独拎出来都不难,但它们会在同一次配置里排队出现,新手很容易在第三个坑的位置就放弃,转头去装 Qt Creator 了。
这篇内容围绕VS2017 + Qt5.14这套组合,把我从零开始配通的完整过程拆开讲:为什么这两个版本的搭配是"原配"、VS2017 侧要提前确认哪些组件、Qt 安装包里哪些勾选项是负担、Qt VS Tools 的版本对应关系、Qt Versions 每一栏该填什么、模板工程生成出来后要检查什么,以及各类报错背后的真实根因。适合手上已经有 VS2017、要在 Windows 上做 C++ 桌面开发的读者,也适合从 Qt Creator 迁移过来、想用 VS 的调试器和debugger生态但不想重装工具链的人。下面按配置的先后顺序展开,中间穿插几张报错对照表,方便你直接按现象查原因。
1. 先搞清楚哪套 Qt5.14 预编译包是为 VS2017 准备的
1.1 Qt 官方 Windows 包里那几个 msvc 目录分别对应谁
去 Qt 的下载页找 Qt5.14.2 的 Windows 包,你会看到同一个版本下面挂着好几个 msvc 前缀的组件,比如MSVC 2017 32-bit、MSVC 2017 64-bit,有些小版本还会顺手带上MSVC 2015 32-bit/64-bit。这些不是"随便选一个都行"的同义词,它们是用不同版本的编译器编译出来的预编译二进制,里面的导入库、DLL、调试版 DLL 都是成对的。你把 VS2017 的工程指到 msvc2015 那一套上,多数时候也能链上(后面讲 ABI 的时候会解释原因),但你就主动放弃了"官方说明里明确支持的组合"这个安全垫。
这里有个很实际的推论:Qt5.14 时代官方给 Windows 桌面端准备的预编译包,就是把 VS2017(以及更早的 VS2015)当成主力编译器的。也就是说,你在 VS2017 上配 Qt5.14,用的是"别人已经替你编译好、并且官方在持续验证"的那一份二进制,不需要自己从源码 build,也不用担心某个模块漏编。这一点对刚开始做项目的团队特别重要——自己编译 Qt 是另一个量级的工作,光是 configure 那一长串参数就够研究一整天,而且 WebEngine 这类模块的编译时间可以按小时计。
另外要留意的是 32 位和 64 位的区别。Qt5.14 的 32 位和 64 位包是两个完全独立的目录,导入库不通用,DLL 也不通用。你如果在 Qt 安装时只勾了MSVC 2017 64-bit,但模板工程默认生成的是 Win32 平台配置,那第一次编译必然失败。我的建议是:如果你的项目没有必须用 32 位的理由(比如要调用某个只有 x86 版本的旧 SDK、或者要跟 32 位的第三方 DLL 对接),直接上 64 位,勾选和工程配置都能少一半事。
1.2 MSVC 2015/2017/2019/2022 的 ABI 兼容边界
很多人被"VS 版本必须严格一一对应"的说法吓到,其实 MSVC 的 C++ 运行时从 VS2015 到 VS2022 是刻意保持了二进制兼容的(v140、v141、v142、v143 的 CRT 是向下兼容的关系)。这意味着用 msvc2017 编译出来的 Qt 库,理论上可以直接被 VS2019 或 VS2022 编译的工程链上去,Qt VS Tools 里也能正常配置。搜索热词里那种"高版本 VS 编译低版本工具集产物"的场景——比如在 VS2022 里编译用 VS2017 工具集生成的目标模块——本质上依赖的就是这条兼容规则。
但"能链上"和"该这么干"是两件事。我在实际项目里踩过的坑是:主工程用 v142 编译,链接了一个 v141 编译的第三方静态库,而这个静态库内部又依赖特定版本的 CRT 行为(比如某些 locale 相关的函数、或者 STL 容器的内存分配器跨模块传递),运行期就会出现一些极难定位的崩溃或者内存告警。所以我的实践原则是:
- Qt 用哪个 msvc 包,工程就尽量用同代工具集。VS2017 就用 v141,别为了"顺手"去切 v142。
- 如果确实要用高版本 VS 打开老工程,先在项目属性里把平台工具集固定成 v141,确认能正常编译再考虑升级。
- 混合工具集的项目,把所有模块的
/MD、/MDd运行时库设置统一,不要出现一部分静态 CRT、一部分动态 CRT 的情况。
顺带说一句,VS2017 里能不能装 v141 工具集,取决于你当时的安装选项。如果你安装 VS2017 的时候只勾了默认组件,后面再用 VS2022 的安装器去管理,可能发现 v141 不在列表里,需要单独补装"MSVC v141 - VS2017 C++ x64/x86 生成工具"。这个组件装不上,Qt 配好了也编不过。
1.3 什么情况下该掉头去选 Qt5.12.10
热词里出现"VS2017 + Qt5.12.10"这种组合不是偶然。Qt5.12 是 LTS(长期支持)版本,5.12.10 是这个系列的收尾版本,修掉了大量早期问题;而 Qt5.14 是常规发布版本,生命周期短,官方不会为它长期回补安全与兼容性修复。所以选型时我的判断标准是这样的:
| 场景 | 建议版本 | 理由 |
|---|---|---|
| 企业内部长期维护的工具、要发布给客户 | Qt5.12.10 或更高的 LTS 线 | 补丁可预期,第三方库兼容验证充分 |
| 学习、做 Demo、跟进较新特性 | Qt5.14.2 | 语法和 API 较新,预编译包齐全 |
| 需要 Qt Quick 的新特性或较新的 WebEngine | Qt5.14.2 | 5.12 线在部分模块上偏旧 |
| 项目已经跑在 5.12 上且稳定 | 不升 | 升级收益小于回归风险 |
如果你的目标只是"把 VS2017 + Qt 跑通",那么 5.12.10 和 5.14.2 在配置流程上是完全一致的,Qt VS Tools 里换个 qmake 路径就行。真正会让人卡住的是混装:同一台机器上装了 5.12 和 5.14 两套,Qt Versions 里配了名字很接近的两条记录,工程里选错了一条,症状就是头文件能找到、链接却报符号缺失,或者反过来。这个坑后面第六章会详细说。
2. VS2017 这一侧要提前确认的三件事
2.1 离线安装包里到底该勾哪些组件
VS2017 最省事的装法是用官方安装器在线装,但很多人(尤其是内网环境)需要离线包。离线包的做法是在能联网的机器上用安装器加--layout参数把安装文件下载到本地目录,再把整个目录拷到目标机器,运行目录里的安装程序。这里我不展开命令行细节,重点是离线包的组件选择要在下载阶段就定下来,因为离线布局只包含你当时勾选的东西,事后再想加组件就得重新下载。
针对 Qt 开发,VS2017 侧至少要有这些:
- 工作负载里的"使用 C++ 的桌面开发"。
- 单个组件里的
MSVC v141 - VS2017 C++ x64/x86 生成工具(这是 v141 工具集本体)。 - 一个 Windows 10 SDK(版本可以选当前主流的,注意 SDK 版本决定了你能用的 Windows API 和部分头文件)。
Windows 10 SDK对应的调试工具(调试时查看调用堆栈、加载符号会用到)。- 如果要做界面以外的活儿,比如调 PaddleOCR 之类的推理库,还需要对应的 C++ 运行库和 CMake 支持;Paddle 的 C++ 推理库在 Windows 上通常以预编译包形式提供,需要匹配你的工具集与位数,配置流程跟 Qt 类似,都是"包含目录 + 库目录 + 附加依赖项"三件套。
有个容易被忽略的细节:VS2017 社区版对个人开发者和小团队是免费使用的,商业环境下的授权问题建议按贵司的合规流程走,不要图省事绕开。我在团队里推工具链的时候,第一件事就是把版本和授权这两件事在群里说清楚,后面省掉很多麻烦。
2.2 确认 v141 工具集和 Windows SDK 真的装上了
装完之后别急着装 Qt,先做一次自检:打开 VS2017,新建一个空的 C++ 控制台工程,项目属性里看"平台工具集"下拉框里有没有Visual Studio 2017 (v141)。如果只有 v140 或者根本没有选项,说明工具集没装全。接着编译一个 hello world,确认能过,这一步是排除"VS 本身就有问题"这个变量。
再确认 SDK:项目属性里"Windows SDK 版本"应该有一个默认值,如果你安装了多个版本,这里可以切换。有些第三方库(比如某些版本的 OpenCV、Paddle 的预编译包)对 SDK 版本有隐含要求,版本太新或太旧都可能报找不到某个头文件。我的习惯是在团队统一一个 SDK 版本号,写进项目文档,避免每个人机器上默认 SDK 不同导致"我这里能编,你那里编不过"。
2.3 顺便说下插件生态:Visual Assist 和 Qt VS Tools 的共存
VS2017 时代很多人会装 Visual Assist(VAX)来做代码补全和重构,热词里也能看到"VS2017 assist 插件"的搜索。VAX 和 Qt VS Tools 在绝大多数情况下能和平共处,但有两个已知的相互影响值得提一句:
一是VAX 的解析器需要知道 Qt 的头文件路径,否则它会把Q_OBJECT、signals、slots这些宏标成错误。VS2017 环境下 Qt VS Tools 会把包含目录注入到工程属性里,VAX 通常能读到;如果发现 VAX 报一堆红色波浪线但编译正常,去 VAX 设置里手动补一下 Qt 的 include 目录,或者让它重新解析工程。
二是插件加载顺序和启动性能。同时装了好几个大插件,VS2017 启动会明显变慢,调试大工程时偶尔出现"扩展导致 UI 卡住"的情况。如果遇到莫名其妙的界面问题,先用devenv /safemode启动一次,确认是不是插件引起的,再逐个禁用排查。
3. Qt5.14.2 安装时的组件勾选与目录规划
3.1 组件勾选清单:哪些必装,哪些是负担
Qt 的 Windows 离线安装器是个"全家桶",默认勾选的东西能装出好几个 G。针对 VS2017 + MSVC 的使用场景,我一般这样勾:
必装:
Qt 5.14.2下的MSVC 2017 64-bit(主用),如果项目需要 32 位再加MSVC 2017 32-bit。Qt Debug Information Files——只在需要调试进 Qt 源码内部时才需要,体积不小,但排查崩溃时很有用。装不装看你有没有"要打断点进 QWidget 内部"的需求。Qt Creator:很多人觉得用 VS 就不需要 Creator 了,我建议留着,因为在 Creator 里看.ui的实时预览、跑 qmake 检查环境变量、快速验证一段 Qt 代码是否正常,都比在 VS 里折腾快。
按需:
Qt Charts、Qt Data Visualization:做数据可视化的项目要。Qt WebEngine:嵌入浏览器内核的项目要,注意它体积巨大,而且 Windows 上基本只有 64 位预编译可用。Qt Virtual Keyboard:嵌入式触屏项目常见。Sources:想阅读 Qt 源码、或者要自己编译某个模块时勾上。MinGW 7.3.0:如果你同时想用 MinGW 工具链做对比测试就勾,纯 MSVC 环境可以不装,能省一个 G 左右。
不用装:
UWP、Android相关组件:除非你真做那类项目。Qt Installer Framework:做安装包的时候再说。
3.2 安装路径、PATH 与多版本共存
安装路径我强烈建议不要带空格、不要带中文,像是D:\Qt\Qt5.14.2这种就很好。默认的C:\Qt也行,但如果你打算同时装多个 Qt 版本(5.12.10 和 5.14.2 共存是很常见的),用一个统一的根目录、每个版本一个子目录,管理起来最清楚:
D:\Qt\ Qt5.12.10\ 5.12.10\msvc2017_64\bin\qmake.exe Qt5.14.2\ 5.14.2\msvc2017_64\bin\qmake.exe注意那个多出来的一层版本号目录,这是安装器自己的结构,别觉得奇怪。
关于 PATH:不要把两个 Qt 版本的 bin 同时塞进系统 PATH。Qt 的 DLL 名字在不同小版本之间是一样的(Qt5Core.dll),PATH 里先找到哪个就用哪个,很容易出现"我明明编译的是 5.14,运行起来加载的是 5.12 的 DLL"这种诡异情况。我的做法是系统 PATH 里不放 Qt,需要的时候靠 Qt VS Tools 在调试会话里注入,或者用脚本临时设置。打包发布时用 windeployqt 把依赖拷到 exe 旁边,也就不依赖 PATH 了。
3.3 用 qmake -v 做一次最小验证
装完之后别急着开 VS,先在命令行做一次最小验证:
D:\Qt\Qt5.14.2\5.14.2\msvc2017_64\bin\qmake.exe -v正常输出会告诉你 qmake 用的是哪个版本的 Qt、以及它对应的编译器是 MSVC 的哪一代。这一行输出是你后面配 Qt VS Tools 时要填路径的直接依据,务必确认路径里的msvc2017_64跟你工程的目标平台一致。如果这里报找不到某些 DLL,说明安装不完整,先解决这一步再往下走。
验证完还可以顺手跑一次qmake -query,输出里会有QT_INSTALL_PREFIX、QT_INSTALL_BINS、QT_INSTALL_HEADERS等路径。以后遇到"头文件找不到"的报错,先看 qmake 报的这些路径是不是你期望的位置,能省很多排查时间。
4. Qt VS Tools:插件版本、安装方式与 Qt Versions 配置
4.1 版本对应关系:为什么别盲目装最新
Qt VS Tools(老版本里叫 Qt5Package、Qt VS Add-in)是让 VS 认识 Qt 工程的关键。它的版本和 VS 版本之间存在对应关系,越新的插件版本对 VS2017 的支持越弱,这不奇怪,毕竟 VS2017 已经很老了,官方把精力放在 VS2019/2022 上是正常的。所以你在 Qt 官方下载页的"Qt Visual Studio Tools"区域里,会看到一长串.vsix文件,文件名里通常带着msvc2017、msvc2019、msvc2022这样的标识。
我的实操建议是:先看文件名里带 msvc2017 的那几个,再用 2.4.x 或 2.5.x 这两个大版本。这两个版本在我手上过 VS2017 是最稳的,向导、Qt Versions 配置、.ui编辑、moc 自动生成全都正常。如果你装了明显更新的版本,可能会遇到:安装时报兼容性警告、装完菜单项不出现、或者工程属性页里 Qt 相关的选项卡直接消失。
热词里"VS2017 Qt 5.12.10 插件"这个搜索大概率也是同一个问题——大家在找"哪个版本的 Qt VS Tools 能装在 VS2017 上"。答案的思路是一样的:先按 VS 版本筛,再按需选较新的稳定版。
4.2 两种安装方式与安装后的确认动作
安装方式有两种,我都用过:
方式一:VS 内扩展市场。打开 VS2017,工具 → 扩展和更新 → 联机 → 搜索 Qt,找到 Qt Visual Studio Tools 安装。优点是版本自动匹配;缺点是内网环境打不开市场,而且推荐给你的版本可能已经不支持 VS2017。
方式二:手动装 vsix。从 Qt 官网下载对应的.vsix,关闭所有 VS 进程,双击安装。如果双击没反应或者被识别成别的 VS 版本,用命令行装:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VSIXInstaller.exe" qt-vsaddin-msvc2017-2.4.3.vsix注意路径要按你实际的 VS 版本(Community / Professional / Enterprise)改。装完之后一定要重启 VS,而且要看菜单栏有没有多出Qt VS Tools这一项。没有这一项,后面所有配置都无从谈起,先解决它。
这里插一个排查点:如果同时装了多个 VS 版本,.vsix可能会被装到多个实例上,而 Qt VS Tools 的 Qt 版本列表是按用户账户保存的机器级配置,但工程里选了哪个 Qt 版本是跟着工程文件走的。这会导致一个很典型的现象:同事把工程发给你,你打开后报 "There's no Qt version assigned to this project for platform x64",原因是他工程里写的 Qt 版本名字是Qt5.14.2_msvc2017_64,而你机器上没有这个名字的记录。解决办法就是你在自己的 Qt Versions 里新建一条名字完全一样的记录,指向你本机的 qmake。
4.3 Qt Versions 里那几栏到底填什么
打开Qt VS Tools→Qt Versions(老版本叫Qt Options),你会看到一个列表和几个按钮。点 Add 新建一条:
- Name(名称):这是给你自己看的,但也是写进工程文件里的字符串。命名上我推荐带全信息,比如
Qt5.14.2_msvc2017_64,一眼看出 Qt 版本、编译器代次、位数。别用"Qt1""test"这种名字,工程一多你会记不清。 - Path(路径):指到 qmake.exe 所在目录,通常是
...\msvc2017_64\bin。有的版本要求指到目录,有的接受直接选 qmake 文件,按界面提示来。 - 默认版本(Default):列表里可以设一个默认,新建工程时会自动用它。建议把最常用的那个设成默认。
配好之后,点击 OK,回到工程上做一次绑定验证:右键工程 →Qt Project Settings→ General 选项卡里的Qt Installation下拉框,应该能看到你刚建的版本。把 Debug|x64 和 Release|x64 两个配置都确认一遍——这个设置是按平台/配置组合保存的,只设了 Debug|x64,切到 Release 就会报 "no Qt version assigned"。
还有一点值得提醒:如果你发现 Qt Installation 下拉框是空的,别急着重装插件。先关掉 VS,把%LOCALAPPDATA%\QtMsBuild这个目录删掉,再打开 VS 让它重新释放一遍构建脚本。这个目录是 Qt VS Tools 存放 moc、uic、rcc 的 MSBuild targets 的地方,插件升级、或者 Qt 版本换路径之后它经常"缓存变味",删掉重建能解决大半的诡异问题。这一招我从 2.x 用到现在的版本,命中率非常高。
5. 第一个工程:从模板生成到跑通调试
5.1 模板生成出来的东西都有什么
配置好之后,新建工程:文件 → 新建 → 项目 → Visual C++ → Qt →Qt Widgets Application(做 QML 项目就选Qt Quick Application)。填名字、选路径,向导会让你选需要哪些基础类,勾上 Core / GUI / Widgets 就够了。
生成出来的工程结构大致是这样的:
main.cpp:包含QApplication的创建、主窗口的实例化与show()。mainwindow.h/mainwindow.cpp:主窗口类,头文件里有Q_OBJECT宏。mainwindow.ui:界面描述文件,XML 格式。.vcxproj/.sln:VS 的工程和解决方案文件,Qt 相关的属性会写进 vcxproj 里。
第一件要做的事,是在mainwindow.h里看到Q_OBJECT宏的状态。如果 VS 把它标成红色波浪线,但编译能过,那是 VAX 或者 IntelliSense 没解析到 Qt 的头文件,属于显示问题,不影响构建。真正的构建失败会以错误列表里的 C 开头或 LNK 开头的编号出现。
5.2 Qt Project Settings 各选项卡在管什么
Qt Project Settings 是这套工具链里最该花时间摸清楚的界面,理解它之后,百分之八十的"莫名其妙"都能自己定位:
- General:核心是 Qt Installation。这里选错了 Qt 版本,后面的包含目录、库目录全都会指到错误的路径上。
- Qt Modules:勾选你要用的 Qt 模块,Core、Gui、Widgets、Network、Sql、Charts 等等。每勾一个模块,链接器的附加依赖项里就会多出对应的库(Debug 配置下是带 d 后缀的版本,比如
Qt5Cored.lib)。这是新手最容易漏的地方:代码里#include <QtNetwork/QTcpSocket>写得好好的,编译过了,链接报一堆未解析符号,原因就是没勾 Network 模块。 - moc / uic / rcc 相关选项卡:这些控制的是元对象编译器、界面编译器、资源编译器的参数,比如额外的包含路径、命令行参数、输出目录。绝大多数项目保持默认即可,只有在写自定义插件、或者有特殊的编译期宏时才需要动。
关键是理解一件事:这个界面改的不是"某个开关",而是它会把结果写进.vcxproj,也就是说这些配置是可以提交到版本库、被团队共享的。理解这点之后,你就能解释为什么"我改了 Qt 版本,同事拉下来还是老样子"——他需要重新打开工程让 VS 读到新的 vcxproj。
5.3 平台下拉框、PATH 与调试启动的关系
VS 顶部的平台下拉框(x86 / x64)决定的是编译器生成的位数,而 Qt Installation 是按这个平台分别配置的。这是"配了 Qt 还是报 no Qt version assigned"的头号原因。
调试阶段还有一个隐形的便利:用 VS 的 F5 启动时,Qt VS Tools 会自动把 Qt 的 bin 目录加到调试进程的 PATH 里,所以你能正常跑起来。但如果你去x64\Debug目录里直接双击那个 exe,就会发现它找不到Qt5Cored.dll。这不是工程配置错了,而是环境变量没设。理解这个区别很重要——很多人在这一步慌了,以为工程有问题,其实只是发布时要处理依赖。
想验证也很简单:把 exe 需要的几个 DLL 从 Qt 的 bin 目录拷到 exe 旁边,再双击,如果正常启动,那就确认是 PATH 与依赖部署的问题,不是构建问题。
6. 报错对照表:踩过的坑和它们的根因
6.1 六类高频报错的现象、根因与修复
下面这张表是我这些年攒下来的,按出现频率排的。遇到问题先对号入座,别一上来就重装插件。
| 现象 | 真实根因 | 修复动作 |
|---|---|---|
There's no Qt version assigned to this project for platform x64 | 当前平台/配置没绑定 Qt 版本;或工程来自别人机器,版本名对不上 | Qt Project Settings 里为该平台选 Qt 版本;名字对不上就新建同名记录 |
无法打开包括文件QtWidgets/QApplication | 包含目录没注入,通常是 QtMsBuild targets 没加载 | 确认 Qt Installation 生效;删除%LOCALAPPDATA%\QtMsBuild重开 VS |
LNK1104无法打开文件Qt5Core.lib | Qt Modules 没勾 Core;或库目录指向另一个 Qt 版本;或位数不匹配 | 检查模块勾选、检查 Qt 版本路径里是 32 还是 64 位 |
LNK2019无法解析的外部符号__imp_... | 工程与 Qt 的位数不一致;debug 工程链了 release 库;工具集混用 | 统一平台位数,统一 Debug/Release,工具集统一 v141 |
启动提示no Qt platform plugin could be initialized | exe 同级缺少platforms\qwindows.dll | 从 Qt 的plugins\platforms拷贝,或用 windeployqt |
提示缺少Qt5Cored.dll | 直接双击运行,PATH 里没有 Qt 的 bin | 加 PATH,或把依赖拷到 exe 旁边 |
用这张表的时候有个技巧:从最后一条现象往前推。比如LNK2019报的是某个QString相关的符号找不到,那基本可以断定是位数或 Debug/Release 的问题,因为你不会忘记勾 Core 模块(不勾 Core,连QApplication都找不到,错误会更靠前)。
6.2 debug/release 混用引发的连锁反应
这是我觉得最值得单独讲的一个坑。Qt 的官方 msvc 包同时提供 Debug 和 Release 两套库(Qt5Cored.lib/Qt5Core.lib),工程在 Debug 配置下会链接带 d 的那套。如果你在 Release 配置里手动加了一个来自 Debug 目录的库,或者在 Debug 配置里加了一个 release 版本的第三方库,症状通常是:
- 编译阶段一切正常,链接阶段报一堆符号缺失;
- 或者链接通过,运行到某个 Qt 容器操作时直接崩;
- 更隐蔽的是,程序能跑,但在退出时崩溃,因为跨模块的内存分配和释放用了不同的堆。
排查方法很土但有效:打开项目属性的"链接器 → 输入",把附加依赖项完整看一遍,凡是 Debug 配置里出现不带 d 的 Qt 库,或者 Release 配置里出现带 d 的,都是可疑对象。另外检查"链接器 → 常规 → 附加库目录"里有没有残留一个指向 Debug 目录的路径。Qt VS Tools 自动生成的依赖一般是对的,出问题的往往是你后来手动添的那些。
6.3 中文乱码、/utf-8 与高 DPI
中文乱码这个坑跟 Qt 关系不大,但和 MSVC 关系很大。MSVC 默认按系统本地代码页(简中环境是 GBK)解释没有 BOM 的源文件,而 Qt5 在把窄字符串转成QString时按 UTF-8 处理。两边标准不一致,结果就是界面上的中文变成一堆问号或者方块。
三种解法,我推荐第三种:
- 把源文件保存成"UTF-8 带 BOM",MSVC 看到 BOM 就知道按 UTF-8 解析。
- 显式用
QString::fromLocal8Bit("中文"),在 GBK 源文件下能正常,但换环境就崩。 - 在项目属性 → C/C++ → 命令行里加
/utf-8,让编译器统一按 UTF-8 处理源文件和执行字符集。这个设置对一个团队来说最容易统一,也是我在所有新工程里的默认动作。
高 DPI 是另一个必踩的点。Qt5.14 在 4K 屏上默认可能界面糊或者控件尺寸不对,需要在main()里、在构造QApplication之前设置:
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication app(argc, argv);顺序写反了是不生效的,这点很关键。Qt5.14 也支持用环境变量QT_ENABLE_HIGHDPI_SCALING=1控制,临时验证时比较方便。
7. .ui、.qrc 与 moc:VS 里这些文件是怎么被处理的
7.1 .ui 文件在 VS 里的两种打开方式
在 Qt Creator 里双击.ui就是设计器,在 VS 里这事稍微绕。装了 Qt VS Tools 之后,双击工程里的.ui文件,通常会在 VS 内部以文档窗口的形式打开 Qt Designer 的界面,可以拖控件、改属性、连信号槽。这条路能走通的前提是插件版本和 VS 版本匹配,插件加载正常。
如果双击打开的是 XML 文本,或者报了"无法加载设计器",两个备选方案:
- 在文件上右键,选"打开方式",找到
Qt Designer(安装 Qt 时附带的designer.exe,在 Qt 的 bin 目录下)。 - 直接用 Qt Creator 打开这个
.ui单独编辑,保存后回到 VS 编译,两边不会冲突。
要理解的是,.ui文件在构建时会被 uic 工具转成一个ui_xxx.h头文件(一般生成在中间目录里),你的mainwindow.cpp里#include "ui_mainwindow.h"用的就是它。所以改了.ui之后必须重新编译,界面才会变;有时候界面没更新,是因为增量编译没识别到文件变化,清理后重新生成就好。
7.2 .qrc 资源与 rcc 的生成时机
.qrc是 Qt 的资源描述文件,用来把图片、图标、翻译文件、样式表打包进 exe。它的处理链是:rcc 把.qrc里列出的文件编译成 C++ 源码,再参与链接。这个过程对使用者是透明的,但有两个需要注意的点:
第一,加入.qrc的文件在工程里是"外部文件",VS 的解决方案资源管理器里可能看不到它们(除非手动加到筛选器里),但它们在编译时会被读取。路径写错了(尤其是相对路径)会报找不到文件,而且报错信息有时候不太直观。
第二,资源文件改动后同样要重新编译。如果你替换了一张图片,界面上还是旧的,先确认是不是资源没重新生成。另外.qrc里路径写错大小写,在 Windows 上可能侥幸能过(文件系统不区分大小写),但换到别的平台就炸了,所以从一开始就严格按实际大小写写。
7.3 QtMsBuild 缓存与增量编译的怪现象
前面提过%LOCALAPPDATA%\QtMsBuild这个目录,这里展开说下它为什么重要。Qt VS Tools 2.x 之后,moc/uic/rcc 的执行不是硬编码在插件里的,而是通过一组 MSBuild targets 文件驱动的。VS 在构建工程时会加载这些 targets,判断哪些文件需要生成、生成到哪里、依赖关系是什么。
由此带来几类典型怪现象:
- 改了头文件里的
Q_OBJECT相关信号槽,编译却不报错也不生效:moc 的依赖判断没跟上,清理后重建。 - 报 "QtMsBuild not found" 或某个 targets 文件缺失:插件升级或路径变更后缓存的旧 targets 失效。
- 构建速度突然变慢,每次都在重新生成 moc 文件:targets 里的时间戳判断被破坏了。
对应处理就一条:关 VS,删%LOCALAPPDATA%\QtMsBuild,重开,让它重新释放。我一般还会顺手把工程的x64\Debug中间目录删掉,做一次干净的完整重建,确认问题是否真的消失。这一套下来能解决九成的"玄学构建问题"。
8. 打包发出去:windeployqt 与缺 DLL 的老问题
8.1 一条能用的 windeployqt 命令
调试跑通只是第一步,把程序给别人用的时候,依赖得自己带上。Qt 提供了windeployqt.exe,位于 Qt 的 bin 目录下,它会扫描你的 exe,把需要的 Qt DLL、插件、翻译文件拷到 exe 旁边。我最常用的形式是这样:
D:\Qt\Qt5.14.2\5.14.2\msvc2017_64\bin\windeployqt.exe ^ --release ^ --no-translations ^ --no-system-d3d-compiler ^ --no-opengl-sw ^ D:\build\MyApp\x64\Release\MyApp.exe几个参数说一下取舍逻辑。--release明确告诉它是 release 版本,避免它误判后拷了带 d 的调试 DLL(那些 DLL 在没装 VS 的机器上根本跑不起来,而且体积大一倍)。--no-translations和--no-system-d3d-compiler、--no-opengl-sw是缩小体积用的,如果你的程序不需要多语言、不需要 Qt 自带的 D3D 编译器和 OpenGL 软件渲染回退,关掉它们能省不少空间。QML 项目还要额外加--qmldir指向你的 qml 源码目录,让它扫描出实际用的 QML 模块。
打包完成之后,一定要在一台没装 Qt 也没装 VS 的干净机器上测一遍。这一步别省,我见过太多次"开发机跑得好好的,客户机器上白屏"。
8.2 常见"能调试不能双击运行"的原因
这类问题的根因基本可以归成四类,按概率排:
- 缺
platforms\qwindows.dll。Qt 的窗口系统是通过插件加载的,缺了它就报no Qt platform plugin could be initialized。注意目录结构必须是exe所在目录\platforms\qwindows.dll,直接放到 exe 旁边是不行的。 - 缺 C++ 运行库。目标机器没装对应的 VC++ 运行库,需要一起带上或者让用户装。VS2017 对应的运行库版本要和你编译时用的一致。
- 缺图片格式插件。用了 PNG、JPEG 之外的特殊格式,或者用了 SVG,需要
imageformats目录下的对应插件。 - 加载了错误的 DLL。目标机器的 PATH 里有另一个版本的同名 Qt DLL,被优先加载了。这个问题最气人,因为表现是随机崩溃而不是启动失败。解决办法是把依赖都放在 exe 同级目录,利用 Windows 的 DLL 搜索顺序(exe 所在目录优先于 PATH)。
另外还有一个容易被忽略的点:如果你在代码里用了QSplashScreen显示启动画面,或者用了某些需要在QApplication之前创建的对象,顺序错了会在 release 版本下崩溃而在 debug 下正常,因为 debug 版本的容错性更强。这类问题排查时,把 release 版本的崩溃信息(可以用qInstallMessageHandler记录,或者看 Windows 事件查看器里的模块名)当成第一手线索。
最后分享两个我一直在用的习惯。一个是给每个工程写一份"环境卡",就放在仓库根目录的 README 里,写清楚:Qt 版本号、msvc 包名、VS 版本与工具集、SDK 版本、需要手动勾选的模块和 /utf-8 这类编译选项。新人入职或者换机器的时候照着卡片走一遍,能省掉大半天试错。另一个是把 Qt Versions 的命名规范固化下来,全团队用同一套命名(比如Qt<版本>_msvc<代次>_<位数>),这样别人工程里的 Qt 版本引用在你机器上一定能找到同名记录,不会再被 "no Qt version assigned" 卡住。这两个习惯看起来是流程上的小事,但在多人协作里,它们比任何一条编译参数都值钱。