
简介面向使用 Qt6.2.4 与 VS2019 进行 x64 开发的工程师这份资源提供了 qtmqtt 的预编译动态库和配套的简单示例工程专门帮助从 Qt5 迁移或初学 Qt6 的开发者消除对 CMake 构建模式的陌生感快速在自己的项目中集成 MQTT 通信能力。压缩包共收录 110 个文件压缩后约 33.36MB其中包含 55 个头文件、4 个导入库和 6 个运行库以及 16 个 CMake 配置模板、若干 pri 工程片段和 bat 批处理脚本可直接复制到现有工程中完成链接与配置同时 pdb、manifest 等文件也为调试和部署提供了便利。demo 目录下的 mqtt 模块设计得十分简洁既可以独立编译演示也能够整体拷贝到其他项目中复用省去手动设置头文件路径、链接库名称和依赖项等繁琐步骤。资源还附带了 Qt 在线安装包和 Perl 安装包帮助用户一次备齐编译环境规避搭建过程中的常见缺口。目前已有 1327 人学习下载非常适合需要基于 Qt6 快速接入 MQTT 的客户端或嵌入式应用开发者。1. 为什么 Qt 6.2.4 VS2019 还要手动编译 qtmqtt 动态库Qt 官方从 Qt 6.0 开始将 MQTT 模块移出了主仓库不再随在线安装包分发预编译二进制。这意味着即便你通过 Qt Maintenance Tool 勾选了全部模块也找不到Qt6Mqtt.dll和对应的头文件。项目里#include QMqttClient能写出来但链接阶段必然报LNK2019: unresolved external symbol。这个坑在高版本 Qt 上尤其常见因为网上大量教程停留在 Qt 5.15 时代那时的 qtmqtt 还在 Qt 官方仓库里直接 git clone 就能用。切换到 6.2.4 后编译方式、模块依赖、CMake 行为都有变化照着旧教程来往往会卡在元对象编译器或 OpenSSL 依赖上。这篇文章要解决的正是这条完整的落地路径在 Windows 10/11 x64 环境下用 VS2019MSVC 2019 x64 工具链编译 qtmqtt 的 x64 动态库并给出一个能跑起来的 MQTT 发布/订阅示例。同时会把 Qt 在线安装包和 Perl 安装包的获取方式、版本匹配关系讲清楚避免在环境准备阶段反复折腾。适合的人群是正在做设备接入、工业网关、车联网终端等场景需要在 Qt 6.2 项目里用 MQTT 协议但不想换用 QNetworkAccessManager 手搓 HTTP 长轮询的开发者。阅读本文后你应该能从零开始独立完成一次 qtmqtt 编译并把生成的动态库和头文件集成到自己的工程里。2. 编译前的三件事Qt 在线安装包、Perl、VS2019 组件核对2.1 Qt 6.2.4 在线安装包到底选哪些组件Qt 官方在线安装器qt-unified-windows-x64-online.exe运行后需要 Qt 账号登录这是许多人在内网环境下的第一道坎。如果没有账号可以用--offline模式或提前下载离线安装包但 6.2.4 的离线包体积超过 10 GB相比之下在线安装更能按需勾选。安装过程中开发者通常会忘记展开Qt节点下对应的编译器分支Qt 6.2.4 ├── MSVC 2019 64-bit # 必须勾选 ├── Qt Debug Symbols # 可选编译 qtmqtt 不需要 ├── Qt Additional Libraries # 建议展开查看 ├── Qt Multimedia # 与 MQTT 无关可跳过 └── Qt Tools ├── Qt Creator # 集成开发环境建议勾选 ├── Qt Debugger # 建议勾选 └── MinGW 11.2.0 # 不需要但勾了也不影响注意MSVC 2019 64-bit这一项决定的是 Qt 库本身是用 MSVC 编译的后续用 VS2019 编译 qtmqtt 时必须让 qtmqtt 的 CMake 找到这个路径下的Qt6Config.cmake。如果装的是 MinGW 版本的 QtVS2019 的 cl.exe 链接时会出现 ABI 不兼容这是初学者最常踩的坑。安装完成后把C:\Qt\6.2.4\msvc2019_64\bin和C:\Qt\6.2.4\msvc2019_64\lib加入系统 PATH。虽然 CMake 通常能通过CMAKE_PREFIX_PATH找到 Qt但加入 PATH 后后续运行时Qt6Mqtt.dll的搜索路径问题也会一并解决。2.2 Perl 不是可选项它是编译 qtmqtt 的必要条件很多从 Linux 过来的工程师会疑惑编译一个 C 库为什么需要 Perl这是因为 qtmqtt 的源码仓库里包含一组由 Perl 脚本生成的源码文件特别是src/mqtt/qmqtt_p.h中的某些枚举定义和序列化辅助代码是在编译前由脚本动态生成的。CMake 配置阶段会检测perl命令找不到就直接报错-- Could NOT find PERL (missing: PERL_EXECUTABLE) CMake Error at qtmqtt/CMakeLists.txt:123 (message): Perl is required to build qtmqtt.所以必须先装 Perl。推荐使用 Strawberry Perl因为它在 Windows 下自带完整的开发环境和依赖管理工具。安装时勾选Add Perl to PATH完成后在 CMD 里验证perl --version看到This is perl 5, version 32, subversion 1之类的输出就说明环境就绪。需要强调的是这里对 Perl 的版本没有严格要求5.30/5.32/5.36 都行关键是安装后要能被 CMake 在 PATH 中找到。提示Perl 装在带空格的路径如 C:\Program Files\Strawberry Perl下时某些旧版 CMake 可能会解析路径出错。遇到这种问题用 8.3 短路径名或重新安装到 C:\Strawberry 下都能解决。2.3 VS2019 必须安装的组件VS2019 的安装策略直接影响编译成败。在 Visual Studio Installer 中除了一般的使用 C 的桌面开发工作负载外还要确认以下单项组件存在MSVC v142 - VS 2019 C x64/x86 生成工具Windows 10 SDK10.0.19041 或更高版本C CMake tools for Windows其中 Windows SDK 版本尤其重要。如果你同时装了 VS2022 的 Windows 11 SDK10.0.22000CMake 默认会挑新版本但这没有问题真正的问题是只装了 VS2022 没装 VS2019 的 v142 工具集那 CMake 生成的工程虽然能打开但编译时找不到cl.exe和vcvars64.bat。判断工具集是否可用的快速方法C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars64.bat执行后没报错且where cl能定位到 cl.exe说明工具链完整。VS2019 的 Community/Professional/Enterprise 三个版本对编译 qtmqtt 没有区别不必纠结版本授权问题。3. 获取 qtmqtt 源码并完成第一个 x64 动态库编译3.1 源码拉取和分支确认qtmqtt 的源码托管在 Qt 官方代码仓库code.qt.io/cgit/qt/qtmqtt.git以及 GitHub 镜像github.com/qt/qtmqtt。Windows 下用 Git Bash 或 CMD 拉取均可关键是分支要匹配 Qt 版本git clone https://github.com/qt/qtmqtt.git cd qtmqtt git checkout 6.2.4这里需要特别说明的是6.2.4这个 tag 不是每个版本都存在。Qt 6.2.x 系列的 qtmqtt 发布节奏和 Qt 本身不完全同步如果git checkout 6.2.4失败可以用git tag -l查看可用 tag选择最接近的如v6.2.4或直接git checkout 6.2。由于 qtmqtt 的维护策略是向后兼容的6.2 分支的最新 commit 也适用于 6.2.4 的 Qt 库。源码目录下的CMakeLists.txt就是后续编译的入口无需额外初始化子模块因为 qtmqtt 没有依赖第三方子仓库。3.2 用 CMake 生成 VS2019 工程并编译动态库qtmqtt 默认构建出来的目标类型是动态库SHARED不需要你去改任何 CMake 参数只要配置时没有显式声明BUILD_SHARED_LIBSOFF产物就是 Qt6Mqtt.dll。进入源码目录创建一个构建目录然后执行配置mkdir build cd build cmake .. -G Visual Studio 16 2019 -A x64 -DCMAKE_PREFIX_PATHC:/Qt/6.2.4/msvc2019_64 -DCMAKE_BUILD_TYPERelease这条命令的含义是-G指定生成 VS2019 工程-A x64声明目标架构为 x64CMAKE_PREFIX_PATH告诉 CMake 去哪里找 Qt6 的 CMake 配置文件CMAKE_BUILD_TYPE在单配置生成器中不影响实际构建但写上无妨。配置成功后用下面的命令编译 Release 版本cmake --build . --config Release --parallel 8--config Release在 VS 生成器中是必需的因为 MSVC 的多配置模式默认不生成任何版本。--parallel 8控制并行编译任务数对 qtmqtt 这样的小库来说意义不大但如果你同时开启了其他项目会有帮助。编译完成后检查输出目录dir .\lib\Release\*.dll dir .\lib\Release\*.lib dir .\lib\Release\*.pdb正常情况下能看到Qt6Mqtt.dll、Qt6Mqtt.lib和Qt6Mqtt.pdb。Qt6Mqtt.lib是导入库链接阶段用Qt6Mqtt.dll是运行时加载的实际代码PDB 文件如果不需要断点调试可以不用保留但建议留着后续排查QMqttClient内部行为时会更方便。注意如果编译过程中报LNK1104 cannot open file Qt6Core.lib不是 qtmqtt 的代码问题而是 CMake 没有正确找到 MSVC 编译的 Qt 6.2.4 库路径。检查CMAKE_PREFIX_PATH并确认指向的路径下存在lib\cmake\Qt6目录。3.3 动态库依赖 Qt6Core.dll 和 Qt6Network.dll 的注意事项编译成功后先别急着把 Qt6Mqtt.dll 拷到系统目录。这个动态库对 Qt 6.2.4 的Qt6Core.dll和Qt6Network.dll有直接依赖运行时若找不到它们会弹错误对话框The code execution cannot proceed because Qt6Core.dll was not found。QMqttClient内部基于QAbstractSocket和QHostAddress实现网络通信所以 Qt6Network 是必须的。部署到目标机器时通常有三种方案一是把整个 Qt 目录拷过去并将bin加入 PATH适合开发调试二是用 windeployqt 工具自动拷贝 Qt 运行库到 exe 目录适合交付小工具三是静态编译 Qt 本身彻底免除动态库分发但静态编译 Qt 6.2.4 耗时较长且需要额外配置 OpenSSL一般不推荐仅为了 MQTT 模块这么做。C:/Qt/6.2.4/msvc2019_64/bin/windeployqt.exe --release --no-opengl-sw --no-system-d3d-compiler --no-angle --no-egd ./your_app.exewindeployqt 会扫描 exe 的导入表自动把 Qt6Core.dll、Qt6Network.dll、Qt6Mqtt.dll 以及对应的 plugins 目录一并拷贝到当前目录。注意--no-*参数是去掉不需要的图形相关组件让输出目录更精简。执行后建议再检查一下platforms\qwindows.dll是否存在没有这个插件GUI 程序会直接闪退或报could not find a Qt platform plugin与 MQTT 无关却最容易在联调阶段绊倒人。4. 验证动态库与编写发布/订阅示例程序4.1 用 dumpbin 确认 dll 导出符号编译完成后验证动态库是否正确的最终手段是检查导出符号。x64 下的 MSVC 编译产物没有 32 位时代的下划线前缀问题导出函数名可以直接对应到 C 符号。使用 VS2019 自带的 dumpbin 工具C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\dumpbin.exe /exports C:\qtmqtt\build\lib\Release\Qt6Mqtt.dll输出中会列出 DLL 导出的所有符号。重点观察是否存在?staticMetaObjectQMqttClient2UQMetaObjectB之类的 Qt 元对象符号以及public: __cdecl QMqttClient::QMqttClient(class QObject *)构造函数。如果导出表为空说明编译配置出了问题常见的诱因是在CMakeLists.txt中意外设置了BUILD_SHARED_LIBSOFF或在源码根目录的.pro文件旧的 qmake 项目里把CONFIG staticlib写死了。对于 64 位动态库还需要确认导入库Qt6Mqtt.lib与 DLL 的位数一致。可以用dumpbin /headers Qt6Mqtt.dll | findstr machine看到x64即为匹配。如果你在 32 位机器上编译出 x64 的 DLL部署到 64 位系统上运行时反而会有问题因为 Qt 6.2.4 官方只提供 x64 和 arm64 的预编译版本x86 环境下需要自己从源码编译整套 Qt。4.2 最小可运行的 MQTT 发布端示例接下来创建一个最简单的 Qt Widgets 或控制台程序来验证动态库。在 VS2019 中新建Qt Console Application工程配置时选择 Qt 6.2.4 msvc2019_64 的 Kit然后在工程属性的VC 目录中设置包含目录C:\qtmqtt\lib\includeqtmqtt 源码中的 include 路径也可能在src\mqtt目录库目录C:\qtmqtt\build\lib\Release附加依赖项Qt6Mqtt.libCMake 会自动链接 Qt6Core.lib 和 Qt6Network.lib但手写时别漏了这两个示例代码中main.cpp只做一件事创建QMqttClient实例连接本机 1883 端口然后发布一条主题为qtmqtt/test的消息。这里用std::chrono::seconds控制循环次数避免死循环。#include QCoreApplication #include QMqttClient #include QDebug int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QMqttClient client; client.setHostname(127.0.0.1); client.setPort(1883); client.setUsername(test); client.setPassword(test123); // 连接状态变化时输出日志 QObject::connect(client, QMqttClient::stateChanged, [](QMqttClient::ClientState state) { qDebug() state changed: state; }); // 连接成功后立即订阅主题 QObject::connect(client, QMqttClient::connected, [client]() { qDebug() connected to broker; client.subscribe(qtmqtt/response, 0); // QoS 0 }); client.connectToHost(); // 异步连接不阻塞 // 用定时器在 3 秒后发布消息 QTimer::singleShot(3000, client, [client]() { client.publish(qtmqtt/test, hello from qt6, 0, false); qDebug() message published; }); return app.exec(); }这段代码的意图很清晰setHostname和setPort指定 broker 地址stateChanged信号在连接状态机切换时触发Disconnected - Connecting - Connectedsubscribe的第三个参数是 QoS 等级这里用 0 表示最多一次投递适合验证场景publish的四个参数分别是主题、载荷、QoS 和 retain 标志。整个流程是异步的connectToHost()返回后事件循环处理底层 socket这也是 Qt 网络模块的典型行为。编译运行前确保本机已经有一个 MQTT broker。Windows 上最轻量的是下载 Mosquitto 的 Windows 安装包安装后执行net start mosquitto启动服务或者前台模式mosquitto -v。没有 broker 的话连接会打印state changed: 2Connecting后长时间停留在该状态不会报错也不会超时这是 Qt MQTT 与直接 socket 编程的一个差异点调试时容易被误判成程序假死。4.3 订阅端验证和 topic 过滤器仅仅发布消息不足以证明双向链路通畅再用 Qt 写一个订阅端来接收刚才发布的消息。可以用同一个示例程序增加一个参数来切换模式也可以另建工程。订阅端代码#include QMqttClient #include QDebug void runSubscriber() { QMqttClient sub; sub.setHostname(127.0.0.1); sub.setPort(1883); // 收到消息回调 QObject::connect(sub, QMqttClient::messageReceived, [](const QByteArray message, const QMqttTopicName topic) { qDebug() topic: topic.name() payload: message; }); QObject::connect(sub, QMqttClient::connected, [sub]() { sub.subscribe(qtmqtt/); // 通配符 匹配单层主题 }); sub.connectToHost(); }messageReceived信号的第一个参数是消息载荷第二个参数是主题对象不是简单的字符串。subscribe时用qtmqtt/可以匹配qtmqtt/test但不会匹配qtmqtt/a/b因为只匹配一层。如果你想匹配所有子主题用qtmqtt/#。这里的 QoS 参数和 messageReceived 回调之间没有直接绑定关系无论 broker 以什么 QoS 投递回调里拿到的都是完整消息。如果要获取每条消息实际的 QoS 等级需要重写QMqttSubscription的消息处理函数这个细节常见于实测报告和踩坑记录中。5. 三个常见编译报错从报错文本反推根因5.1 LNK2038 或 C1189 的 _MSC_VER 不匹配当你用 VS2019 编译 qtmqtt 时如果编译器提示_MSC_VER相关的#error或链接器报LNK2038 mismatch detected for _MSC_VER几乎可以肯定是了编译器版本混用的问题。比如 VS2019 安装了 v142 工具集但在 CMake 中通过-T v142指定了低于 14.29 的版本而 Qt 6.2.4 预编译库是用 14.29 编译的。解决方式是打开 Vs 安装目录下的vcvars64.bat并查看_MSC_VER环境变量如果是 1929对应 14.29切换工具集到 v142 的最新更新。你的工程如果是从 VS2019 升级到 VS2022报错文本可能变成_MSC_VER defined in Qt6Core与_MSC_VER defined in your_project的不一致。这种场景下不需要重编 qtmqtt只要把项目的Platform Toolset从 v143 改回 v142 即可因为 Qt 6.2.4 官方发布时没有用 VS2022 验证过所有模块。5.2 cmake 找不到 Qt6MqttConfig.cmakeqtmqtt 编译安装后不会自动把 CMake 配置文件拷贝到 Qt 的安装目录。你在自己的工程里写find_package(Qt6 Mqtt REQUIRED)如果 CMake 报Could not find a package configuration file named Qt6MqttConfig.cmake根本原因是 qtmqtt 的安装路径不在CMAKE_PREFIX_PATH中。编译 qtmqtt 时在 build 目录之外再执行一次安装是更规范的做法cmake --install . --prefix C:/qtmqtt_install执行后C:/qtmqtt_install/lib/cmake/Qt6Mqtt下会出现Qt6MqttConfig.cmake和Qt6MqttConfigVersion.cmake。随后在项目里用 CMake 集成时set(CMAKE_PREFIX_PATH C:/qtmqtt_install ${CMAKE_PREFIX_PATH}) find_package(Qt6 COMPONENTS Core Network Mqtt REQUIRED) target_link_libraries(MyApp PRIVATE Qt6::Mqtt)注意到这里find_package必须把Network也带上因为Qt6::Mqtt的目标定义里INTERFACE_LINK_LIBRARIES引用了Qt6::Network少写 Network 会在生成阶段报target Qt6::Mqtt links to target Qt6::Network but the target was not found。这个报错的频率非常高新手往往直接把罪归到 qtmqtt 编译过程实际只是自己的 CMakeLists 写得不够严谨。5.3 运行时 QMqttClient 构造后直接崩溃程序能编译、能链接但运行到QMqttClient client;这一行就崩通常不是 qtmqtt 的问题而是 Qt 插件系统加载异常。定位方法是看崩溃栈是否在QLibraryPrivate::load_sys如果是说明qmqtt.dll在加载时连带加载的 Qt6Core.dll 版本不匹配。典型场景是把 VS2019 debug 编译的 Qt6Mqtt.dll 放进了 release 版程序目录或反过来。调试信息确认方式QStringList paths QCoreApplication::libraryPaths(); for (const QString p : paths) { qDebug() p; }确认输出的路径中能找到C:/Qt/6.2.4/msvc2019_64/plugins。此外Qt 6 下动态库的 debug/release 混合使用不会报DLL init failed但会在qDebug中输出Qt6Mqtt.dll is compiled with debug symbols, but the application is compiled release之类的提示然后可能持续工作也可能随机崩溃。最简单根治方式是 debug/release 各编译一次 qtmqtt两个版本的 dll 分开存放部署时严格对齐配置。6. 用 qmake 不走 CMakeqmake 工程直接编译 qtmqtt 的方式如果你的项目仍是 qmake 体系.pro文件则编译 qtmqtt 和集成方式会更绕一点但思路清晰。qtmqtt 的源码仓库里保留了.pro文件适用于 qmake 编译。先打开 Qt 6.2.4 的 MSVC 命令行环境C:\Qt\6.2.4\msvc2019_64\bin\qtenv2.bat然后进入 qtmqtt 源码目录依次执行qmake nmake releaseqmake 模式下nmake release会在当前目录生成lib和include两个子目录。lib下有Qt6Mqtt.lib和Qt6Mqtt.dllinclude下有QtMqtt和QtMqtt/6.2.4/QtMqtt两个目录层级。这里有一个容易忽略的细节qmake 生成的.pro文件默认会根据qtConfig(mqtt)判断是否启用编译但 Qt 6.2.4 没装 qtmqtt 模块时qtConfig(mqtt)返回 false需要手动修改qtmqtt.pro或直接用CONFIG mqtt指定。更稳妥的做法是在命令行加参数qmake CONFIGrelease CONFIGmqtt集成到工程时在.pro文件中加入INCLUDEPATH C:/qtmqtt/include LIBS -LC:/qtmqtt/lib -lQt6Mqtt对比 CMake 方式qmake 的集成门槛略低但不会自动处理 Qt6Network 的依赖如果目标程序里没有其他地方引用 Qt6Network需要在 LIBS 中手动补充-lQt6Network。实际项目里我更推荐 CMake 路径因为 Qt 6 官方新项目已全面迁移 CMakeCMake 的find_package能解决全部传递依赖。qmake 路径更适合需要快速验证或正在维护 Qt5 遗留工程的情况。无论走哪条路编译出来的Qt6Mqtt.dll本质上是同一个 ABI可以互相替换使用。本文还有配套的精品资源点击获取