news 2026/9/8 6:36:27

VS2019下静态编译libjsoncpp与libjson-rpc集成指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VS2019下静态编译libjsoncpp与libjson-rpc集成指南

简介:面向Windows平台上的C++开发者,提供基于Visual Studio 2019环境静态编译完成的JSON解析库和JSON-RPC通信库,整体打包为可直接引用的静态链接库文件,包含头文件与导入库。针对目前网络上流行的相关编译包存在缺少依赖文件以及仅支持三十二位架构的缺陷,此包特意补齐依赖,并同时准备好六十四位与三十二位两套构建工程,方便开发者按需选用或在此基础上进行二次编译。压缩包内文件总数为三百五十五个,大小约二十点八二兆字节,主要包含头文件、源文件、对象文件、编译日志、配置文件以及构建辅助脚本,目录结构清晰,方便查阅与定位模块。目前已有四百七十四人学习使用。除最终库文件外,还附带构建配置脚本和许可证说明,有助于理解编译流程与后续移植。 做Windows C++开发的人,十有八九都被JSON解析和跨进程通信这两件事折磨过。标准库不带JSON解析功能,RPC就更别想了,最常见的路子就是引入libjsoncpp和libjson-rpc这两个开源库。但源码拿回来后,你还得自己过一遍CMake配置、编译、链接,中间踩的坑一套接一套:CMake版本不对、依赖库找不到、运行库冲突、Debug和Release混用……每一步都能让新手折腾大半天。

这次分享一套在VS2019下静态编译好的libjsoncpp和libjson-rpc库文件,目录整理干净,拿到手就能直接集成到项目里用。凡是做C++桌面程序、需要本地JSON解析,或者打算用JSON-RPC做进程间通信的朋友,这篇内容大概率能帮你省掉一个下午的折腾时间。

我先把结论放在前面:这套库我一直在用,编译参数、目录结构、使用方式都验证过,下面会把编译过程中的关键参数、集成步骤和遇到的坑全部写清楚。就算你不想直接用现成的库文件,跟着操作自己从头编一遍也不难。

1. 为什么一定要静态编译这两个库

1.1 两个库各管哪摊事

先明确概念。libjsoncpp,也就是常说的jsoncpp,是目前C++生态里最流行的JSON解析与序列化库之一。它的核心思路很简单:把JSON文本解析成一棵用Json::Value表示的树形结构,之后你想读哪个字段、改哪个字段、再把整个结构输出成字符串,都在这棵树上面操作。相比直接手写解析器,jsoncpp极大降低了JSON处理的心智负担。

libjson-rpc-cpp则是云端之上的另外一层。它实现了JSON-RPC协议——简单说,就是让两个进程之间通过JSON格式的请求和响应来完成“调用远程方法”这件事。最常见的使用场景是:服务端注册几个方法,监听TCP端口或HTTP端口;客户端连接过来,发一段JSON请求,服务端执行对应方法后把结果以JSON格式返回。你不用关心底层的socket细节,只需要面向协议写业务逻辑。

这两个库本身没有强绑定关系,但libjson-rpc-cpp依赖jsoncpp来完成消息的解析与组装。所以你需要两个库一起编译、一起提供,集成方拿到手才能直接跑。

1.2 动态库和静态库的真实取舍

有人会问:为什么非要静态编译,用DLL不行吗?那得看你项目的实际部署场景。

Windows下用VS2019编译DLL,生成时会附带一些额外的运行时DLL依赖,比如msvcp140.dllvcruntime140.dll等。如果你交付的是一个小工具、一个内部系统组件,目标机器上不一定装了对应版本的VC++运行库。虽然大多数Windows 10/11系统都预装了常见版本,但碰到精简版系统、服务器环境,或者同时装了多个版本的VS,DLL冲突的情况屡见不鲜。

静态编译后,这些依赖都会被链接进最终的exe。我实际测试过,把这套静态库编进去的程序拷贝到一台什么开发环境都没有的Windows 10机器上,双击就能跑,连VC运行库都不用装。对交付来说,省心程度完全不是一个级别。

静态库的代价主要是两个:一是生成的exe体积会大一些;二是如果你还想和其他动态库混用,运行库设置必须对齐,否则会出现LNK2038这类链接错误。这两点权衡下来,对于大多数工具型、系统型项目,静态编译的收益远大于代价。

对比项动态库(DLL)静态库(LIB)
部署依赖需要目标机器有对应运行库/适配补丁依赖全部打进exe
exe体积较小偏大,一般几MB起步
链接配置相对麻烦,还要带DLL一起发布只需配置include和lib
升级替换换DLL即可需要重新编译整个工程
更适合场景大型插件架构、模块频繁更新工具类、交付类项目

1.3 为什么选VS2019而不是新版本

VS2019使用的是v142工具集,支持C++14/17非常成熟,兼容性也稳。很多公司的内部项目还停留在VS2019,行业里面流传下来的构建脚本、代码风格也大多基于这一代。另外VS2019社区版免费,不像早年专业版要序列号,团队成员之间协作完全无障碍。

还有一个现实原因:这套库我在VS2019下编译并验证过,稳定用了很长时间。虽然VS2022的v143工具集也能链接v142编译出来的静态库,但在编译环境和交付环境保持一致的场景下,VS2019仍然是绕不开的版本。下面所有步骤都以VS2019 + x64架构为例。

2. 编译前的准备工作和关键参数

2.1 源码版本与依赖关系

编译之前,先把源码版本钉死。我用的分别是:

  • jsoncpp:1.9.5
  • libjson-rpc-cpp:1.3.0

这两个版本是一套经过验证的组合。libjson-rpc-cpp在CMake配置阶段会去查找jsoncpp的头文件和库文件,它的CMakeLists.txt写得比较“挑”:版本太新或太旧都可能出现找不到头文件、链接符号对不上的问题。如果你用最新版jsoncpp去配旧版libjson-rpc-cpp,大概率会遇到Json::Value相关的编译错误——因为新版jsoncpp内部头文件路径或API有过调整。

源码都从GitHub官方仓库拉,别去乱七八糟的镜像站。jsoncpp可以直接下载release的zip包;libjson-rpc-cpp同理,release页面有对应版本的压缩包,解压即可。

2.2 决定静态编译的核心CMake开关

编译静态库最关键的几个CMake参数,我直接列出来:

  • BUILD_SHARED_LIBS=OFF:告诉CMake生成静态库而不是动态库。这个开关在CMake工程里几乎是“静态库标准开关”的存在。
  • JSONCPP_WITH_TESTS=OFF:jsoncpp默认会连带编译一堆单元测试,关掉可以节省大量编译时间,也避免生成多余的测试目标。
  • JSONCPP_WITH_PKG_CONFIG=OFF:不需要生成pkg-config文件,Windows下用不到。
  • COMPILE_TESTS=OFF:libjson-rpc-cpp的测试开关,同样关掉。
  • CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded:对应编译器选项就是/MT,这是保证静态编译后不依赖动态运行库的核心开关。

另外还有一个容易忽略的点:CMake默认在Release配置下可能会继续沿用动态运行库(/MD),因为你光把BUILD_SHARED_LIBS设为OFF只能控制库本身是静态的,但库的CRT依赖是动态的还是静态的,得单独用CMAKE_MSVC_RUNTIME_LIBRARY来管。这一步不做,编译出来的.lib虽然是静态库,但它内部还依赖msvcp140.dll,等于白干。

2.3 64位还是32位

现在Windows环境绝大多数都是x64系统,VS2019默认的x64工具链也最成熟。我建议编译x64版本。如果项目非要32位,配置上基本完全一样,把-A x64换成-A Win32即可,但需要留意目标机器的系统位数,别编译完拿到32位系统上跑(虽然现在很罕见了)。

3. 完整编译过程:从源码到 .lib

3.1 编译jsoncpp

jsoncpp的CMake配置比较简单。下载源码并解压后,在源码目录下建一个build文件夹,然后打开VS2019的“开发者命令提示符”,执行:

cd /d D:\thirdparty\jsoncpp-1.9.5 mkdir build cd build cmake .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_PKG_CONFIG=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded

CMake会在build目录下生成jsoncpp.sln解决方案文件。用VS2019打开后,把解决方案配置切到Release x64,然后右键目标“jsoncpp_static”选择“生成”。这一步顺利的话,会在build\lib\Release下得到jsoncpp_static.lib文件。

如果你不想用命令行,也可以直接用CMake GUI:源码路径和生成路径填好之后,勾选BUILD_SHARED_LIBS取消勾选,其余参数在界面里一样能找到。实际体验下来,命令行更快,还能保留日志反复核对。

3.2 编译libjson-rpc-cpp

libjson-rpc-cpp的编译比jsoncpp多一步:需要明确告诉它jsoncpp的位置。它默认会尝试通过CMake的find_package去找,但如果你像我一样已经把jsoncpp编成静态库,最好直接手动指定路径,避免它在系统目录里找到别的不匹配版本。

在libjson-rpc-cpp源码目录下同样建build文件夹执行:

cd /d D:\thirdparty\libjson-rpc-cpp-1.3.0 mkdir build cd build cmake .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DCOMPILE_TESTS=OFF -DJSONCPP_INCLUDE_DIR=D:/thirdparty/jsoncpp-1.9.5/include -DJSONCPP_LIBRARY=D:/thirdparty/jsoncpp-1.9.5/build/lib/Release/jsoncpp_static.lib -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded

这里JSONCPP_INCLUDE_DIR指向jsoncpp源码目录下的include文件夹,JSONCPP_LIBRARY直接指向刚才编译好的静态库文件。这一步如果路径填错,CMake会在配置阶段就报错,耐心检查路径即可。

配置成功后用VS2019打开jsonrpccpp.sln,切到Release x64,执行生成。libjson-rpc-cpp会生成三个静态库:jsonrpccpp-common.lib(基础公共库)、jsonrpccpp-server.lib(服务端)、jsonrpccpp-client.lib(客户端)。需要的库文件就这三个加一个jsoncpp_static.lib,一个都不能少。

3.3 整理目录结构

编译完成后,我会把文件和头文件整理成一套干净的结构,方便后续复用:

jsoncpp-rpc/ ├── include/ │ ├── json/ │ │ └── *.h │ └── jsonrpccpp/ │ ├── client/ │ ├── common/ │ └── server/ ├── lib/ │ ├── Release/ │ │ ├── jsoncpp_static.lib │ │ ├── jsonrpccpp-client.lib │ │ ├── jsonrpccpp-common.lib │ │ └── jsonrpccpp-server.lib │ └── Debug/ │ ├── jsoncpp_static.lib │ ├── jsonrpccpp-client.lib │ ├── jsonrpccpp-common.lib │ └── jsonrpccpp-server.lib

如果你只需要Release库,目录可以精简到只留Release。但我的习惯是编译一套Debug版本留着,调试代码时用Release库会有很多困扰(变量看不到、断点不生效、优化行为不一致)。Debug版的编译过程一模一样,只要在VS里把配置切到Debug再生成一遍即可。

4. 库文件如何集成到VS2019项目

4.1 项目属性配置三步走

拿到这套库之后,集成到VS2019项目的步骤如下。假设你新建了一个空的控制台程序,打开“项目属性”:

第一步,设置头文件目录。“C/C++ → 常规 → 附加包含目录”,加上你的目录\include,注意不用细分到jsonjsonrpccpp子目录,因为代码里包含头文件时写的是#include <json/json.h>#include <jsonrpccpp/server.h>,编译器会自己往子目录找。

第二步,设置库文件目录。“链接器 → 常规 → 附加库目录”,加上你的目录\lib\Release

第三步,设置依赖库。“链接器 → 输入 → 附加依赖项”,手动填入:

jsoncpp_static.lib jsonrpccpp-client.lib jsonrpccpp-common.lib jsonrpccpp-server.lib

这里有一个很重要的注意事项:链接顺序和库的依赖关系。通常把被依赖的库放在后面,jsoncpp_static.lib放在最后,多维依赖时MSVC的链接器对顺序比较挑剔。按上面这个顺序写,实测稳定。

4.2 运行时库必须统一

配置完上面的路径和依赖项之后,还要回到“C/C++ → 代码生成 → 运行库”,确认当前项目也选的是多线程(/MT),而不是默认的多线程调试 DLL(/MDd)多线程 DLL(/MD)

这一点的原理在于:静态库内部是按照/MT方式链接的,如果你项目本身用/MD,那么exe和静态库将使用不同的C/C++运行库(一个静态版、一个动态版),两边在内存分配、堆管理上各搞一套,轻则编译告警,重则链接直接报LNK2038,运行期出现偶发崩溃。这也是static库和动态库混合使用时的第一大坑。

我见过不少人在这里卡住,明明库文件路径都配对了,编译就是报错,最后发现是运行库选项没有改。如果你要把这套库集成到已有项目里,改这个选项之前最好确认项目里其他第三方库的编译方式,如果它们是用/MD编译的,那就不建议硬改全局设置,而是换一套用/MD编译的库文件。这也是为什么我前面建议Debug库和Release库各留一份,真遇到运行库冲突时还能灵活切换。

4.3 一段能跑通的测试代码

集成完成后,用一段最简单的代码验证库是否可用。先测jsoncpp的解析:

#include <iostream> #include <json/json.h> int main() { std::string raw = R"({"name":"test","value":42})"; Json::Value root; Json::CharReaderBuilder builder; std::string errs; std::istringstream iss(raw); if (!Json::parseFromStream(builder, iss, &root, &errs)) { std::cerr << "parse error: " << errs << std::endl; return -1; } std::cout << "name=" << root["name"].asString() << std::endl; std::cout << "value=" << root["value"].asInt() << std::endl; return 0; }

再测libjson-rpc-cpp的最简服务端和客户端。服务端注册一个sayHello方法:

#include <jsonrpccpp/server.h> #include <jsonrpccpp/server/connectors/tcpsocketserver.h> class SampleServer : public jsonrpc::AbstractServer<SampleServer> { public: SampleServer(jsonrpc::IConnectionHandler& conn, jsonrpc::serverVersion_t type) : AbstractServer<SampleServer>(conn, type) { this->bindMethod("sayHello", &SampleServer::sayHello); } void sayHello(const Json::Value& request, Json::Value& response) { response["result"] = "hello, " + request["params"]["name"].asString(); } }; int main() { jsonrpc::TcpSocketServer server("127.0.0.1", 8080); SampleServer sample(server, jsonrpc::JSONRPC_SERVER_V2); sample.StartListening(); std::cout << "server started, press any key to exit..." << std::endl; std::cin.get(); sample.StopListening(); return 0; }

客户端简单调一下这个方法:

#include <jsonrpccpp/client.h> #include <jsonrpccpp/client/connectors/tcpclientconnector.h> int main() { jsonrpc::TcpClientConnector conn("127.0.0.1", 8080); jsonrpc::Client client(conn, jsonrpc::JSONRPC_CLIENT_V2); Json::Value params; params["name"] = "world"; try { Json::Value result = client.CallMethod("sayHello", params); std::cout << result.toStyledString() << std::endl; } catch (jsonrpc::JsonRpcException& e) { std::cerr << e.what() << std::endl; } return 0; }

先启动服务端程序,再启动客户端程序,能打印出hello, world就说明整套库链路完全没问题。这个测试值得保留下来,以后每次在新环境集成时,先拿这段代码验证环境,能排除掉一半以上的配置类问题。

5. 编译和使用中的常见坑与排查

5.1 LNK2038 运行时库不匹配

这是使用这套静态库时最常遇到的链接错误,报错长这样:

error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'

原因就是我在4.2里说的,项目运行库设置和库本身的运行库不一致。排查方式很简单:打开项目属性,把运行库改成多线程(/MT),重新编译即可。如果你的项目因为其他依赖不能改,那就只能换一套用/MD编译的库文件,别无他法。

5.2 无法解析的外部符号

error LNK2019: unresolved external symbol "public: void __cdecl jsonrpc::...".

这种情况多半是附加依赖项漏写了。libjson-rpc-cpp有三个库,少写一个就会出现这种错误。另一个常见原因是Debug模式下错误地链接了Release库,或者反过来。Debug库通常带d后缀,编译之前先去lib目录里确认文件名,再对着文件名填依赖项即可。

5.3 cpp文件加中文注释就报错

这个问题在很多VS项目里都会碰到,和你用不用这两个库没关系,但集成时很容易撞上。现象是:cpp文件里一旦出现中文注释,编译就报error C2001: 常量中有换行符,或者警告C4819,有些情况下还报乱码错误。根因是VS2019默认按系统当前代码页去解析源文件,如果源文件是UTF-8编码但没有BOM头,编译器可能错误地把中文注释的字节流当成别的编码解析,从而破坏语法结构。

解决办法有两个,二选一:一是把源文件另存为“UTF-8 with BOM”,VS2019里通过“文件 → 高级保存选项”选择这个编码;二是在项目“C/C++ → 命令行 → 附加选项”里加上/utf-8,让编译器强制按UTF-8解析。我建议直接加编译选项,一劳永逸,不用每个文件单独保存编码。

5.4 Debug和Release库混用

这套库如果用一段时间后,你可能会像我一样把Debug和Release库都编译好放在一起。这时注意一个陷阱:Debug库和Release库的文件名默认是一样的(除非你在CMake里手动给Debug版本加了后缀)。如果两个版本都拷贝到了同一个目录,后生成的会覆盖先生成的,导致Debug和Release模式下链接到同一份文件,运行期出现各种诡异行为。

我自己的做法是用目录区分:lib\Releaselib\Debug分开放,然后在VS2019里针对Debug和Release配置分别设置不同的附加库目录,这样永远不会混。另外每次重新编译库之后,记得确认一遍文件的修改时间,确保拷贝的是最新版本。

5.5 版本新旧对应不上

如果你打算自己重新编译最新版libjson-rpc-cpp,需要特别留意它和jsoncpp的版本对应关系。我用的1.9.5 + 1.3.0组合虽然老,但兼容性最好。新版本的libjson-rpc-cpp可能对C++标准要求更高,可能需要VS2019的较新更新补丁,或者要求jsoncpp的头文件位置不同。

这里给你一个排查思路:编译libjson-rpc-cpp时如果报找不到json/json.h,那就是JSONCPP_INCLUDE_DIR没配好;如果报Json::Value相关的红波浪线或链接错误,那就要检查jsoncpp版本。不要指望最新版爽,稳定复现才是重点。

写在后面

这套VS2019静态编译好的libjsoncpp和libjson-rpc,我实际用了挺长一段时间,好几个内部工具都是拿它打底做的。最直观的感受就是:交付省心。编出来的exe拷到没装开发环境的机器上,双击就能跑,不需要额外装运行库,也不用担心DLL缺失。

如果你也打算在自己的项目里用,我的建议是不要只拿别人编译好的库文件就跑,最好把编译过程也过一遍,哪怕花一个小时把CMake命令跑通。因为只有理解了/MTBUILD_SHARED_LIBS、include和lib目录这些概念,遇到问题的时候才不会慌。之后哪怕项目升级到VS2022,或者换了别的编译器,你也能照葫芦画瓢重新编译一套。这套东西值不值得折腾,用过一次就知道了。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 6:34:38

D3D11下YV12视频渲染实战:GPU加速YUV转RGB的完整方案

简介&#xff1a;面向视频显示与播放开发的 Direct3D YUV 渲染示例工程&#xff0c;支持 YV12、I420、NV12、YUY2、UYVY 及 RGB24、RGB32、RGB555、RGB565 等常见像素格式输入&#xff0c;并在画面上实现半透明文本叠加&#xff0c;便于播放器或监控客户端直接嵌入使用。工程基…

作者头像 李华
网站建设 2026/9/8 6:34:36

LLM核心机制拆解:Token、上下文窗口与采样参数实战指南

先坦白一个事儿&#xff1a;我最早做 LLM 应用时&#xff0c;最懵的不是提示词&#xff0c;也不是模型选型&#xff0c;而是一堆看着眼熟的术语——Token、上下文、温度。明明每个词单独看都认识&#xff0c;连在一起却搞不清它们怎么影响模型输出。更尴尬的是&#xff0c;我曾…

作者头像 李华
网站建设 2026/9/8 6:34:17

OpenSmith:本地化LLM流水线追踪工具的原理与应用实践

这次我们来看一个本地化 LLM 流水线追踪工具——OpenSmith。这个项目的核心价值在于让开发者能够在本地环境中完整追踪大语言模型的工作流程&#xff0c;无需依赖云端服务&#xff0c;所有数据都存储在本地 SQLite 数据库中。对于需要调试 LLM 应用、分析提示词效果或优化流水线…

作者头像 李华
网站建设 2026/9/8 6:34:16

3ds Max零基础室内小卧室建模:从搭框架到渲染出图全流程

这次我们来看一个非常适合入门的 3Dmax 场景建模练习案例&#xff1a;简单室内单间小卧室模型搭建。很多新手第一次打开 3ds Max 不知道从哪下手&#xff0c;新建一个空白场景后对着四个视图发呆&#xff0c;最后只能随便拖几个方块就当练习完了。这个案例的目的就是把“不知道…

作者头像 李华
网站建设 2026/9/8 6:32:16

Python实战:从函数图像绘制到电影短评爬取的全流程解析

头一回看到这个题目的时候我就觉得挺有意思&#xff0c;Python里最常被拿来练手的两个点——函数图像绘制和网页数据爬取&#xff0c;偏偏被塞进了同一个作业里。一个是纯本地计算加可视化&#xff0c;一个是网络请求加解析&#xff0c;看起来八竿子打不着&#xff0c;实际做下…

作者头像 李华
网站建设 2026/9/8 6:32:04

次世代武器全流程制作:3ds Max安装排查到若水弓建模渲染

做次世代武器&#xff0c;最怕的不是布线难&#xff0c;也不是贴图画不好&#xff0c;而是软件环境先把你卡死在门外。最近想拿原神里夜兰的“若水”做一把全流程练习作品&#xff0c;结果光是 3ds Max 装完闪退、报 1603 错误、启动界面闪一下就没了&#xff0c;就折腾了近一天…

作者头像 李华