简介:面向需要在 VS2019 中使用 MQTT C++ 客户端的开发者,这份编译好的 paho.mqtt.cpp 库压缩包可省去从源码搭建编译环境、处理 CMake 配置与第三方依赖的繁琐过程。压缩包内含 VS2019 完整工程与解决方案,源码、可用的 dll 和 lib 库均已备齐,拿到后即可集成进自己的 MQTT 通信项目。资源共 550 个文件,整体约 64.21MB,主要包含 cpp/h 源码、lib/dll 库文件、vcxproj/sln 工程配置、cmake 构建脚本以及 exe/pdb 等调试产物,目录结构完整,适合直接参考或复用。目前已有 2979 人学习,说明这套编译产物对不少 MQTT 开发者有实际帮助。对于想深入理解 paho.mqtt.cpp 编译过程、又不想踩依赖坑的 C/C++ 开发者,这份资源提供了现成的 VS2019 工程组织方式、CMake 生成文件和目标文件;同时保留完整的 CMake 生成信息,便于复现构建;既能快速运行示例,也能对照源码与生成库排查头文件路径、链接库选择等常见集成问题。
1. 别把 paho.mqtt.cpp 当独立库:VS2019 编译前先看清这条依赖链
在 VS2019 下把 paho.mqtt.cpp 编成能直接用的库,卡住过不少刚开始碰 MQTT 的 C++ 开发者。它的坑不在代码本身,而是它不是一条命令能编完的独立库——前面还压着一层 paho.mqtt.c 的 C 依赖。只拉 C++ 库的源码直接 cmake,十有八九会卡在找不到 PahoMqttC 包这一步;就算勉强编过,接入自己工程后还会遇到 DLL 缺失、0xc000007b、链接报错一串串。这篇笔记按我在 Windows 上做 MQTT 客户端的习惯整理:从拉源码、配 CMake、编 C 库、编 C++ 库,到接进 VS2019 工程再验证,一条链全部打通。照着走大概半小时能拿到 x64 的 Release/Debug 产物,适合正被 CMake 报错、缺库、版本不对付折腾的人。
2. 编译前的三件套:CMake 版本、VS2019 工具集与 paho.mqtt.c 依赖
2.1 为什么必须先编译 paho.mqtt.c:库的分层关系
paho.mqtt.cpp 名字里带个完整客户端,实际上它是层 C++ 封装,真正干活的是底层的 paho.mqtt.c:TCP 连接、协议编解码、QoS 重发、心跳包全在 C 库里,C++ 层只负责把异步回调整理成 client 这类顺手用的类。这也解释了为什么配置 C++ 库时一定会执行 find_package(PahoMqttC)——这不是可选项,C 库的头文件和导入库缺一个都编不过。你翻它的 CMakeLists 能看到 PahoMqttC 被标成 REQUIRED,找不到就直接报错退出。
所以编译顺序没有捷径:先把 paho.mqtt.c 编好并 install 到固定目录,再让 paho.mqtt.cpp 用 CMAKE_PREFIX_PATH 指向这份安装。我一般把两个库装到同一个根目录下,比如 D:/deps/paho-c 和 D:/deps/paho-cpp,工程里引用路径写死,换机器重编也快。别图省事把 C 库的 build 目录当安装目录用:C++ 库的 CMake 找的是安装时生成的 PahoMqttCConfig.cmake,build 目录里没有这个文件,找不到就是找不到。
C 库选型也要提前定:异步还是同步、带不带 TLS。paho.mqtt.cpp 内部走的是 MQTTAsync 异步接口,所以 C 库至少要把异步那组(paho-mqtt3a 系列)编出来;如果 broker 要求 TLS 连接,C 库必须带 SSL 编译,产物是 paho-mqtt3as 系列。这两个变体是不同的 lib,链接对象不一样,先想清楚后面就不用返工。我的建议是即使暂时不用 TLS,也把 SSL 选项打开编一份,省得换服务器时被"只支持 TLS 端口"卡住。
2.2 CMake 生成器与平台:为什么固定 Visual Studio 16 2019
VS2019 对应的 CMake 生成器名是 Visual Studio 16 2019,CMake 版本建议 3.20 以上。版本太低有两个老毛病:新选项不识别、FindOpenSSL 找不到新版 OpenSSL。用 VS 生成器而不是 MinGW Makefiles 的理由很实际:生成的 .sln 可以在 VS2019 里直接打开调试,断点能一路跟到 C 库源码,排查协议层问题时比黑盒调接口快太多。工具集对应 v142,如果机器上同时装了 VS2022,建议在命令行里显式加 -T v142,保证产物和 VS2019 环境完全对齐;只装 VS2019 的话不写也没事,CMake 会挑默认工具集。
平台参数用 -A x64 写死。接下来 C 库、C++ 库、业务工程三者的架构必须保持一致,混用会在两个阶段爆雷:链接期报 LNK1112 模块计算机类型冲突,或者运行期弹 0xc000007b。Release 和 Debug 也要分开处理,两个配置的运行时库不同,一套产物不能通吃。另外源码目录路径不能带中文和空格,CMake 对这类路径支持时好时坏,D:/deps 这种纯英文路径最省心,算是 Windows 编 C/C++ 的老规矩。
注意:Windows 的 cmd 里换行续行用 ^,PowerShell 里要用反引号。下面命令以 cmd 写法为准。
| 参数 | 作用 | VS2019 场景建议 |
|---|---|---|
| -G "Visual Studio 16 2019" | 选择生成器 | 固定,对应 VS2019 |
| -A x64 | 目标架构 | 全链统一 x64 |
| -T v142 | 工具集 | 多版本 VS 并存时必加 |
| --config Release | 编译配置 | 每个配置单独编译 |
补充一个环境检查:第一次动手前先确认 cmake --version 能正常输出,并且你是在 VS2019 的开发者命令提示符里跑。普通 cmd 里经常出现 cl 找不到、环境变量错乱的问题,换成 x64 Native Tools Command Prompt for VS2019 再执行,比去改系统 PATH 靠谱得多。
3. 先编译 paho.mqtt.c:CMake 配置、安装目录与 TLS 开关
3.1 拉源码、生成 VS2019 工程:最小命令
git clone https://github.com/eclipse-paho/paho.mqtt.c.git cd paho.mqtt.c git checkout <最新 release 标签> # 别用 master 最新提交做生产 cmake -B build -G "Visual Studio 16 2019" -A x64 ^ -DCMAKE_INSTALL_PREFIX=D:/deps/paho-c ^ -DPAHO_WITH_SSL=ON ^ -DPAHO_ENABLE_TESTING=OFF cmake --build build --config Release cmake --install build参数说明:
- -B build:指定构建目录,生成的 paho.sln 在 paho.mqtt.c/build 下,之后可以 cmake --build build 增量编译,不用重新配置
- CMAKE_INSTALL_PREFIX:安装根目录,头文件和 lib 最终拷到这里;下一步 C++ 库就是靠这个路径定位 C 库
- PAHO_WITH_SSL:ON 时 C 库会去找 OpenSSL,生成带 TLS 的 paho-mqtt3as 系列;暂时不需要可改 OFF,少一个 OpenSSL 的坑,但以后要用 TLS 就得重编
- PAHO_ENABLE_TESTING:关掉,默认开的话会编一堆测试 target,Windows 上还容易带出 pthread 依赖问题
- --config Release:VS 是多配置生成器,必须靠它选编译配置;编 Debug 就换成 --config Debug,install 同样要跑一遍
这里有个从 Linux 转 Windows 的人常犯的错:在配置阶段加 -DCMAKE_BUILD_TYPE=Release。VS 生成器下这个变量不生效,配置时不报错,编出来的还是默认 Debug 配置。正确做法是让 --config 参数来控制。git checkout 那一步也别省,master 上可能有半成品提交,用两个仓库各自的 release 标签(格式类似 v1.x,以仓库实际 tag 为准),两边版本对应关系最省心。
3.2 安装目录结构:C 库给 C++ 库留的接头暗号
执行 install 之后,D:/deps/paho-c 应该是这样的结构:
D:/deps/paho-c/ ├─ include/ │ ├─ MQTTAsync.h │ ├─ MQTTClient.h │ ├─ MQTTProperties.h │ └─ MQTTReasonCodes.h ├─ lib/ │ ├─ paho-mqtt3a.dll │ ├─ paho-mqtt3a.lib │ ├─ paho-mqtt3as.dll # PAHO_WITH_SSL=ON 时才有 │ └─ paho-mqtt3as.lib └─ cmake/ └─ PahoMqttCConfig.cmake这个 cmake/PahoMqttCConfig.cmake 就是接头暗号。paho.mqtt.cpp 的 CMake 在 find_package(PahoMqttC) 时,会通过你给的 CMAKE_PREFIX_PATH 去查这个文件,查不到直接报 Could NOT find PahoMqttC。所以 install 这步不能省。很多人第一次编 C 库只跑了 cmake --build,build/src/Release 里明明有 dll 和 lib,但 C++ 库就是找不到包,原因就是没执行 install,没有生成这个 Config 文件。
异步和同步的差异在这里也看得清楚。paho-mqtt3a 是 async 版本,paho.mqtt.cpp 底层用的是它;如果你以后想直接用 C 库的同步接口,那组 paho-mqtt3c 系列也在这个目录里。目录下还可能有 paho-mqtt3a-static.lib 这类静态产物,取决于 C 库 CMake 的默认设置,Windows 上建议把动态和静态都留一份,后面接入工程时按部署方式选。
还有一点容易忽略:Release 和 Debug 的 install 目录最好分开,比如 D:/deps/paho-c 和 D:/deps/paho-c-debug。两个配置的 dll/lib 同名,装到同一个目录后面那个会覆盖前面那个,等你切配置调试时会发现库行为对不上,白白浪费半天。
4. 编译 paho.mqtt.cpp 并把产物接进 VS2019 工程
4.1 CMake 配置:用 CMAKE_PREFIX_PATH 让 C++ 库找到 C 库
git clone https://github.com/eclipse-paho/paho.mqtt.cpp.git cd paho.mqtt.cpp git checkout <最新 release 标签> # 和 C 库的版本对应起来 cmake -B build -G "Visual Studio 16 2019" -A x64 ^ -DCMAKE_PREFIX_PATH=D:/deps/paho-c ^ -DCMAKE_INSTALL_PREFIX=D:/deps/paho-cpp ^ -DPAHO_BUILD_STATIC=ON ^ -DPAHO_BUILD_SHARED=ON ^ -DPAHO_BUILD_SAMPLES=OFF ^ -DPAHO_ENABLE_TESTING=OFF cmake --build build --config Release cmake --install buildCMAKE_PREFIX_PATH 指的是 C 库安装目录,C++ 库的 find_package 会顺着这个路径找到 PahoMqttCConfig.cmake。PAHO_BUILD_STATIC 和 PAHO_BUILD_SHARED 控制产物组合,两个都开最稳妥,一个给调试用,一个给发布用。PAHO_BUILD_SAMPLES 和 PAHO_ENABLE_TESTING 关掉,省编译时间,示例程序你大概率用不上。
如果配置时看到 Manually-specified variables were not used 的警告,说明某个选项名在当前版本里不存在或被改名,不影响编译主流程,但最好去官方 CMakeLists 里确认一遍选项名。链接期如果报找不到 OpenSSL 符号,说明 C 库编的是带 TLS 版本,你的工程链接时需要把 OpenSSL 的库也带上,这一点在 4.3 里会说。
4.2 产物清单:dll、lib、exp 各干什么
Release 编译完成后,默认产物在 build/src/Release 下,install 后会统一拷到 D:/deps/paho-cpp/lib。四个文件各司其职:
| 文件 | 类型 | 链接期 | 运行期 |
|---|---|---|---|
| paho-mqtt.dll | C++ 动态库本体 | 不需要 | exe 同目录或 PATH |
| paho-mqtt.lib | 动态库导入库 | 链接器附加依赖项 | 不需要 |
| paho-mqtt-static.lib | 静态库 | 链接器附加依赖项 | 不需要 |
| paho-mqtt.exp | 导出符号表 | 一般不用 | 排查符号导出问题时才看 |
exp 文件平时不用管,只有你怀疑动态库符号没导全时,拿 dumpbin /exports paho-mqtt.dll 看一眼确认。链接器用的是 lib,不是 dll,很多人在这里搞反,把 dll 填进附加依赖项,链接器直接报找不到库文件。
4.3 把库接进 VS2019 工程:四处配置
新建一个 C++ 控制台工程,属性页按下面顺序配:
- C/C++ → 常规 → 附加包含目录:加 D:/deps/paho-cpp/include
- C/C++ → 代码生成 → 运行时库:Release 默认 /MD,工程保持默认就行
- 链接器 → 常规 → 附加库目录:加 D:/deps/paho-cpp/lib 和 D:/deps/paho-c/lib
- 链接器 → 输入 → 附加依赖项:填 paho-mqtt.lib; paho-mqtt3a.lib(动态库方案),或 paho-mqtt-static.lib; paho-mqtt3a-static.lib(静态库方案,文件名以实际目录为准)
如果 C 库是带 TLS 编的,第 4 步要把 paho-mqtt3a.lib 换成 paho-mqtt3as.lib,并去 OpenSSL 安装目录的 lib 下把 libssl.lib 和 libcrypto.lib 一并加进附加依赖项。链接成功后,运行前把 paho-mqtt.dll 和 paho-mqtt3a.dll(以及 OpenSSL 的 dll)拷到 exe 输出目录;我习惯直接拷 DLL,部署时少一层环境依赖,比改系统 PATH 干净。
#include <mqtt/client.h> #include <iostream> int main() { mqtt::client cli("tcp://127.0.0.1:1883", "vs2019_demo"); mqtt::connect_options opts; opts.set_keep_alive_interval(20); // 心跳间隔,超时会被 broker 踢掉 opts.set_clean_session(true); // 测试场景用 true,清掉残留会话 cli.connect(opts); cli.publish("demo/topic", mqtt::buffer("hello paho"), 1, false); cli.disconnect(); std::cout << "ok" << std::endl; return 0; }这段代码故意不包 try/catch,让异常直接抛出来,方便看 MQTT 返回码和错误文本。编译前确认 include 路径能找到 mqtt/client.h;运行时如果报找不到 paho-mqtt.dll,回到 4.3 开头说的拷贝步骤检查。publish 的第三个参数 1 是 QoS,第四个 false 是不保留消息,这两个值在自测时最常用。
5. 编译和链接阶段的高频翻车点:5 个排查记录与解决步骤
5.1 CMake 提示 Could NOT find PahoMqttC
现象:配置 paho.mqtt.cpp 时,CMake 报 Could NOT find PahoMqttC(missing: PahoMqttC_DIR),然后直接退出。
原因:最常见两种。一是 CMAKE_PREFIX_PATH 没传或路径写错;二是 C 库只跑了 cmake --build,漏了 cmake --install,目标目录里根本没有 PahoMqttCConfig.cmake。
解决:先看 D:/deps/paho-c 下有没有 cmake/PahoMqttCConfig.cmake,没有就回去补 install。有的话检查命令行里路径格式,我统一写成 D:/deps/paho-c 这种正斜杠,写在 -D 参数里不容易被 cmd 转义吃掉。别把反斜杠和引号混在一起写,那是 Windows 命令行报错的高发区。
5.2 运行时报找不到 DLL 或者 0xc000007b
现象:工程编译链接全过,启动 exe 弹"找不到 paho-mqtt.dll",或者直接报 0xc000007b。前者好理解,后者看着像玄学,其实是系统在拒绝加载。
原因:找不到 DLL 是运行期依赖缺失;0xc000007b 通常是 DLL 的架构和进程不一致,x64 的库被 32 位进程加载,Windows 直接拒绝执行。
解决:把 paho-mqtt.dll、paho-mqtt3a.dll 拷到 exe 同目录,然后在 VS2019 开发者命令提示符里跑 dumpbin /headers,确认 DLL 的 machine 字段是 x64。临时加到 PATH 只能用来验证,发布还是要拷 DLL。如果问题还在,用 Dependencies 工具看缺哪个传递依赖,比逐个换 DLL 快得多。
5.3 静态库链接报一堆 unresolved external symbol
现象:换成 paho-mqtt-static.lib 后,链接器冒出一串 _imp开头或 MSVCRT 相关的 unresolved external symbol,换回动态库又没事。
原因:静态库把 CRT 调用也编进了产物,库编译时的运行时库(/MD 还是 /MT)和你的工程不一致,符号就对不上。动态库不受影响,因为 CRT 符号走的是导入表。
解决:打开工程属性 C/C++ → 代码生成 → 运行时库,和库保持一致。最省心的做法是编译两个库时在 CMake 加 -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL,业务工程统一 /MD;想要彻底免 DLL 依赖就选 /MT,但所有参与链接的库都必须 /MT,混一个都不行。
5.4 TLS 功能没生效:要么找不到 OpenSSL,要么链接不过
现象:程序连带 TLS 的 broker 端口,connect 抛异常或直接失败;个别情况编译期就报找不到 ssl 相关符号。
原因:C 库编的时候 PAHO_WITH_SSL 是 OFF,或者 OpenSSL 路径不对,导致即使开了 ON,TLS 变体也没编出来。
解决:先装 OpenSSL 的 Windows 预编译安装包,编译 C 库时加 -DOPENSSL_ROOT_DIR=D:/OpenSSL 和 -DPAHO_WITH_SSL=ON,确认安装目录里有 include/openssl/ssl.h。编完用 dumpbin /dependents 看 paho-mqtt3as.dll 依赖了哪个版本的 libssl/libcrypto,运行期把对应的 DLL 放进 exe 目录。注意 OpenSSL 1.1 和 3.x 的 DLL 命名规则不同,两个版本不要混用。
5.5 旧版本 C 库在 Windows 上报 pthread 相关错误
现象:编译 paho.mqtt.c 时,链接器报 pthread_create、pthread_once 等 unresolved external,或者头文件阶段找不到 pthread.h。
原因:较早版本的 C 库在 Windows 上依赖 pthreads-win32 提供 pthread API,环境里缺这份依赖;较新版本已经改走系统线程封装,不再需要外部 pthread。
解决:优先切到较新的 release 标签重新编 C 库,一了百了。如果因为业务原因必须锁在旧版本,下载 pthreads-win32 二进制,把 include 和 lib 目录加进 CMake 路径,链接时补 pthreadVC2.lib,运行目录放 pthreadVC2.dll。这也是我在 3.1 里强调用 release 标签不用 master 的原因之一。
注意:这五个翻车点背后其实是同一句话——版本、架构、运行时库三处必须对齐。库编译报错先自检这三项,再查具体符号,别一上来就怀疑源码有问题。
6. 验证编译产物:10 秒跑通一个自订阅自发布
编译链走通不等于库能用。我的验证习惯是起一个本地 broker(比如 mosquitto,默认端口 1883),写一个能同时订阅和发布的小程序,把消息发出去再收回来,收到才算这份 paho.mqtt.cpp 合格。这个测试能一次性暴露三类问题:DLL 加载失败、TLS 配置不对、QoS 流程异常。
#include <mqtt/client.h> #include <iostream> #include <chrono> int main() { mqtt::client cli("tcp://127.0.0.1:1883", "verify_cpp"); cli.connect(); cli.subscribe("verify/topic", 1); cli.publish("verify/topic", mqtt::buffer("ping"), 1, false); auto msg = cli.try_consume_message_for(std::chrono::seconds(5)); if (msg) { std::cout << msg->get_topic() << " -> " << msg->to_string() << std::endl; cli.disconnect(); return 0; } std::cerr << "timeout waiting message" << std::endl; return 1; }try_consume_message_for 最多阻塞 5 秒,超时返回空指针,比裸用 consume_message 挂死友好。把收到的 topic 和 payload 打出来,能顺手确认订阅 QoS 和发布参数一致。跑通之后再回去写业务代码,心态会完全不一样:库是自己编的,问题都在自己的逻辑里,排查范围一下子小了很多。
再补一个部署习惯。我见过不少项目用动态库接入,交付时漏带 DLL,现场装完就报缺库。所以现在收尾动作固定成这样:把 paho-mqtt.dll、paho-mqtt3a.dll(以及 OpenSSL 的 DLL)和 exe 放进同一个发布目录,并写进交付清单;如果目标是免安装绿色包,改用静态库方案,但整个工程要统一 /MT,代价是 exe 体积涨一到两倍。每次升级库版本,我都重新跑一遍从 C 库开始的整条编译链,再跑一遍上面的自订阅自发布,确认 QoS1 消息能回来才让代码进主干。这套流程帮我避掉的坑,比翻文档管用得多。希望帮到你。
本文还有配套的精品资源,点击获取