十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

nlohmann/json 的 CMake 集成全指南:五种引入方式、`nlohmann_json::nlohmann_json` 目标与全部构建选项解析 nlohmann/json 的 CMake 集成全指南五种引入方式、nlohmann_json::nlohmann_json目标与全部构建选项解析【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/jsonJSON for Modern Cnlohmann/json是一个纯头文件库官方推荐通过 CMake 的接口目标INTERFACE targetnlohmann_json::nlohmann_json进行集成——它会自动携带正确的头文件搜索路径与 C11 编译特性要求。本文以项目文档 docs/mkdocs/docs/integration/cmake.md 为主线结合仓库根目录的 CMakeLists.txt 与tests/cmake_*集成测试完整讲解find_package、add_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向所有消费者传递C11 编译特性要求保证头文件所依赖的语言特性可用通过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策略允许外部-D或CACHE变量覆盖库的默认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_DIAGNOSTICS1JSON_Diagnostic_PositionsOFF开启异常诊断中的行列位置信息JSON_DIAGNOSTIC_POSITIONS1JSON_DisableEnumSerializationOFF关闭默认的枚举序列化JSON_DISABLE_ENUM_SERIALIZATION1JSON_FastTestsOFF跳过耗时测试套件依赖JSON_BuildTestsJSON_GlobalUDLsON将_json等用户自定义字面量放入全局命名空间JSON_USE_GLOBAL_UDLS详见下文JSON_ImplicitConversionsON开启隐式类型转换JSON_USE_IMPLICIT_CONVERSIONS关闭时置 0JSON_Install顶层工程为ON子工程为OFFinstall 步骤是否安装 CMake 目标JSON_LegacyDiscardedValueComparisonOFF恢复被丢弃discardedJSON 值的旧版错误比较行为JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON1JSON_MultipleHeadersON使用多头文件版include/置OFF则使用单头文件版single_include/JSON_SystemIncludeOFF将库头文件按系统头文件方式添加加SYSTEM便于 Clang-Tidy 等工具跳过检查JSON_ValgrindOFF使用 Valgrind 执行测试套件依赖JSON_BuildTestsNLOHMANN_JSON_BUILD_MODULESOFF构建实验性 C20 modulenlohmann.json需 CMake 3.28逐项深入说明JSON_BuildTests与 CTest 的BUILD_TESTING联动。库的默认值通过 CMakeLists.txt 中MAIN_PROJECT检测逻辑决定当库本身是顶层工程时预设为ON作为子工程引入时预设为OFF因此“按上述方式集成时若不显式打开该选项不会构建整套测试”。最终编译测试还要求NOT DEFINED BUILD_TESTING OR BUILD_TESTINGCMakeLists.txt。仓库的完整测试代码位于 tests/src可在需要时自行开启。JSON_Diagnostics与JSON_Diagnostic_Positions分别对应宏JSON_DIAGNOSTICS与JSON_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.pcpkg-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_DIAGNOSTICS1与消费方设置的任何变量无关。若确需为已安装包开启扩展诊断唯一可靠做法是find_package()之后直接覆写导入目标的属性find_package(nlohmann_json REQUIRED) set_target_properties(nlohmann_json::nlohmann_json PROPERTIES INTERFACE_COMPILE_DEFINITIONS JSON_DIAGNOSTICS1)该方法仅在你的工程是该导入目标的唯一消费者时才能干净工作若依赖图中多处拉入 nlohmann_json 且JSON_DIAGNOSTICS取值不一致同一编译命令行上可能出现相互冲突的-D标志从而触发JSON_DIAGNOSTICS redefined编译错误。同理本库其余由选项定义的宏如关闭隐式转换、禁用枚举序列化等对预安装包也都遵循这一限制。实验性功能NLOHMANN_JSON_BUILD_MODULESC20 moduleNLOHMANN_JSON_BUILD_MODULES用于构建实验性的 C20 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)若你只在 C20 下使用头文件、不接触 module则该选项保持默认OFF即可。关键默认值小结与选用建议综合 CMakeLists.txt 的源码日常集成时最常接触的默认值速查如下作为顶层工程构建时默认开启JSON_BuildTests与JSON_Install作为子工程引入时二者默认关闭JSON_MultipleHeaders与JSON_GlobalUDLs默认ONJSON_ImplicitConversions默认ONJSON_Diagnostics、JSON_Diagnostic_Positions、JSON_DisableEnumSerialization、JSON_LegacyDiscardedValueComparison、JSON_SystemInclude、JSON_Valgrind、JSON_FastTests、JSON_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),仅供参考
返回列表