news 2026/9/10 16:24:02

nlohmann/json 的 CMake 集成全指南:五种引入方式、`nlohmann_json::nlohmann_json` 目标与全部构建选项解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
nlohmann/json 的 CMake 集成全指南:五种引入方式、`nlohmann_json::nlohmann_json` 目标与全部构建选项解析

nlohmann/json 的 CMake 集成全指南:五种引入方式、nlohmann_json::nlohmann_json目标与全部构建选项解析

【免费下载链接】jsonJSON for Modern C++项目地址: https://gitcode.com/GitHub_Trending/js/json

JSON for Modern C++(nlohmann/json)是一个纯头文件库,官方推荐通过 CMake 的接口目标(INTERFACE target)nlohmann_json::nlohmann_json进行集成——它会自动携带正确的头文件搜索路径与 C++11 编译特性要求。本文以项目文档 docs/mkdocs/docs/integration/cmake.md 为主线,结合仓库根目录的 CMakeLists.txt 与tests/cmake_*集成测试,完整讲解find_packageadd_subdirectory、FetchContent 等五种引入方式,并逐一解析所有 CMake 选项的默认值与宏映射关系。读完即可在任何 C++ 工程中正确、稳定地接入该库,并能按需开启诊断信息、禁用隐式转换、关闭枚举序列化等行为。

核心入口:nlohmann_json::nlohmann_json接口目标

无论以哪种方式引入该库,最终供消费方链接的都是带命名空间的接口目标nlohmann_json::nlohmann_json。从根 CMakeLists.txt 的源码结构可以看到它的真实构成:

  • 它由add_library(nlohmann_json INTERFACE)创建,并以别名目标形式对外暴露nlohmann_json::nlohmann_json
  • 通过target_compile_features(... INTERFACE cxx_std_11)(CMake < 3.8 时退化为cxx_range_for)向所有消费者传递C++11 编译特性要求,保证头文件所依赖的语言特性可用;
  • 通过target_include_directories(... INTERFACE ...)注入头文件目录,并使用生成器表达式区分构建期与安装期路径:$<BUILD_INTERFACE:...>指向源码内include/(多头文件版)或single_include/(单头文件版),$<INSTALL_INTERFACE:...>指向安装前缀下的 include 目录;
  • 各种行为选项以INTERFACE_COMPILE_DEFINITIONS的形式通过$<BOOL:...>生成器表达式传播(详见下文「CMake 选项与宏映射」),消费者无需手动定义宏。

因此,target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json)之后,#include <nlohmann/json.hpp>即开箱可用,且会自动获得正确的标准版本约束。

方式一:外部安装后通过find_package()引入(External)

当系统已安装该库(源码编译安装、包管理器安装等)时,直接在项目 CMakeLists 中调用find_package(),再链接命名空间导入目标即可:

cmake_minimum_required(VERSION 3.5) project(ExampleProject LANGUAGES CXX) find_package(nlohmann_json 3.12.0 REQUIRED) add_executable(example example.cpp) target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json)

其中版本号参数用于版本匹配。供find_package()使用的包配置文件是nlohmann_jsonConfig.cmake(由 cmake/config.cmake.in 模板生成),版本文件是nlohmann_jsonConfigVersion.cmake(由 cmake/nlohmann_jsonConfigVersion.cmake.in 生成)。这两个文件既可以从安装树(install tree)使用,也可以直接从构建树(build tree)使用——这正是仓库 CI 中cmake_import测试所验证的场景:见 tests/cmake_import/CMakeLists.txt,它以-Dnlohmann_json_DIR=${PROJECT_BINARY_DIR}指向本仓库构建目录后运行 configure 与 build。

版本兼容性细节:为什么它是“架构无关”的

cmake/nlohmann_jsonConfigVersion.cmake.in 的开头注释说明了一个关键设计:该版本文件有意省略了标准BasicConfigVersion中的 32/64 位架构检查。原因是本库为纯头文件实现,编译平台与使用平台的架构差异不影响可用性(对应上游 issue #1697)。同时它采用SameMajorVersion策略:仅当请求的主版本号与包主版本一致、且包版本不小于请求版本时判定为兼容。这一点在跨平台移植、把构建产物拷贝到其他架构机器上复用时非常实用。

方式二:子目录内嵌(Embedded)

若希望把整个源码树嵌入现有工程,作为子目录直接参与构建,可使用add_subdirectory()

cmake_minimum_required(VERSION 3.5) project(ExampleProject LANGUAGES CXX) # 若该第三方库仅在 PRIVATE 源文件中使用,主项目安装时无需安装它 set(JSON_Install OFF CACHE INTERNAL "") add_subdirectory(nlohmann_json) add_executable(example example.cpp) target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json)

仓库集成测试 tests/cmake_add_subdirectory/project/CMakeLists.txt 展示了实际用法,它同样先set(JSON_BuildTests OFF CACHE INTERNAL "")add_subdirectory(...),并分别用命名空间目标与非命名空间目标各链接了一个可执行文件。

!!! note "⚠️ 不要使用 include(nlohmann_json/CMakeLists.txt)"

官方明确警告:**不要**用 `#!cmake include(nlohmann_json/CMakeLists.txt)` 的方式拉入该库——这会带来难以预料的副作用并破坏构建。`include()` 本就不适合引入独立 CMake 工程,这是被普遍(虽然未必被充分记载)劝阻的做法。

方式三:同时兼容外部与内嵌(Supporting Both)

工程可以同时支持“系统已安装的外部库”与“内嵌源码副本”两种来源,用option一键切换:

project(ExampleProject LANGUAGES CXX) option(EXAMPLE_USE_EXTERNAL_JSON "Use an external JSON library" OFF) add_subdirectory(thirdparty) add_executable(example example.cpp) # 无论以何种方式导入,命名空间目标始终可用 target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json)
if(EXAMPLE_USE_EXTERNAL_JSON) find_package(nlohmann_json 3.12.0 REQUIRED) else() set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(nlohmann_json) endif()

其中thirdparty/nlohmann_json是本源码树的一份完整拷贝。该模式成立的前提在于:add_subdirectory()与本库导出的 config 文件都会提供同一个命名空间目标nlohmann_json::nlohmann_json,消费方的链接语句完全无需随引入方式变化。

旧版兼容:非命名空间目标如何被补齐

值得注意的是,cmake/config.cmake.in 中还包含一段向后兼容逻辑:当检测到请求版本小于 3.2.0、或目标未定义时,会额外补建一个名为nlohmann_json(不带命名空间)的INTERFACE IMPORTED目标,并将其INTERFACE_LINK_LIBRARIES指回命名空间目标。这正是 tests/cmake_import/project/CMakeLists.txt 中同时链接nlohmann_json::nlohmann_json与裸nlohmann_json两个目标都能成功的原因。因此老代码中的裸目标写法仍可工作,但新代码应统一使用带命名空间的推荐目标。

方式四:FetchContent 自动下载

从 CMake 3.11 起,可用 FetchContent 在配置阶段自动下载依赖。官方推荐的写法是直接下载发布归档

cmake_minimum_required(VERSION 3.11) project(ExampleProject LANGUAGES CXX) include(FetchContent) # 将 <RELEASE_ARCHIVE_URL> 替换为对应版本发布的 json.tar.xz 归档地址 FetchContent_Declare(json URL <RELEASE_ARCHIVE_URL>) FetchContent_MakeAvailable(json) add_executable(example example.cpp) target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json)

注意:这里应使用发布版 tar 归档(json.tar.xz),而不是去 clone 整个 Git 仓库——官方在文档中说明仓库体积较大,直接下载归档既快又省磁盘。该「URL 方式」自 3.10.0 版本起即可用;若你确实想用 Git 拉取,也可写成:

FetchContent_Declare(json GIT_REPOSITORY <git_repository_url> GIT_TAG v3.12.0 )

仓库内部 CI 的 tests/cmake_fetch_content/project/CMakeLists.txt 与 tests/cmake_fetch_content2 即采用 Git 方式引用本地源码目录来做端到端验证;实际消费工程把GIT_REPOSITORY指向该库的仓库地址即可。由于 FetchContent /add_subdirectory属于子工程覆盖场景,根 CMakeLists.txt 在 CMake 3.13+ 下会显式设置CMP0077 NEW策略,允许外部-DCACHE变量覆盖库的默认option值——这也是方案二/三中set(JSON_BuildTests OFF CACHE INTERNAL "")之所以有效的前提。

CMake 选项总览与宏映射

文档第二大部分定义了本库的全部构建选项。这些选项绝大部分并不改变库的代码,而是通过向INTERFACE_COMPILE_DEFINITIONS写入对应的宏定义(由 CMakeLists.txt 的生成器表达式统一完成),把行为开关透传给所有消费者。其映射关系与各宏的详细说明可交叉查阅 docs/mkdocs/docs/api/macros 目录下的对应文档。

CMake 选项默认值实际作用(对应宏)
JSON_BuildTests顶层工程为ON,子工程为OFF结合 CTest 的BUILD_TESTING决定是否编译单元测试
JSON_CIOFF启用 CI 专用构建目标,目标随 CI 流程演进、不保证稳定
JSON_DiagnosticsOFF开启扩展诊断信息(JSON_DIAGNOSTICS=1
JSON_Diagnostic_PositionsOFF开启异常诊断中的行列位置信息(JSON_DIAGNOSTIC_POSITIONS=1
JSON_DisableEnumSerializationOFF关闭默认的枚举序列化(JSON_DISABLE_ENUM_SERIALIZATION=1
JSON_FastTestsOFF跳过耗时测试套件(依赖JSON_BuildTests
JSON_GlobalUDLsON_json等用户自定义字面量放入全局命名空间(JSON_USE_GLOBAL_UDLS,详见下文)
JSON_ImplicitConversionsON开启隐式类型转换(JSON_USE_IMPLICIT_CONVERSIONS,关闭时置 0)
JSON_Install顶层工程为ON,子工程为OFFinstall 步骤是否安装 CMake 目标
JSON_LegacyDiscardedValueComparisonOFF恢复被丢弃(discarded)JSON 值的旧版错误比较行为(JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1
JSON_MultipleHeadersON使用多头文件版(include/);置OFF则使用单头文件版(single_include/
JSON_SystemIncludeOFF将库头文件按系统头文件方式添加(加SYSTEM),便于 Clang-Tidy 等工具跳过检查
JSON_ValgrindOFF使用 Valgrind 执行测试套件(依赖JSON_BuildTests
NLOHMANN_JSON_BUILD_MODULESOFF构建实验性 C++20 modulenlohmann.json(需 CMake 3.28+)

逐项深入说明

  • JSON_BuildTests:与 CTest 的BUILD_TESTING联动。库的默认值通过 CMakeLists.txt 中MAIN_PROJECT检测逻辑决定:当库本身是顶层工程时预设为ON,作为子工程引入时预设为OFF,因此“按上述方式集成时,若不显式打开该选项,不会构建整套测试”。最终编译测试还要求NOT DEFINED BUILD_TESTING OR BUILD_TESTING(CMakeLists.txt)。仓库的完整测试代码位于 tests/src,可在需要时自行开启。

  • JSON_DiagnosticsJSON_Diagnostic_Positions:分别对应宏JSON_DIAGNOSTICSJSON_DIAGNOSTIC_POSITIONS。前者让异常消息包含指向出错 JSON 值的路径(如[key1][key2]),后者进一步追加行/列位置,配合 docs/mkdocs/docs/home/exceptions.md#extended-diagnostic-messages 中关于扩展诊断的说明使用,可在排错大 JSON 时极大缩短定位时间。

  • JSON_DisableEnumSerialization:对应JSON_DISABLE_ENUM_SERIALIZATION。默认行为下枚举会直接按其整数值序列化;若希望强制枚举显式走to_json特化、避免意外序列化,应置ON

  • JSON_GlobalUDLs:控制_json_json_pointer等用户自定义字面量的作用域。宏JSON_USE_GLOBAL_UDLS的默认值为1,字面量直接位于全局命名空间可直接使用;宏置0后需using namespace nlohmann::json_literals;才可调用。当前仓库根 CMakeLists.txt 中该 option 实际默认值为ON(与宏默认1一致);由于下一大版本将把 UDL 移出全局命名空间,官方建议逐步显式设置为关闭并引入json_literals命名空间以提前适配。

  • JSON_ImplicitConversions:对应JSON_USE_IMPLICIT_CONVERSIONS。当json需要充当兼容容器、或希望严格区分类型时,可置OFF使json j = ...仅接受显式转换,规避误用带来的隐式类型开销与歧义。

  • JSON_Install:其默认值与MAIN_PROJECT绑定(CMakeLists.txt)。在嵌入(子工程)场景下默认不安装;若内嵌工程需要对外安装库目标,需显式置ON。置ON后才会生成并安装 config/version 文件、导出nlohmann_jsonTargets.cmake、安装nlohmann_json.pc(pkg-config 支持,模板见 cmake/pkg-config.pc.in),并启用 CPack 打包。

  • JSON_MultipleHeaders:决定使用include/下的多头文件(模块化、利于增量编译与 clang-tidy 追踪)还是single_include/下的单头文件 single_include/nlohmann/json.hpp(方便直接拷贝使用)。根 CMakeLists.txt 会根据该选项切换NLOHMANN_JSON_INCLUDE_BUILD_DIR指向。

  • JSON_SystemInclude:置ON后,头文件以SYSTEM目录添加,使 Clang-Tidy 等静态工具默认忽略该第三方头文件中的告警,避免噪声。

  • JSON_FastTests/JSON_Valgrind:均属于测试侧开关(依赖JSON_BuildTests)。前者跳过耗时用例以加速本地验证;后者配合 Valgrind 检查内存问题。

  • JSON_CI:供项目自身的 CI 流水线使用,相关定义见 cmake/ci.cmake,其中目标可能随时调整,不构成稳定接口,普通用户无需开启。

⚠️ 对“已安装包”不生效的选项:以JSON_Diagnostics为例

官方特别警告了一个常见误区:JSON_Diagnostics等编译期选项只在“从源码构建该库”时生效(例如通过 FetchContent 或add_subdirectory内嵌);对于已经构建并安装到别处的包(Homebrew、vcpkg、系统包等)完全无效。原因在于:编译定义在 install 时已被写死进导出的nlohmann_jsonTargets.cmake,此时即便在消费工程里set(JSON_Diagnostics ON)find_package()也无法改变它——实测中 Homebrew 安装的包导出的目标始终携带固定的$<$<BOOL:OFF>:JSON_DIAGNOSTICS=1>,与消费方设置的任何变量无关。

若确需为已安装包开启扩展诊断,唯一可靠做法是find_package()之后直接覆写导入目标的属性:

find_package(nlohmann_json REQUIRED) set_target_properties(nlohmann_json::nlohmann_json PROPERTIES INTERFACE_COMPILE_DEFINITIONS "JSON_DIAGNOSTICS=1")

该方法仅在你的工程是该导入目标的唯一消费者时才能干净工作;若依赖图中多处拉入 nlohmann_json 且JSON_DIAGNOSTICS取值不一致,同一编译命令行上可能出现相互冲突的-D标志,从而触发"JSON_DIAGNOSTICS" redefined编译错误。同理,本库其余由选项定义的宏(如关闭隐式转换、禁用枚举序列化等)对预安装包也都遵循这一限制。

实验性功能:NLOHMANN_JSON_BUILD_MODULES(C++20 module)

NLOHMANN_JSON_BUILD_MODULES用于构建实验性的 C++20 modulenlohmann.json(模块源文件见 src/modules/json.cppm)。从根 CMakeLists.txt 可见,它要求CMake ≥ 3.28,否则只会打印告警并跳过;并且由于宏无法跨模块导出,模块版不提供任何宏。其功能与限制详见 docs/mkdocs/docs/features/modules.md。

文档特别强调:消费工程除了链接nlohmann_json::nlohmann_json之外,还必须链接专用目标nlohmann_json_modulesimport nlohmann.json;才能正确解析:

set(NLOHMANN_JSON_BUILD_MODULES ON) add_subdirectory(path/to/json) add_executable(myproject main.cpp) target_link_libraries(myproject PRIVATE nlohmann_json_modules) target_compile_definitions(myproject PRIVATE NLOHMANN_JSON_BUILD_MODULES)

若你只在 C++20 下使用头文件、不接触 module,则该选项保持默认OFF即可。

关键默认值小结与选用建议

综合 CMakeLists.txt 的源码,日常集成时最常接触的默认值速查如下:

  • 作为顶层工程构建时默认开启JSON_BuildTestsJSON_Install;作为子工程引入时二者默认关闭;
  • JSON_MultipleHeadersJSON_GlobalUDLs默认ON
  • JSON_ImplicitConversions默认ON
  • JSON_DiagnosticsJSON_Diagnostic_PositionsJSON_DisableEnumSerializationJSON_LegacyDiscardedValueComparisonJSON_SystemIncludeJSON_ValgrindJSON_FastTestsJSON_CI默认OFF

实际选型可参考如下建议:小型示例与教学工程用find_package()或 FetchContent URL 方式最快;需要锁定源码版本、离线构建或整体分发的工程用add_subdirectory()内嵌(记得关掉测试与安装);希望一个工程同时兼容两种来源则用「Supporting Both」的option模式;排查解析/异常问题时在从源码构建的前提下打开JSON_Diagnostics(必要时再加JSON_Diagnostic_Positions)。所有集成路径最终都汇聚到同一个命名空间目标上,因此业务代码与target_link_libraries语句可以完全不受引入方式变化的影响。

【免费下载链接】jsonJSON for Modern C++项目地址: https://gitcode.com/GitHub_Trending/js/json

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

安卓应用签名证书在线生成与安全实践指南

1. 安卓证书在线生成的核心价值与应用场景在安卓应用开发与分发过程中&#xff0c;数字证书扮演着至关重要的角色。传统本地生成证书的方式需要开发者手动配置Java Keytool环境&#xff0c;处理复杂的命令行参数&#xff0c;这对新手开发者尤其不友好。在线生成工具通过浏览器即…

作者头像 李华
网站建设 2026/9/10 16:13:22

现在加盟酒店,选哪个品牌比较好?

现在加盟酒店选哪个品牌比较好&#xff1f;"好"是个模糊的词&#xff0c;落到投资上&#xff0c;得拆成几件能核实的事&#xff1a;品牌背景稳不稳、运营筹建成不成体系、客源底盘厚不厚。希尔顿欢朋在这三件事上都有公开信息可以逐项对照。品牌背景和合作期限希尔顿…

作者头像 李华
网站建设 2026/9/10 16:13:02

企业级聚合登录系统架构设计与安全实践

1. 项目背景与核心价值 2026全新聚合登录系统源码是当前企业级身份认证领域的一次重要技术革新。这个开源项目解决了现代应用开发中最头疼的多平台账号体系整合问题。我在实际项目中曾遇到过这样的场景&#xff1a;一个电商平台需要同时支持微信、支付宝、手机号、邮箱等8种登录…

作者头像 李华
网站建设 2026/9/10 16:12:01

论文图表公式被说格式不统一?统一排版的4步清单

图表、公式被审稿意见或导师批注"格式不统一"&#xff0c;是论文写作里高频出现的返修点。问题往往不在某一幅图画得不好&#xff0c;而在全文缺少一套统一的格式规矩&#xff1a;图与表体例各异、公式编号断档、题注前后不一&#xff0c;合在一起就显得"乱&quo…

作者头像 李华