简介:面向 Windows 平台 C++ 开发者,尤其是需要在 VS2019 环境下集成 JSON 解析与 JSON-RPC 通信能力的工程师,这份资源提供已静态编译完成的 libjsoncpp 与 libjson-rpc-cpp 库,可直接用于项目。相比网络上流传的同类包,它补齐了缺失的 libjsoncpp 文件,并采用 X64 架构编译,避免 x86 版本在 64 位工程中无法链接的问题。压缩包共 355 个文件,约 20.82MB,包含 4 个 lib 静态库、3 个 sln 解决方案、4 个 vcxproj 工程文件,以及 27 个 cpp 源文件、25 个头文件、16 个 Python 脚本和若干 json 配置、日志与构建中间文件,既可直接取用库文件,也能基于工程自行二次编译为 X64 或 x86 版本。已有 475 人学习下载,适合希望省去繁琐编译配置、快速搭建 JSON-RPC 服务端与客户端的中高级开发者参考使用。
1. 拿到 libjsoncpp 和 libjson-rpc-cpp 静态库,先别急着往 VS2019 里拖
上周帮一个做桌面端采集工具的朋友收拾构建环境,他项目里要用 JSON 做本地配置读写,还要跑一套 JSON-RPC 做进程间调用。他图省事,从网上随手抓了两个动态库版本的 jsoncpp 和 json-rpc-cpp,结果在 VS2019 里一编译就是一堆 LNK2019 未解析外部符号,换 Debug/Release 又报运行库不匹配,折腾一下午没跑起来。这类坑在 Windows 上太常见了:jsoncpp 和 libjson-rpc-cpp 本身不复杂,难的是编译期和链接期的运行库、字符集、架构三件事必须对齐。这篇记录的就是我拿到一份已经静态编译好的 libjsoncpp 和 libjson-rpc-cpp 之后,怎么在 VS2019 里把它接进工程、怎么配、装坏了怎么救。适合正在做 Windows C++ 桌面项目、需要本地 JSON 解析和轻量 RPC 的开发者,新手能照着走通,熟手能对一下版本和参数取舍。
2. 环境对齐:VS2019 工具集、运行库和架构三件套
静态库能不能直接用,九成取决于「编译库的那套环境」和「你工程的那套环境」是否一致。jsoncpp 和 libjson-rpc-cpp 都是 C++ 库,静态链接时会把库内部的运行库依赖一起带进来,一旦两边对不上,链接器就会用 LNK2038、LNK2019 这类错误告诉你「我们不熟」。所以第一步不是写代码,而是把环境列清楚。
2.1 确认 VS2019 的 MSVC 工具集版本
VS2019 默认装的是 v142 工具集,但小版本之间也有差异。打开「Developer Command Prompt for VS 2019」,敲:
cl输出第一行会带版本号,形如Microsoft (R) C/C++ Optimizing Compiler Version 19.29.xxxxx for x64。19.29 对应 VS2019 的 16.11 系列,这是 v142 的最后一个大版本。静态库如果是用 19.2x 编的,通常能兼容;如果库是用 VS2022 的 v143 编的,链接时大概率报LNK2038: 检测到“_MSC_VER”的不匹配项。我一般会先问清楚库的编译工具集,问不到就用dumpbin反查,后面 2.3 会讲。
提示:不要用 VS2019 打开一个用 VS2022 创建的 sln 再降级,工具集回退经常留下隐藏的
PlatformToolset残留,清理不干净会反复报错。
2.2 运行库选项必须和静态库一致
这是静态链接最容易翻车的地方。VS 工程的「C/C++ → 代码生成 → 运行库」有四个选项:/MT、/MTd、/MD、/MDd。静态库如果是以/MT(多线程静态运行库)编的,你的工程也必须用/MT;用/MD就会报LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”。
常见做法是:拿到静态库先看它带不带libcmt的符号。用dumpbin /directives看库文件里的/DEFAULTLIB指令:
dumpbin /directives libjsoncpp.lib | findstr DEFAULTLIB如果输出里有LIBCMT,说明是/MT系列;有MSVCRT,就是/MD系列。带d后缀的库(如libjsoncppd.lib)一般对应 Debug 运行库。我一般会把 Release 工程固定成/MT,Debug 工程固定成/MTd,和静态库一一对应,省得后面反复切。
2.3 用 dumpbin 反查架构和工具集
架构不对是最隐蔽的坑:x64 工程链 x86 的库,报错往往不是「架构不符」,而是一堆莫名其妙的未解析符号。用下面两条命令把库的底细摸清:
dumpbin /headers libjsoncpp.lib | findstr machine dumpbin /headers libjson-rpc-cpp.lib | findstr machinemachine (x64)表示 64 位,machine (x86)表示 32 位。两个库的架构必须和你的工程平台一致,不能一个 x64 一个 x86 混着链。工具集版本则看库里的_MSC_VER相关符号,或者直接看库文件所在目录的命名习惯——很多预编译包会写成libjsoncpp-v142-x64-MT这种形式,目录名就是最直接的线索。
把这三件事对齐之后,环境这一关就算过了。下面这张表是我自己整理的环境对照,配工程时对着填:
| 项目 | 静态库侧 | VS2019 工程侧 | 不一致的典型报错 |
|---|---|---|---|
| 工具集 | v142 (19.29) | 平台工具集 v142 | LNK2038 _MSC_VER |
| 运行库 | /MT 或 /MTd | 代码生成 → 多线程(/MT) | LNK2038 RuntimeLibrary |
| 架构 | x64 | 解决方案平台 x64 | LNK2019 大量未解析 |
| 字符集 | 与库无关 | Unicode 或 MBCS 均可 | 一般不影响链接 |
3. 把静态库接进 VS2019 工程:头文件、库目录、附加依赖项
环境对齐后,真正把库「接进去」靠的是三处配置:头文件搜索路径、库文件搜索路径、附加依赖项。这三处任何一处写错,表现都是编译能过、链接失败,所以配完一定要做一次完整重建,别只做增量编译。
3.1 头文件目录和库目录怎么填
假设你把预编译包解压到了D:\sdk\json\,目录结构大致是include\json\(jsoncpp 头文件)、include\jsonrpccpp\(json-rpc-cpp 头文件)、lib\x64\(两个 .lib 文件)。在 VS2019 里右键工程 → 属性,注意顶部「配置」选「所有配置」,「平台」选 x64,然后:
- 「C/C++ → 常规 → 附加包含目录」填
D:\sdk\json\include - 「链接器 → 常规 → 附加库目录」填
D:\sdk\json\lib\x64
这里有个细节:jsoncpp 的头文件引用方式是#include <json/json.h>,所以附加包含目录要指到include这一层,而不是include\json。指错了会报Cannot open include file: 'json/json.h'。libjson-rpc-cpp 的头文件常见引用是#include <jsonrpccpp/server.h>,同理指到include层。
注意:路径里尽量不要带中文和空格。VS2019 对含空格路径的处理在部分插件下会出问题,我一般把 SDK 放在纯英文短路径下,比如
D:\sdk\。
3.2 附加依赖项写哪几个 lib
「链接器 → 输入 → 附加依赖项」里填库文件名,多个用分号或换行分隔。Release 配置一般写:
libjsoncpp.lib;libjson-rpc-cpp.libDebug 配置如果预编译包提供了带 d 后缀的版本,就写libjsoncppd.lib;libjson-rpc-cpd.lib。这里要留意 libjson-rpc-cpp 的依赖关系:它内部依赖 jsoncpp,所以链接顺序上 jsoncpp 放在后面通常更稳,MSVC 的链接器对顺序不像 GCC 那么敏感,但把被依赖的库放后面是通用习惯。
如果链接时提示LNK2019: 无法解析的外部符号 ... jsoncpp ...,先别怀疑库坏了,八成是附加依赖项里漏了libjsoncpp.lib,或者库目录指错了一层。我习惯在配完后用「链接器 → 命令行」看一眼最终展开的命令行,确认/LIBPATH和库名都在里面。
3.3 用一段最小代码验证链接是否打通
配置完别急着上业务代码,先写个最小验证程序,把 jsoncpp 的解析和序列化跑一遍:
#include <json/json.h> #include <iostream> #include <sstream> int main() { // 构造一个 JSON 对象并序列化 Json::Value root; root["name"] = "demo"; root["port"] = 8080; root["enabled"] = true; Json::StreamWriterBuilder writer; std::string out = Json::writeString(writer, root); std::cout << "serialized: " << out << std::endl; // 再解析回来,验证读写闭环 Json::CharReaderBuilder reader; Json::Value parsed; std::string errs; std::istringstream iss(out); if (!Json::parseFromStream(reader, iss, &parsed, &errs)) { std::cerr << "parse failed: " << errs << std::endl; return 1; } std::cout << "port = " << parsed["port"].asInt() << std::endl; return 0; }这段代码只用到 jsoncpp,目的是先确认「头文件能找到、库能链上、运行库不冲突」这条链路是通的。Json::StreamWriterBuilder和Json::CharReaderBuilder是 jsoncpp 较新版本的写法,老版本用的是Json::FastWriter和Json::Reader,如果你手上的库版本偏老,编译报「未声明的标识符」,就换成老写法。跑通输出serialized: {"enabled":true,"name":"demo","port":8080}和port = 8080,说明 jsoncpp 这一半已经落地。
libjson-rpc-cpp 的验证放到第 5 章,因为它需要一个 server 和 client 配合,单独跑不起来。先把 jsoncpp 这半边的链接打通,能排除掉大部分环境问题。
4. 避坑与排查:静态链接最常见的五类翻车
静态库的坑有个共同特点:编译期不报,链接期才炸,而且报错信息往往指向业务代码,让人误以为是自己的问题。下面五条是我这几年反复遇到的,按「现象 → 原因 → 解决」记下来,配环境时对着排。
4.1 LNK2038 运行库不匹配
现象:链接时报LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”(xxx.obj 中)。
原因:静态库用/MT编,工程用/MD,或者反过来。静态链接时两套运行库的符号会冲突。
解决:用 2.2 的dumpbin /directives确认库的运行库类型,然后把工程「C/C++ → 代码生成 → 运行库」改成一致。注意 Debug 和 Release 要分别改,VS 默认 Release 是/MD,很多人只改了 Debug 忘了 Release。
4.2 LNK2019 大量未解析符号
现象:几十上百条LNK2019: 无法解析的外部符号,符号名里带jsoncpp或jsonrpc。
原因:三种可能——附加依赖项漏了库、库目录指错、架构不一致。架构不一致时符号名会带不同的修饰,看起来像「库没链上」,其实是链上了但签名对不上。
解决:先看「链接器 → 命令行」确认/LIBPATH和库名都在;再用dumpbin /headers核对架构;最后确认附加依赖项里两个库都写了。三步走完基本能定位。
4.3 头文件能找到但编译报 C4996
现象:编译报C4996: 'Json::FastWriter': 被声明为已否决。
原因:jsoncpp 新版本把FastWriter、Reader等旧接口标记为 deprecated,工程又开了/WX(警告当错误)。
解决:要么改用StreamWriterBuilder/CharReaderBuilder新接口,要么在包含头文件前加#define JSONCPP_DEPRECATED相关宏抑制,但更推荐改代码。我一般直接改新接口,旧接口在后续版本里可能被移除。
4.4 Debug 能跑 Release 崩
现象:Debug 配置下程序正常,切到 Release 一运行就崩,崩在 JSON 解析或 RPC 调用附近。
原因:Debug 用了/MTd的库,Release 却链了/MT的库,或者 Debug 链的是带 d 后缀的库、Release 忘了换。运行库混用导致的堆内存管理不一致,在 Debug 下被调试堆掩盖,Release 下直接暴露。
解决:把 Debug 和 Release 的「附加依赖项」「库目录」「运行库」三处分别核对,确保 Debug 全用 d 版本、Release 全用非 d 版本。我习惯在工程里建两个属性表(.props),Debug 和 Release 各挂一个,避免手改漏项。
4.5 静态库重复定义
现象:链接报LNK2005: xxx 已经在 libjsoncpp.lib 中定义。
原因:工程里同时链了静态库和动态库的导入库,或者两个不同版本的 jsoncpp 库都被链进来。
解决:检查附加依赖项,只保留一套;检查「链接器 → 输入 → 忽略特定默认库」有没有误配。如果是第三方库间接带入了另一份 jsoncpp,用/NODEFAULTLIB排除冲突的那份,但要确认排除后符号仍能解析。
5. 装完怎么验证:server/client 跑通才算真落地
jsoncpp 单独跑通只证明了一半,libjson-rpc-cpp 的价值在于 RPC 调用,必须 server 和 client 配合才能验证静态库完整可用。这一章给一套最小可跑的验证方法,跑通它,这套静态库就算真正接进工程了。
5.1 写一个最小 RPC server
libjson-rpc-cpp 的典型用法是继承AbstractServer或使用HttpServer。下面是一个基于 HTTP 的最小 server,暴露一个add方法:
#include <jsonrpccpp/server.h> #include <jsonrpccpp/server/connectors/httpserver.h> #include <json/json.h> #include <iostream> class DemoServer : public jsonrpc::AbstractServer<DemoServer> { public: DemoServer(jsonrpc::AbstractServerConnector& conn) : jsonrpc::AbstractServer<DemoServer>(conn) { // 绑定方法名和实现,参数个数要与实现签名一致 this->bindMethod("add", &DemoServer::add); } Json::Value add(const Json::Value& request) { int a = request["params"][0].asInt(); int b = request["params"][1].asInt(); Json::Value result(a + b); return result; } }; int main() { jsonrpc::HttpServer httpServer(8383); DemoServer server(httpServer); server.StartListening(); std::cout << "server listening on 8383" << std::endl; std::cin.get(); // 阻塞,回车退出 server.StopListening(); return 0; }bindMethod的第一个参数是客户端调用的方法名,第二个是成员函数指针。HttpServer构造参数是监听端口,这里用 8383 避开常用端口。StartListening之后 server 在后台线程跑,主线程用std::cin.get()阻塞住,回车后StopListening收尾。这段代码同时用到了 jsoncpp 和 libjson-rpc-cpp,能编译链接通过,说明两个静态库都接对了。
5.2 用 client 发一次调用
client 侧可以用HttpClient构造请求,也可以直接用 curl 发 JSON-RPC 报文。用 curl 更轻,适合快速验证:
curl -X POST http://127.0.0.1:8383/ -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[3,5],\"id\":1}"预期返回{"jsonrpc":"2.0","result":8,"id":1}。如果返回Method not found,检查bindMethod的方法名是否和请求里的method一致;如果连接被拒,检查 server 是否真的StartListening成功、端口有没有被占用。这一步跑通,说明静态库的 RPC 链路完整可用。
5.3 验证清单和收尾习惯
我一般按下面这张清单逐项打勾,全过才算这套静态库真正落地:
| 验证项 | 方法 | 通过标准 |
|---|---|---|
| jsoncpp 序列化 | 跑 3.3 的最小程序 | 输出合法 JSON 字符串 |
| jsoncpp 反序列化 | 同上,解析回读 | 字段值正确 |
| RPC server 启动 | 运行 5.1 程序 | 打印 listening 且不崩 |
| RPC 调用 | curl 发 add 请求 | 返回 result 为两数之和 |
| Debug/Release 双跑 | 两个配置各跑一遍 | 均正常,无运行库报错 |
最后说个血泪教训:静态库这东西,最怕「Debug 能跑就以为万事大吉」。我现在的习惯是,每接一套新的静态库,Debug 和 Release 各跑一遍 5.1 的 server/client,两个配置都通过才往业务工程里合。因为运行库和工具集的不一致,往往只在 Release 下暴露,等业务代码堆上去再发现,排查成本翻好几倍。这套 libjsoncpp 和 libjson-rpc-cpp 的静态库本身是干净的,坑基本都在工程配置侧,把第 2 章的三件套对齐、第 4 章的五类报错记住,接进去并不费劲。希望帮到你。
本文还有配套的精品资源,点击获取