很多C++开发者第一次用CLion写完hello world,第二个需求往往就是:在CLion里构建一个Qt项目。这时候你搜出来的教程,十有八九会劝你装Qt Creator,理由通常是“CLion对Qt支持不好”。我一开始也信了,直到把Qt Creator装完、折腾完工程文件、发现和CLion的编辑习惯完全割裂之后,才明白真正的问题不是CLion不能写Qt,而是没人把正确的构建流程讲清楚。
这篇文章就是来解决这个问题的。我会从环境准备、CMake配置、调试排错到发布打包,完整走一遍用CLion从零到一构建Qt项目的流程。整个过程只依赖两个核心东西:CLion自带或系统安装的CMake,以及官方Qt SDK。适合已经在用CLion写C++、但没碰过Qt的开发者,也适合被Qt Creator的工程结构劝退、想用一套统一构建系统管理所有项目的人。
1. 为什么我选择在CLion里写Qt,而不是换个IDE
1.1 Qt Creator很好,但替代不了编辑器的肌肉记忆
先说实话,Qt Creator本身是个优秀的IDE,尤其在做QML开发、快速原型验证的时候,它的Designer和项目向导确实方便。但问题是,如果你已经习惯CLion的快捷键、代码智能提示、Git集成和重构工具,再切到Qt Creator会非常别扭。这种割裂感不是“多学一个工具”就能解决的,它直接影响每天的开发效率。我的选择很简单:既然CLion在主C++开发上已经用得很顺,那就想办法让Qt项目也跑在CLion里。
工具链统一这件事,长期看收益很大。一个团队里,有的人写算法库,有的人写业务界面,如果都用CLion管理所有CMake工程,新人入职第一天就不用纠结“哪个项目用哪个IDE”这种问题。Qt项目本质上就是一个C++项目,只是多了一套Qt库和几个处理步骤而已。
1.2 CLion与CMake:Qt6时代的天作之合
Qt从6.0开始,官方构建系统已经全面转向CMake,qmake退居二线。而CLion对CMake的支持是所有IDE里做得最彻底的一档:自动重载、目标级编译、单文件运行、CMake Profile管理都非常成熟。这俩凑在一起,等于说你的Qt项目不再需要任何额外的构建脚本,CLion的CMake配置直接就是Qt官方推荐的构建方式。
在CLion里建Qt项目,核心工作其实就一句话:写好CMakeLists.txt,让find_package找到Qt库,再处理一下Qt的元对象编译器相关设置。后面所有编译、运行、调试,都和普通C++项目没有区别。这也是“从零到一”最省心的路线。
1.3 一张表看懂四种工具组合的取舍
很多人在选择工具链时纠结不已,我把实测过的几种主流组合整理成一张表,供你参考:
| 工具组合 | CMake支持 | Qt元对象自动处理 | 调试体验 | QML设计器 | 获取成本 |
|---|---|---|---|---|---|
| Qt Creator | 完整 | 自动 | 较好 | 官方支持 | 免费 |
| CLion + CMake | 完整 | 需开启AUTOMOC | 优秀 | 较弱 | 商业/学生免费 |
| Visual Studio + Qt VS Tools | 一般 | 自动(MSVC) | 优秀 | 一般 | 社区版免费 |
| VS Code + CMake Tools | 完整 | 需手动配置 | 一般 | 差 | 免费 |
如果你的项目以C++ Widgets为主、不用大量QML界面,那CLion几乎是最顺手的选择。如果你重度依赖QML可视化设计,Qt Creator的Designer仍然不可替代。我自己的项目里QML用得少,所以CLion是完全够用的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开工前的环境底子:Qt、编译器、CMake怎么搭才不出错
2.1 先搞清楚你系统的编译链路:MinGW还是MSVC
很多人在CLion里配置Qt项目时第一步就卡住了,不是因为代码问题,而是Windows下的编译器选择搞错了。Qt官方安装包在Windows下有两种版本:MinGW版和MSVC版。MinGW是GCC的Windows移植版,MSVC是Visual Studio的编译工具链。这两个编译器生成的二进制格式不一样,不能混用。也就是说,如果你安装的是Qt的MSVC版本,那么CLion里的Toolchain就必须是Visual Studio的MSVC;如果你安装的是Qt的MinGW版本,CLion里的Toolchain就得用MinGW。
我在第一次踩坑时,装的是MSVC版本的Qt,但CLion默认用的是MinGW工具链,导致一编译就报一堆头文件找不到、链接器报错。所以建议你在装Qt之前,先想清楚自己系统里有什么编译器。如果你没有Visual Studio,也不想装它,那就选MinGW版本的Qt,然后在CLion里配置一个MinGW工具链。如果你装过Visual Studio,那就省事,直接选MSVC版Qt。
这台机器上我用的方案是:MSVC 2022 + Qt 6.5.3 MSVC版,CLion里新建一个Visual Studio工具链。这个组合在调试体验上是最好的,因为MSVC的调试器对Windows的调试信息格式支持最完善。
2.2 Qt安装时到底该勾选哪些组件
去Qt官网注册一个账号,下载在线安装器。安装过程中,会让你选组件,很多人面对这么长的组件列表就懵了。我的建议是,先别全选,按你的实际平台来:
- 如果你在Windows下开发,勾选Qt 6.x.x下的“MSVC 2019 64-bit”或者“MinGW 11.2.0 64-bit”,取决于你上面选定的编译器。
- 勾选“Qt Debug Symbols”和“Qt Sources”,调试的时候能进入Qt源码,排查问题非常方便。
- 组件列表里有“Qt Creator”,如果你打算长期用CLion,可以不用勾选,省几个GB空间。
- Additional Libraries里的组件按需选,做Widgets界面只需要Qt Base里的东西,默认就会包含。
安装完成后,默认路径在 C:\Qt\6.5.3\msvc2019_64 这种结构下。路径里不要带中文和空格,Qt本身没问题,但CMake和Ninja在部分旧版本里对中文路径支持不友好,容易出莫名其妙的问题。
2.3 CMake和Ninja从哪来
CLion自带了一套CMake和构建工具,通常路径在CLion安装目录的bin文件夹里,版本一般比较新,直接用就行。如果你希望使用系统安装的CMake,也可以单独装一个,然后在Settings -> Build, Execution, Deployment -> CMake里把CMake路径指向系统版本。这里我的建议是:用CLion自带的就行,省心,而且CLion每次升级都会同步更新内置CMake版本。
关于构建工具,Windows下CLion默认会生成Visual Studio解决方案或使用Ninja。Ninja的并行编译速度很快,CLion新版本对Ninja的支持已经很成熟。如果你的CMake Profile里没有自动识别到Ninja,可以在环境变量里加上Ninja的路径,或者装一个Ninja后指定。在Toolchain设置里,能看到CLion自动检测到的各个工具链,确认你选的那套工具链里有C和C++编译器即可。
2.4 安装完成后怎么验证环境
装完之后,先别急着开CLion,在命令行里验证一下环境变量是否生效。打开PowerShell或CMD,依次执行:
bash复制qmake -v
cmake --version
ninja --version
如果你的系统PATH里没有qmake,说明安装时没有把Qt的bin目录加进去。可以手动添加,但并不强制,因为后续CLion的CMake会通过find_package找到Qt库的路径。更可靠的做法是,在CMakeLists里用set(CMAKE_PREFIX_PATH "C:/Qt/6.5.3/msvc2019_64")显式指定Qt根目录,这样即使PATH没配好也能找到。
验证环境这个步骤,我吃过一次亏。当时装好Qt后直接开CLion建项目,CMake飘红报错找不到Qt,排查了半天发现是安装时没勾选“Qt Debug Symbols”导致的组件目录不完整。重新安装之后才顺畅。所以环境验证别跳过。
3. 在CLion里创建并跑通第一个Qt窗口
3.1 新建项目:“CMake项目”还是“Qt项目”
CLion的新建项目向导里没有“Qt Application”这个模板,这是一个常见误解的来源。实际上你只需要选择“C++ Executable”或者直接选“Empty CMake Project”,然后自己在CMakeLists.txt里把Qt拉进来,就能构建出Qt项目。
选“C++ Executable”会自动生成一个最简单的CMakeLists.txt,包含一个main.cpp。这个起点很干净,适合我们逐步往上加Qt内容。如果你选“Empty CMake Project”,则连main.cpp都得自己建,差别不大,看个人习惯。
新建项目时建议勾选“Add project to CMake”,这样CLion会自动把项目加入CMake配置体系里,省去后面手动添加。
3.2 一份可以直接抄的CMakeLists.txt
项目建好后,把自动生成的CMakeLists.txt替换成下面这份,这是我在多台机器上验证过的稳定配置:
cmake复制cmake_minimum_required(VERSION 3.16)
project(MyQtApp)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Qt元对象编译器、UI编译器、资源编译器的自动处理开关
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
# 同时兼容Qt5和Qt6
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
add_executable(MyQtApp
main.cpp
)
target_link_libraries(MyQtApp PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
这份配置有几个关键点:第一,find_package(QT NAMES Qt6 Qt5)这种写法非常实用,它会优先找Qt6,找不到再找Qt5,你不用因为升级Qt而频繁改CMake文件。第二,AUTOMOC、AUTOUIC、AUTORCC三个开关必须打开,这关系到Qt的moc、uic、rcc三个工具能不能自动运行,下面第4章会详细讲。第三,target_link_libraries里链接的是Qt6::Widgets或者Qt5::Widgets,如果你的项目里用到网络、数据库等模块,就继续追加对应的组件,比如Network、Sql。
3.3 main.cpp:最小Qt窗口
配套的main.cpp可以这样写,一个标准的最小窗口加一个按钮事件:
cpp复制#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QMainWindow window;
window.setWindowTitle("CLion + Qt");
window.resize(800, 600);
auto *button = new QPushButton("点击我", &window);
button->setGeometry(350, 280, 100, 40);
QObject::connect(button, &QPushButton::clicked, [&window]() {
window.setWindowTitle("按钮被点击了");
});
window.show();
return QApplication::exec();
}
这段代码创建了一个QMainWindow,里面放了一个按钮。注意按钮用了new QPushButton("点击我", &window),父对象是window,所以Qt会负责在窗口销毁时释放这块内存,不需要手动delete。信号槽用了新语法,编译期就能检查参数类型是否匹配,不容易写错。
3.4 选择Toolchain与运行配置
写完CMakeLists和main.cpp后,CLion的CMake会自动加载。在右下角可以看到当前选择的CMake Profile,点开后选择与你的Qt包匹配的Toolchain。比如我用的MSVC版Qt,就选择Visual Studio工具链;如果你用的是MinGW版Qt,就选MinGW工具链。这一步非常关键,选错了编译阶段就会报错。
接下来点击运行按钮旁边的下拉菜单,选择“Edit Configurations”,确认运行目标选的是MyQtApp。默认配置基本够用,但有一个小技巧:如果你需要在运行时设置工作目录(比如加载相对路径的资源文件),可以在“Working directory”里指定。如果你在调试时需要用特定环境变量,也可以在“Environment variables”里加,比如某些OpenGL驱动异常时需要设置QT_OPENGL=software。
3.5 点运行,看到窗口
配置完成后,点击绿色运行按钮,你会看到CLion的底部窗口开始编译。第一次编译需要生成CMake缓存,可能要一小会儿,之后每次改动代码重新编译就快很多。如果一切顺利,屏幕上会弹出一个标题为“CLion + Qt”、大小为800x600的窗口,点击按钮,标题会变成“按钮被点击了”。
看到这个窗口,说明你的CLion + Qt开发环境已经彻底跑通了。接下来大部分开发工作都是在这个基础上叠加更多模块、更多文件、更多界面而已。
4. CMake里的Qt构建魔法:AUTOMOC、AUTOUIC、AUTORCC
4.1 三个开关分别管什么
Qt除了是C++库之外,还自带三个“代码生成器”:moc、uic、rcc。它们分别在编译前处理三类文件:
| 开关 | 对应工具 | 处理文件 | 生成内容 |
|---|---|---|---|
| CMAKE_AUTOMOC | moc | 含Q_OBJECT宏的.h/.cpp | 元数据moc_xxx.cpp |
| CMAKE_AUTOUIC | uic | .ui界面文件 | ui_xxx.h |
| CMAKE_AUTORCC | rcc | .qrc资源文件 | qrc_xxx.cpp |
这三个开关在CMake里打开后,你不需要手动调用任何工具,CMake会在编译过程中自动把源文件丢给moc/uic/rcc处理,再把生成的代码编译进目标里。这也是CLion写Qt项目最舒服的地方:你不用像传统Makefile那样自己写一堆规则。
4.2 不开AUTOMOC会出什么错
我见过太多人卡在这里。写下第一行带Q_OBJECT的类定义后,编译一跑,链接器报错:
text复制undefined reference to `vtable for MainWindow'
或者:
text复制undefined reference to `MainWindow::qt_metacall(QMetaObject::Call, int, void**)'
这类报错十有八九就是CMAKE_AUTOMOC没有打开。C++编译器本身不知道Q_OBJECT是什么,它需要moc生成的代码来补全虚函数表、信号槽元信息。AUTOMOC就是帮你自动补全这一步。首次写CLion + Qt项目时,我漏过一次这个开关,排查了一个多小时,最后发现只是CMakeLists里少了一行,当时真想拍桌子。
4.3 为什么Qt必须要moc这层预处理
简单来说,Qt的信号槽机制是C++标准之外的扩展。它允许一个对象在状态变化时发出信号、另一个对象感受槽并响应,这种“类型安全但不依赖RTTI”的机制需要额外的元数据描述每个类的信号和槽。moc工具做的就是扫描头文件,识别Q_OBJECT宏,生成包含元数据的C++源码。这些源码会被送入编译器,与你的类一起编译链接。
正是这层机制,让Qt项目的CMake配置比普通C++项目多了一步。好在新时代的CMake和CLion已经把这一步自动化了,你只需要记住打开那三个开关,其他的交给构建系统去处理。
4.4 如果你不想用AUTOMOC,也可以用传统写法
虽然我强烈推荐用自动开关,但了解一下手动写法还是有用的,尤其当你的项目结构比较特殊时。手动模式长这样:
cmake复制set(CMAKE_AUTOMOC OFF)
qt_wrap_cpp(moc_sources
MainWindow.h
)
qt_wrap_ui(ui_sources
MainWindow.ui
)
qt_wrap_rc(rcc_sources
resources.qrc
)
add_executable(MyQtApp
main.cpp
MainWindow.cpp
${moc_sources}
${ui_sources}
${rcc_sources}
)
手动写法的好处是生成过程完全透明、你可以控制文件名和输出位置;坏处是每新增一个带Q_OBJECT的头文件就得往CMakeLists里加一行,维护成本高。日常开发时,自动开关打开就够了。我在自己的模板项目里是全部三条开关写满,加上对齐注释,这样别人拿到你的项目也能秒懂。
4.5 顺手解决“Qt弹出对话框选择文件”
趁这个章节还在讲Qt的实用组件,分享一个高频需求:点击按钮后弹出文件选择对话框。这在Qt里就是三行代码的事:
cpp复制#include <QFileDialog>
QString filePath = QFileDialog::getOpenFileName(
&window,
"选择文件",
QDir::homePath(),
"所有文件 (*.*);;文本文件 (*.txt);;图片 (*.png *.jpg)"
);
if (!filePath.isEmpty()) {
qDebug() << "用户选择了:" << filePath;
}
getOpenFileName是静态函数,直接调用就弹出模态对话框。第一个参数是父窗口,第二个是标题,第三个是默认目录,第四个是文件类型过滤器。这个功能做文件导入、配置读取的时候几乎必用,建议直接收藏。注意要在CMakeLists里确认你已经链接了Qt${QT_VERSION_MAJOR}::Widgets,这样QFileDialog头文件才能找到。
5. 那些卡住很多人的坑:完整排查过程而不是直接给答案
5.1 qt.qpa.plugin could not find the Qt platform plugin “windows”
这个报错几乎每个Qt新手都会遇到,尤其是从CLion里点Run明明能跑,但把exe拷贝到另一个目录后运行就报这个错。完整的排查链路是这样的:
第一步,看报错信息里提示的平台插件名字。如果是“windows”,说明Qt在启动时需要加载windows平台插件,也就是platforms/qwindows.dll。Qt的QPA(Qt Platform Abstraction)机制要求插件路径必须在可执行文件目录的platforms子目录下,或者能被Qt的库搜索路径找到。报错的根因就是它找不到这个dll。
第二步,确认你的exe目录下有没有platforms文件夹。如果没有,从Qt安装目录的plugins\platforms里拷贝一份过来,或者用第6章的windeployqt自动部署,它会帮你把所有依赖一起拷出来。
第三步,如果是在CLion里调试时报错,那么检查可执行文件的工作目录和PATH,确保Qt的bin目录在PATH里。因为运行时Qt会尝试从当前目录和PATH两个方向找插件。
第四步,还有一个容易忽略的点:如果你的项目里显式调用了QApplication::addLibraryPath或设置了QT_QPA_PLATFORM_PLUGIN_PATH环境变量,优先级高于默认搜索逻辑,一旦路径写错,也会出现这个问题。所以排查时先检查代码里有没有设置过这个环境变量。
5.2 Linux下qxcbconnection相关报错
在Linux上做Qt开发时,常见报错长这样:
text复制qt.qpa.xcb: could not display
qxcbconnection: failed to initialize xrandr
qt.qpa.plugin: could not load the Qt platform plugin "xcb"
或者:
text复制qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in ""
qxcbconnection: Qt: xkeyboard extension not present
排查链路从最底层往上走。首先确认图形环境本身没问题:DISPLAY环境变量是否设置正确,X server或Wayland是否正常。其次确认Qt的xcb依赖库是否齐全,这是最常见的原因,尤其是精简版Linux发行版缺少libxcb相关运行库。可以用下面的命令检查:
bash复制ldd your_app | grep xcb
如果输出里显示libxcb-xinerama.so.0 => not found或者libxkbcommon-x11.so.0 => not found,就安装对应依赖:
bash复制sudo apt install libxcb-xinerama0 libxkbcommon-x11-0 libxkbcommon0
装完再跑一次,如果还报xrandr的问题,继续装libxrandr-dev相关的运行库。这一类问题的本质是Qt的xcb平台插件在运行时依赖一系列动态库,而这些库没有被打包进发布环境。Linux下发布Qt程序时,用ldd检查依赖、用linuxdeployqt打包,是绕不开的一步。
5.3 信号槽没有触发,断点也进不去
代码写得没问题,编译也过去了,但点按钮后信号槽就是不执行,断点打上去也不命中。这个问题排查链路要从几个角度同时看。
第一,检查connect的写法。新语法QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot)如果写成connect(button, &QPushButton::clicked, &window, &MainWindow::onClicked),一旦onClicked不是槽或兼容的成员函数,编译期就会报错。如果硬要用字符串老语法connect(button, SIGNAL(clicked()), this, SLOT(onClicked())),运行时如果槽名字拼错,不会报错,只会静默不触发。所以强烈建议用新语法。
第二,检查connect调用时,sender和receiver是否已经构造完成。如果你在MainWindow构造函数里connect某个子对象,而这个子对象是nullptr,比如成员变量的初始化顺序和声明顺序不一致,那connect时传入的sender为空指针,连接不会生效。
第三,如果是跨线程信号槽,要注意连接类型。默认情况下,如果sender在子线程、receiver在GUI线程,Qt会排队连接,事件循环必须跑起来才能执行。如果你在子线程里直接调用了槽函数,那是直接连接,和信号槽机制不是一回事。遇到这种场景,建议先在槽函数入口加qDebug()打印,确认到底有没有进入槽,再分析是发送端没发还是接收端没收到。
5.4 中文乱码:CLion的编码与MSVC编译选项
在Windows + MSVC环境下,源码文件里的中文字符串在运行时会变成乱码。这个问题的原因有两个层面。
第一层,CLion默认以UTF-8编码保存源文件,而MSVC编译老版本时默认按本地代码页(GBK/936)解析源文件,导致UTF-8的中文字面量被编译器读错。解决办法是在CMakeLists里给MSVC加一个编译选项:
cmake复制if(MSVC)
add_compile_options(/utf-8)
endif()
加上/utf-8后,编译器就会按UTF-8解析源码,中文不会乱码。如果还是乱,检查CLion的File Encoding设置,把项目、默认都设成UTF-8,同时切到Release和Debug都试一下。
第二层,运行时字体渲染的问题。Qt在Windows下对默认字体处理的比较好,但还是建议在main函数里设置一个支持中文的字体,比如:
cpp复制QApplication::setFont(QFont("Microsoft YaHei", 9));
这样即使在英文系统上,只要安装了微软雅黑,界面中文也能正常显示。
5.5 调试器断不下来
CLion用的调试器在Windows下默认是Visual Studio Debugger或GDB,在Linux下是GDB。如果你在断点处看到圆圈里有个斜杠、断点被标记为“未被解析”,一般来说有三个原因:构建类型不是Debug、优化级别太高、调试符号没有生成。
在CLion的CMake Profile设置里,把Build type选成Debug,同时确认CMakeLists里没有手动加-O2这类的优化选项。最好也不用CMAKE_BUILD_TYPE=Release跑调试,因为Release模式下变量可能被优化掉,断点位置会错位。
第二,检查CMake是否生成了调试符号。Visual Studio工具链默认Debug会生成.pdb文件;GCC/Clang用-g参数。如果用的是MinGW的GCC,可以在CMakeLists里加一行:
cmake复制set(CMAKE_CXX_FLAGS_DEBUG "-g")
保证生成dwarf调试信息。如果断点还是打不上,在CLion右下角的Debugger进程窗口里看提示信息,通常会告诉你具体原因。
6. 从能跑到能发布:打包与部署的关键
6.1 三种平台一个逻辑:把依赖库放到exe旁边
开发机上点击Run能跑,不代表把exe拷到别的机器上也能跑。原因是Qt程序是动态链接的,运行时候需要一堆Qt5/6核心库、平台插件、样式插件。离开开发环境后,这些库不会自己出现。
发布的基本逻辑很简单:把你构建出来的exe/dylib/可执行文件,和它依赖的所有Qt库、插件一起放进同一个目录。不同平台有不同的帮助工具来完成这件事:Windows用windeployqt,macOS用macdeployqt,Linux用linuxdeployqt或者ldd手工收集动态库。
6.2 Windows下windeployqt的用法与参数
在Windows上,如果Qt安装在C:\Qt\6.5.3\msvc2019_64,并且你的exe路径是build\MyQtApp.exe,发布命令非常简单:
bash复制cd build
C:\Qt\6.5.3\msvc2019_64\bin\windeployqt.exe --release --no-translations MyQtApp.exe
执行完成后,exe旁边的目录里会自动多出Qt的dll、platforms插件、styles插件、iconengines插件等。常用参数如下:
| 参数 | 作用 |
|---|---|
| --release | 按Release模式生成依赖,缺省为Debug,注意别搞混 |
| --debug | 部署Debug版依赖,体积大很多,调试用 |
| --no-translations | 不拷贝Qt多语言翻译文件,减少体积 |
| --compiler-runtime | 同时拷贝C++运行库(MSVC的vcruntime) |
| --no-system-d3d-compiler | 不拷贝D3D编译器,不需要DirectX时可以省掉 |
| --list | 只列出需要的依赖,不实际拷贝 |
跑完以后,建议把整个文件夹拷到一台干净机器或虚拟机里测试,重点检查双击exe能不能正常启动、窗口和按钮是否显示。这一步验证很重要,因为windeployqt默认按Qt的install路径去查找依赖,如果你的程序还间接依赖了其他第三方动态库,windeployqt并不会帮你拷贝,需要你自己把那些dll一起带上。
6.3 在CMake里配置自动拷贝依赖
每次手动跑windeployqt有点烦,而且容易漏。我现在的做法是在CMakeLists里加一个自定义目标,把windeployqt集成进构建流程:
cmake复制if(WIN32)
add_custom_command(TARGET MyQtApp POST_BUILD
COMMAND ${Qt6_DIR}/../../../bin/windeployqt.exe
--release --no-translations
$<TARGET_FILE:MyQtApp>
COMMENT "Running windeployqt to deploy runtime dependencies..."
)
endif()
这样每次在CLion里构建项目后,windeployqt会自动执行,把依赖库拷贝到执行文件旁边。开发期就能在目录里看到一堆dll,发布时直接打包整个build目录就行。${Qt6_DIR}来自find_package自动生成的变量,路径定位到Qt的lib/cmake目录,往上三级就是Qt安装根目录。如果路径不对,也可以自己写死确认过的Qt bin路径。
6.4 发布前的检查清单
我在发布前的检查经验,总结成清单如下:
- 确认构建配置是Release,不是Debug。Debug版Qt库体积大、运行速度慢,且依赖一大堆调试符号,不适合发布。
- 确认exe目录里的platforms文件夹存在并包含qwindows.dll。这是Qt窗口启动的底线。
- 确认图标、资源文件已经被rcc编译进二进制或正确放置在相对路径。如果用.qrc打包资源,一般编译进exe,不需要额外拷贝。
- 卸载Qt环境变量或者换一台干净机器再运行测试。这一步是验验真章,很多“开发机能跑、别人机器跑不了”的问题在这一步就会暴露。
- 如果有打印功能,确认Qt的打印插件已经部署;如果用了图标主题,确认iconengines插件存在。
这个检查清单看起来琐碎,但每一条都是我实际踩过的坑。尤其是“换台干净机器测试”这条,能过滤掉90%的环境依赖问题。
最后再分享一个小技巧:CLion会自动生成build目录,但如果你的CMakeProfile里开启了多个构建类型(Debug和Release),建议在CMake里用CMAKE_RUNTIME_OUTPUT_DIRECTORY把exe统一输出到一个固定的bin目录,比如${CMAKE_BINARY_DIR}/bin。这样一来,运行时找相对路径的资源、部署时打包目录都会方便很多,不会在build目录里翻来翻去找exe。我在自己的项目模板里一直是这么做的,时间久了,你会发现这种小的目录规划节省的调试时间远比想象的要多。
