☰
VS2019静态链接libjsoncpp与libjson-rpc-cpp实战指南
2026/10/27 10:56:50 网站建设 项目流程

简介:面向 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 machine

machine (x64)表示 64 位,machine (x86)表示 32 位。两个库的架构必须和你的工程平台一致,不能一个 x64 一个 x86 混着链。工具集版本则看库里的_MSC_VER相关符号,或者直接看库文件所在目录的命名习惯——很多预编译包会写成libjsoncpp-v142-x64-MT这种形式,目录名就是最直接的线索。

把这三件事对齐之后,环境这一关就算过了。下面这张表是我自己整理的环境对照,配工程时对着填:

项目静态库侧VS2019 工程侧不一致的典型报错
工具集v142 (19.29)平台工具集 v142LNK2038 _MSC_VER
运行库/MT 或 /MTd代码生成 → 多线程(/MT)LNK2038 RuntimeLibrary
架构x64解决方案平台 x64LNK2019 大量未解析
字符集与库无关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.lib

Debug 配置如果预编译包提供了带 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 章的五类报错记住,接进去并不费劲。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询