很多刚接触Qt开发的朋友,第一次把编译好的exe拷贝到别的电脑上运行,双击后系统提示“缺少Qt5Core.dll”、“找不到Qt5Widgets.dll”,那一瞬间整个人是懵的。明明在自己的开发机上跑得好好的,为什么换个环境就罢工?这就是典型的Qt部署问题。解决这个问题最常用的工具就是windeployqt,而每次构建完都要手动打开命令行执行windeployqt,久而久之人就会变懒,也很容易在某次版本迭代后忘记执行,导致发给测试或客户的包是残缺的。这篇文章就围绕“Qt Creator配置自动部署windeployqt”这个主题,把我实际配置过、踩过坑、最后稳定运行的经验完整写出来,希望让同样被部署问题折磨的朋友少走弯路。
整个过程会分成几个部分:先讲清楚为什么要做自动部署、底层原理是什么;然后对比两种主流配置方式(自定义构建步骤和QMake的QMAKE_POST_LINK),分别给出可直接抄作业的配置步骤和参数说明;再补充QML工程、第三方库、安装包工具衔接等进阶场景;最后整理一份完整的问题排查速查表。无论你用的是Qt 5还是Qt 6,qmake还是CMake,这篇文章都有参考价值。
1. 为什么要让Qt Creator自动跑windeployqt
1.1 手动部署有多痛苦
很多从Visual Studio或纯C++转过来的朋友,一开始是看不上windeployqt这种工具的,总觉得“不就是把几个DLL复制过去吗”。但真正用过一次就会发现,Qt的依赖关系比想象中复杂得多。随便一个基于Widgets的小程序,依赖的DLL就包括Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll,这些DLL又依赖ICU库、DirectX相关的运行时、OpenGL相关的dll等,光靠手工复制根本不可能搞清完整依赖链。
有个比较极端但真实的案例:一个只用了QPushButton和QLineEdit的简单程序,在Release模式下用windeployqt扫描后,生成的部署目录里竟然有几十个文件,包含platforms目录下的qwindows.dll、styles目录下的qmodernstyle.dll等。这些都属于运行时必须的组件,只是你平时在开发机上没感知罢了。
手动执行windeployqt的问题不只是麻烦,更致命的是容易漏步骤。我自己的习惯是每次发布前跑一遍命令,但人总有忙糊涂的时候,某次赶进度直接把构建出的exe丢进了打包工具,结果测试那边反馈程序启动崩溃,查了半天才发现是少了qwindows.dll插件。从那以后我就下决心把部署流程固化到Qt Creator里,让每一步构建都自动完成依赖收集。
1.2 自动部署的核心思路与方案对比
自动部署的思路本质上很简单:在编译完成后,让构建系统自动触发一次windeployqt(或对应版本的部署工具),把可执行文件、依赖DLL、QML相关文件(如果有)、平台插件等全部收集到指定输出目录。
实现这个目标有两种主流方式,我先做一个对比,后面会分别展开讲细节:
| 对比维度 | 自定义构建步骤 | QMAKE_POST_LINK |
|---|---|---|
| 适用构建系统 | qmake和CMake均可 | 仅qmake工程 |
| 配置位置 | Qt Creator的项目设置界面 | 工程文件.pro |
| 可移植性 | 依赖个人IDE配置,换电脑需重配 | 随.pro文件走,团队共享方便 |
| 执行时机 | 在Make阶段之后调用 | 链接完成后自动执行 |
| 控制粒度 | 可添加多个步骤,可配置条件 | 本质是一条命令行,适合单一动作 |
| 适合场景 | 快速配置、不想改工程文件 | 团队协作、要求配置正式化、跨平台 |
两种方式我实际都用过,各有各的适用场景。如果只是自己本地开发、快速验证,自定义构建步骤更快,不用改任何工程文件;如果是正式项目且需要团队协作,那QMAKE_POST_LINK的配置跟着.pro文件走,其他人拉代码后自动生效,明显更合理。
2. 动手前的准备:工具链与构建流程梳理
2.1 确认你的Qt构建方式
配置自动部署前,先确认一件事:项目的构建系统用的是qmake还是CMake。这个决定了你后面用哪种配置方案,也决定了windeployqt在构建流程中的插入位置。
qmake工程的最外层标志是存在.pro文件,Qt Creator打开这类工程时会在“项目模式”里显示“构建步骤”为“qmake”和“Make”。而CMake工程的最外层标志是CMakeLists.txt文件,构建步骤显示为“CMake配置”和“构建”。两种工程在Qt Creator里的自动部署配置入口完全不同,混着看容易绕晕。
另外,Qt 6开始CMake已经成了官方主推的构建方式,新项目基本都是CMake。但国内大量老项目、以及一些习惯于qmake开发的团队,仍然在用.pro。好在windeployqt对两者的支持都不错,我们后面讲的内容两种构建系统都覆盖到位。
2.2 找到windeployqt的正确路径
windeployqt是Qt安装目录自带的工具,具体位置和你的Qt安装路径、编译器套件、架构有关。一个典型的安装路径结构是:
D:\Qt\6.5.3\msvc2019_64\bin\windeployqt.exe D:\Qt\5.15.2\mingw81_64\bin\windeployqt.exe路径拆开来看:
- 版本号目录:6.5.3、5.15.2等,注意这里要选和你项目实际编译用的Qt版本一致的目录。
- 编译器套件目录:msvc2019_64表示MSVC编译器(64位),mingw81_64表示MinGW编译器(64位),还有android_arm64_v8a、wasm_single等,对应不同平台。
- bin子目录:windeployqt.exe、qmlimportscanner.exe等工具都在这里,后面配置路径或环境变量时用的都是这个目录。
值得注意的是,有些从网上下载的绿色版Qt或自己用源码编译的Qt,windeployqt的路径可能不在默认位置,建议先在文件管理器里搜索确认一下再配置。如果你同时在用多个版本的Qt,一定要确认当前构建套件用的是哪个版本,否则用5.15的windeployqt去部署6.5编译出来的程序,大概率会报版本不匹配的错误。
2.3 明确部署目标目录
windeployqt执行后会把DLL和插件输出到指定目录,这个目录可以是项目的构建目录,也可以单独指定一个“发布目录”。我的习惯是单独建一个deploy文件夹,放在构建目录之外,理由是每次重新构建时,构建目录会被清理,如果把部署文件也放在里面,清理之后还要重新部署一遍,纯属浪费时间。
典型的目录规划方式:
D:\workspace\MyApp\ ├── build-MyApp-Desktop_Qt_6_5_3_MSVC2019_64-Release\ ├── MyApp.pro └── deploy\构建目录是Qt Creator自动生成的,里面会有Release或Debug子目录,exe文件默认生成在build-MyApp-Desktop_Qt_6_5_3_MSVC2019_64-Release\release\MyApp.exe。deploy目录是自己建的,最终发布的文件全部汇集到这里。
如果你的项目也采用了类似的目录结构,下面的配置命令就可以直接改路径复用;如果目录结构不一样,只要把路径替换成你自己的就行,原理完全一致。
3. 方案一:通过自定义构建步骤实现自动部署
3.1 自定义构建步骤的界面操作
先讲方案一,因为它不修改任何工程文件,纯粹靠Qt Creator的界面配置搞定,适合快速搭建和个人使用。
操作入口在Qt Creator的“项目”模式里。打开项目后,左侧栏切换到“项目”,找到“构建和运行”分类下当前使用的构建套件(比如Desktop Qt 6.5.3 MSVC2019 64bit),下方会列出“构建步骤”。如果你的工程是qmake,默认会有qmake步骤、Make步骤;如果是CMake工程,则有CMake配置步骤和构建步骤。
我们要做的,是在这些默认步骤后面追加一个“自定义处理步骤”。步骤位置选择的是“添加构建步骤”,在下拉菜单里选“自定义处理步骤”。
新增出来的自定义步骤界面有几个字段:
- Command:要执行的命令,也就是windeployqt的完整路径。
- Arguments:传给windeployqt的参数。
- Working directory:命令执行时的工作目录,一般改成exe所在目录。
- 启用:勾选框,控制这个步骤是否启用。如果你构建Debug版本时不想部署,可以直接取消勾选,或利用“启用此步骤的条件”做版本判断。
这个界面设计得比较简洁,但实际操作时有个容易被忽略的点:Qt Creator的“自定义处理步骤”默认在每个构建配置下都需要单独配置。也就是说,你给Release版本加了步骤,切到Debug版本后那个步骤不会自动出现,必须手动再添加一次。我最初就栽在这里,给Release配好了,切到Debug一编译发现exe旁边的DLL还是老样子。
3.2 参数与命令设计的细节
界面配置本身不难,难的是命令参数的设计。很多人在这个环节直接卡住,因为windeployqt的命令行参数资料比较零散,这里把常见参数完整列出来:
windeployqt [options] [files]常用选项如下:
| 参数 | 作用 | 备注 |
|---|---|---|
| --release | 部署Release版本 | 默认自动检测,如果检测失败需手动指定 |
| --debug | 部署Debug版本 | Debug程序用这个,会把调试版DLL打进去 |
| --qml-dir | 指定QML模块目录 | QML工程必须加,否则漏掉Qt Quick相关依赖 |
| --dir | 指定输出目录 | 不指定则输出到exe同级目录 |
| --libdir | 指定DLL输出目录 | 到插件和DLL分开的场景用 |
| --plugindir | 指定插件输出目录 | 到platforms、imageformats等插件单独放置的需求 |
| --no-translations | 不复制翻译文件 | 体积强迫症患者推荐 |
| --no-system-d3d-compiler | 不复制D3D编译器 | 不需要DirectX功能时可加 |
| --no-opengl-sw | 不复制OpenGL软件模拟 | 没有兼容性顾虑时推荐 |
| --compiler-runtime | 复制编译器运行时库 | MSVC工程建议加上,MinGW经常不用 |
| --no-compiler-runtime | 不复制编译器运行时 | 如果你的安装包已包含VC++ Redistributable可考虑 |
| --force | 强制更新所有文件 | 目标文件存在时默认会跳过,某些异常时可加 |
| --dry-run | 只分析不复制 | 调试配置时非常有用 |
实际项目中,我常用的一组命令是这样的:
D:\Qt\6.5.3\msvc2019_64\bin\windeployqt.exe --release --compiler-runtime MyApp.exe工作目录设置为exe所在目录,这样部署结果会直接输出到exe同级目录。如果希望把文件分散到deploy目录,可以加--dir D:\workspace\MyApp\deploy参数。
注意我上面强调的--release参数。理论上windeployqt会自动检测exe是Debug还是Release,但我在实际使用中发现中文路径下偶尔检测会失灵,导致把Debug的Qt DLL复制到Release程序旁边,程序运行时直接崩溃。所以建议手动指定这个参数,不确定时就先用--dry-run跑一遍看输出日志。
3.3 这个方案的优缺点
自定义构建步骤的优势就是快、直观,不污染工程文件,而且它对CMake工程同样友好,不需要额外安装或配置别的东西。
但缺点也很明显,最核心的就是“不可移植”。你这个配置只存在于你的Qt Creator里,换一台电脑、或者同事拉取代码后打开项目,自定义步骤是不会跟着走的,需要每个人都手动配一遍。团队人一多,就会出现“我这边配置了、他那没配”的混乱场面。
另外,自定义步骤的配置是跟着“套件+构建配置”走的,项目里每增加一个构建套件(比如同时加了MSVC和MinGW两套),就要为每个套件分别配置一次。项目大了以后这部分维护成本就上来了。
因此,这个方案我推荐的场景是:个人项目、学习练习、快速原型开发。如果你是团队协作或者要长期维护的正式项目,下面要讲的QMAKE_POST_LINK方案更值得投入。
4. 方案二:在.pro文件中用QMAKE_POST_LINK实现一站式部署
4.1 QMAKE_POST_LINK的工作原理
先解释一下QMAKE_POST_LINK是什么。qmake在生成Makefile时,会暴露一批“钩子”变量,让开发者往构建过程里插入自定义命令。比较常用的有:
- QMAKE_PRE_LINK:链接之前执行
- QMAKE_POST_LINK:链接完成之后执行
- QMAKE_CLEAN:执行make clean时的动作
QMAKE_POST_LINK的执行时机是程序链接成功之后、这一条构建链路结束之前。也就是说,每次编译并链接出exe,紧接着就会执行这里配置的命令。这正是我们要的时机——因为windeployqt处理的对象正是刚生成的exe。
它的语法比较简单,就是把你希望执行的命令行放进去,多条命令用&&连接。把这个变量写进.pro文件,整个工程的部署逻辑就跟源码一起走了,任何人拉取代码,只要用qmake重新生成Makefile,自动部署就生效。
原理层面有个值得注意的点:QMAKE_POST_LINK只是在Make层面执行命令,不依赖Qt Creator界面,所以如果你用命令行手动执行qmake和make,同样会触发部署。这既是好事(可移植、自动化力度强),也带来一个小风险:Debug构建也会执行部署命令。所以配置时要做构建类型判断,这个在下面具体配置里我给出写法。
4.2 一个可直接抄的完整配置模板
下面是我在qmake工程里用的一个完整配置模板,历经了几个项目的验证,比较稳定:
# Qt自动部署:仅Release版本执行windeployqt CONFIG(debug, debug|release) { # Debug版不执行部署,保持构建速度 message("Debug mode, skip windeployqt.") } else { # Release版自动执行依赖部署 DEPLOY_TARGET = $$OUT_PWD/release/$$TARGET # windeployqt 路径按自己的安装目录修改 WIN_DEPLOY_TOOL = D:/Qt/6.5.3/msvc2019_64/bin/windeployqt.exe # 建议将部署文件统一输出到项目根目录下的deploy文件夹 DEPLOY_DIR = $$PWD/deploy # 确保deploy目录存在 !exists($$DEPLOY_DIR) { mkdir $$DEPLOY_DIR } QMAKE_POST_LINK += $$WIN_DEPLOY_TOOL --release --compiler-runtime \ --dir $$DEPLOY_DIR \ \"$$DEPLOY_TARGET\" }这里有几个关键细节需要说明:
第一,构建类型判断。CONFIG(debug, debug|release)的含义是“如果当前配置属于debug/ release这一组中的debug”,就执行message跳过部署。qmake里这个写法是逻辑严谨的,不会因为顺序问题导致两边都执行。
第二,输出路径的获取。$$OUT_PWD是qmake内置变量,指向Makefile生成的目录。在Qt Creator默认的“影子构建”模式下,这个目录就是实际构建目录。$$TARGET是不带路径的exe名称,比如MyApp.exe。两者拼接后得到exe完整路径。Debug构建模式下输出目录通常是$$OUT_PWD/debug/,我这里因为已经在上面排除了Debug,所以直接写release路径没有问题,但如果你要适配多套件,这里的路径需要按实际情况调整。
第三,命令行的引号处理。.pro文件里写带空格的路径时,需要手动加转义引号\",上面\"$$DEPLOY_TARGET\"的写法就是把整个目标exe路径用引号包起来,防止路径包含空格时命令被拆断。我在Windows中文用户名环境下经常碰到这个问题,路径是C:\Users\张三\...,如果不加引号,windeployqt会把路径按空格分割,导致参数解析错误。
第四,关于--dir参数和引号嵌套。你可能会奇怪,--dir $$DEPLOY_DIR这里怎么没加引号?因为DEPLOY_DIR用的是$$PWD,如果项目的路径里恰好有空格,一般建议也加上引号,即\"$$DEPLOY_DIR\"。我在模板里省略是为了直观,实际项目中建议加上,避免项目路径带空格的场景踩坑。
把这段配置写进.pro文件后,每次构建Release版本,链接完成后就会自动调用windeployqt,把依赖文件复制到deploy目录,全程无需手动干预。我用这套配置已经跑了好几个版本迭代,稳定性很高。
4.3 引号、转义与路径空格的处理
上面已经提过引号问题,这地方太容易让人踩坑了,我单独拿出来再强调一遍。
qmake的QMAKE_POST_LINK最终会被写入Makefile,然后由shell(在Windows下通常是cmd.exe)执行。这里存在两层转义:第一层是qmake解析.pro文件时的转义,第二层是cmd.exe解析命令行时的转义。
一个比较经典的场景:如果你的Qt安装路径带空格,比如D:\Qt 6.5\msvc2019_64,在.pro里直接写D:/Qt 6.5/msvc2019_64/bin/windeployqt.exe,最终生成命令行时这个路径会被拆成两个参数,命令直接执行失败。解决办法有两个:
- 给带空格的路径加
\",像这样:QMAKE_POST_LINK += \"D:/Qt 6.5/msvc2019_64/bin/windeployqt.exe\" --release ... - 更建议把windeployqt的路径统一设置为不含空格的路径,或者直接把windeployqt目录加入系统PATH环境变量,这样.pro里只写命令名,不与路径空格纠缠。
第二种方式是我实际比较推荐的。在系统环境变量PATH里添加D:\Qt\6.5.3\msvc2019_64\bin,然后在.pro里写:
QMAKE_POST_LINK += windeployqt --release --compiler-runtime --dir $$DEPLOY_DIR \"$$DEPLOY_TARGET\"这样写简洁直观,且不会遇到qmake转义带来的各种边界问题。代价是换电脑后需要重新配置一次PATH环境变量,但相对于调试转义省下的时间,这点成本实在微不足道。
还有一个小细节:qmake的$$quote()函数可以用来自动处理路径空格,比如QMAKE_POST_LINK += $$quote($$WIN_DEPLOY_TOOL) ...。但实测下来,在某些Qt版本里$$quote()对特殊字符(比如中文)的处理并不完美,我还是倾向手动加\",可控性更强。
5. 实战中的高频问题和排查技巧
5.1 常见问题速查表
配置自动部署的过程中,我自己踩过也帮朋友排查过不少问题,这里整理成速查表,按“症状 → 原因 → 解决办法”的格式列出:
| 症状 | 原因 | 解决办法 |
|---|---|---|
| 构建时报“command not found” | windeployqt路径错误或未加入PATH | 确认windeployqt.exe所在目录,修正路径,或加入PATH后重启Qt Creator |
| 执行了但exe旁边没有DLL | 工作目录或--dir参数指向了错误目录 | 检查命令输出,确认部署目标目录;用--dry-run查看实际分析结果 |
| 程序启动提示缺少Qt5Core.dll | 自动检测识别错了Debug/Release | 手动加上--release或--debug参数 |
| QML程序运行黑屏或控件不显示 | 缺少QML模块 | 加--qml-dir参数,指向项目的QML源码目录或Qt的qml目录 |
| MSVC构建部署后提示VCRUNTIME140.dll缺失 | 没用--compiler-runtime参数 | 增加--compiler-runtime,或者确保目标机器安装了VC++ Redistributable |
| 部署后exe体积异常大,几百MB | Debug库被复制进来了 | 确认加了--release;检查环境变量是否混入了Debug版的Qt路径 |
| 目标机器还是报无法定位程序输入点 | 部署的Qt DLL和exe版本不一致 | 检查是否用了多个Qt版本,确保构建套件和windeployqt版本一致 |
| 自定义步骤在Debug配置下也执行 | 每个构建配置需单独配置 | 在Debug配置下移除或禁用对应自定义步骤 |
| 构建卡在QMAKE_POST_LINK没有任何提示 | exe路径写错导致命令静默失败 | 检查$$TARGET和$$OUT_PWD是否正确;在命令前加echo打印实际值 |
| 中文路径下部署报“Error 2:系统找不到指定的文件” | cmd.exe无法解析中文路径导致的编码问题 | 在.pro里设置msvc.name = ...等方法规避中文路径,或把项目放到纯英文路径下 |
上面表格里有一个高频问题需要多说一句:那就是Debug和Release DLL混用的问题。windeployqt虽然号称能自动检测,但它的检测逻辑依赖于exe中导入的DLL名称特征。有个排查细节,部署完成后直接看exe目录下Qt5Core.dll(或Qt6Core.dll)的文件大小,Debug版通常会比Release版大不少,而且文件名上可以区分——Debug版其实是Qt5Cored.dll、Qt5Widgetsd.dll这种带d后缀的。如果看到d后缀的DLL出现在Release目录里,基本可以确定部署参数有问题。
5.2 QML工程的一些补充
如果你开发的是QML程序,部署时比纯Widgets程序要多几步。windeployqt对QML并不是自动扫描的,只靠默认行为往往会把QML模块漏掉。之前我就有个Qt Quick工程,部署后在别的机器上一运行,窗口能弹出来但整个界面都是黑屏或空白,打开Debug输出一看,一堆“module QtQuick.Controls is not installed”的报错。
解决办法是给windeployqt加上--qml-dir参数。这个参数的取值有两种:
- 指向你的项目QML源码目录(包含qml文件的路径),例如:
--qml-dir D:\workspace\MyApp\qml - 指向Qt安装目录中的qml模块目录,例如:
D:\Qt\6.5.3\msvc2019_64\qml
这两种方式效果上有区别。指向项目QML源码目录时,windeployqt会分析工程中使用到的import语句,按需复制对应的模块;指向Qt的qml目录时,会把整个大型QML模块树都考虑进去,部署结果会大不少,但更保险。
我自己的建议是优先用项目源码目录,因为它只复制真正用到的模块,部署体积较小。缺点是如果项目通过QUiLoader或者动态字符串加载方式引用QML文件,静态扫描可能会漏掉一部分模块,这种情况就得退一步选择Qt目录方式,甚至手动补充复制。
在QMAKE_POST_LINK方案里,给模板补充一下QML支持的写法:
QMAKE_POST_LINK += windeployqt --release --compiler-runtime \ --qml-dir $$PWD/qml \ --dir $$DEPLOY_DIR \ \"$$DEPLOY_TARGET\"需要注意--qml-dir参数如果路径含空格,同样需要\"包裹。
5.3 与安装包制作工具的衔接
windeployqt能解决的是“把依赖文件放在exe旁边”,但它本身不负责制作安装包。实际项目发布时,我们还经常要把部署完成的文件夹再交给Inno Setup、NSIS、Qt Installer Framework等工具做成安装程序。
如果你用的是Inno Setup,脚本里直接引用deploy目录即可:
[Files] Source: "D:\workspace\MyApp\deploy\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs这里有一个衔接上的小建议:windeployqt默认会把DLL、插件、翻译文件等全部平铺到部署目录,结构相对规整。但建议在最终打包前做一次“瘦身”,把不需要的翻译文件、冗余的平台插件删掉。体积这一块很多项目做不好,我看过有人把整个deploy目录几百MB直接打进安装包,用户安装时叫苦不迭。常见的瘦身操作包括:
- 删除translations目录下用不到的语言包,只保留中文和英文
- 删除iconengines、imageformats里用不到的格式插件(如果只用png/jpg,其他可以不留)
- 确认没有把Debug版的DLL混进来
- 不需要Qt Network或Qt SQL功能的项目,可以试试删除对应DLL,但务必在干净环境测试后再删
至于Qt Installer Framework,它的正常流程是把deploy目录作为组件内容打包,原理相同。总之,自动部署解决的是“依赖完整性”问题,安装包制作解决的是“分发体验”问题,两者拼起来才是完整的发布链路。
5.4 排查命令的要点
最后分享一个排查问题时的小技巧,非常适合在配置阶段使用。无论你用的是自定义构建步骤还是QMAKE_POST_LINK,初始配置时建议先加一个--dry-run参数,让windeployqt只扫描不复制,把执行结果打印出来看一遍:
D:\Qt\6.5.3\msvc2019_64\bin\windeployqt.exe --dry-run --release MyApp.exe执行后终端会列出“would deploy”之类的分析结果,包括哪些DLL会被复制、哪些QML模块会被处理、哪些插件目录会被创建。这些信息能帮你快速判断参数是否正确,比直接执行后翻目录验证省事得多。等确认无误后,再把--dry-run去掉,正式启用自动部署。
还有一个思路是在windeployqt命令前加echo或cmd /c去捕获详细输出。Windows下如果部署过程中没有弹窗,输出信息会被Qt Creator的“编译输出”面板吞掉一部分,这时可以在自定义构建步骤的“Command”里写成cmd /c echo start && D:\Qt\...\windeployqt.exe ... && echo done,这样能明确看到命令是否执行成功,定位问题更直接。
6. 我个人在实际使用中的一些体会
这套自动部署配置,前前后后用了大概两年,有三个体会比较深。
第一,自动部署不是一劳永逸的,每次升级Qt版本或切换构建套件,都必须重新检查一次。Qt从5到6,windeployqt的参数变化不大,但有些默认行为有调整,比如Qt 6里QML相关处理和Qt 5就有差异。你升级编译器或Qt版本后,最好把部署目录清理干净,重新执行一次,然后用Dependency Walker或Process Explorer之类的工具检查关键依赖是否齐全。
第二,自动部署能解决90%的问题,但剩下10%需要人工兜底。典型的情况就是第三方动态库,比如你自己用CMake编译了某个第三方库并动态链接,windeployqt无法感知它的依赖。每次构建完,我仍会把deploy目录里有没有第三方DLL作为一项手动确认清单来检查。实际上,更好的做法是在部署脚本里加一条copy命令,把第三方DLL一并复制过去,这样那10%也能变成自动。
第三,尽早把自动部署引入项目,越早越省心。我见过不少项目,开发期完全不在意部署,等到要交付了才手忙脚乱地补DLL、做安装包。那种状态下出问题的概率极高,而且问题往往集中在“缺这个模块、少那个插件”的上,排查起来非常烧脑。不如从一开始就配置好自动部署,每次构建都以“可发布状态”输出,平时多花几分钟,临到交付就能稳稳当当。
最后再分享一个小技巧:如果你的项目构建频率很高,Release和Debug来回切换,建议把自动部署只挂在Release配置上。Debug构建在本地开发阶段根本不需要部署,挂上反而拖慢构建速度,而且Debug版DLL体积大,部署目录会很臃肿。让Release版本配合自动部署,Debug版本保持纯粹的生产力工具,这种分工在实际开发中是最舒服的平衡点。