news 2026/10/4 1:40:37

EDK II Redfish 平台的 JSON 处理基石:JsonLib(Jansson 2.13.1)封装库深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
EDK II Redfish 平台的 JSON 处理基石:JsonLib(Jansson 2.13.1)封装库深度解析
  • 固件
  • 操作系统
  • 驱动开发
  • 嵌入式

【免费下载链接】edk2

EDK II

项目地址:https://gitcode.com/gh_mirrors/ed/edk2
点击查看免费下载

本篇技术指南聚焦 edk2 仓库中RedfishPkg/Library/JsonLib这一关键基础设施:它如何将业界成熟的开源 JSON 库 Jansson 移植进 UEFI/EDK II 环境,并以JsonLib.h封装出一套面向 Redfish 应用的 EDKII JSON API。读完本文,你将掌握 Jansson 的核心设计理念、JsonLib 在 EDK II 中的构建集成方式(含配置头文件与编译选项)、其 API 映射与编码/解码标志的对应关系,以及仓库内针对上游load.c构建问题的本地修复细节。

一、Jansson:被选中的 JSON 处理引擎

RedfishPkg/Library/JsonLib/Readme.rst开篇即明确了 JsonLib 的第三方依赖:Jansson——一个用于 JSON 数据的编码、解码与操作的 C 语言库。其核心特性与设计原则包括:

  • 简单直观的 API 与数据模型:以json_t为统一句柄,对象、数组、字符串、整数、实数、布尔与 null 均通过同一套引用计数机制管理;
  • 全面的文档:Jansson 2.13 提供完整 API 参考(对应版本文档位于官方 readthedocs 站点的 2.13 分支);
  • 零外部依赖:可独立编译,便于嵌入到 UEFI 固件这类受控环境中;
  • 完整 Unicode(UTF-8)支持:词法层直接处理多字节 UTF-8 序列,并提供\uXXXX转义与代理对(surrogate pair)解码;
  • 广泛的测试套件:上游持续以自动化测试保障 API 稳定性。

在许可与适用性方面,Readme.rst 明确指出 Jansson 采用MIT 许可证(详见仓库根目录的 License.txt),API 稳定且已用于生产环境,可运行于众多类 Unix 系统与 Windows,既适用于桌面、服务器,也适用于小型嵌入式系统——这与固件场景的需求高度吻合。

事实依据:以上结论均出自 Readme.rst,属项目文档明确声明的信息。

二、JsonLib 在 EDK II / Redfish 项目中的定位

Readme.rst 特别强调:

在 UEFI/EDK II 环境中,Redfish 项目消费(consume)Jansson 来实现 JSON 操作。

这意味着 JsonLib 不是孤立模块,而是整个 Redfish 栈的数据平面基础。Redfish 协议本身以 JSON 作为资源表述格式(包括 REST 请求/响应体、属性清单、事件负载等),因此 JsonLib 提供的能力直接决定了 Redfish 驱动与库对配置数据的解析与序列化效率。

版本信息同样来自 Readme.rst:

  • edk2 上的 Jansson 版本为 2.13.1,API 行为以该版本的官方参考手册为准;
  • EDK II 的 jansson 封装层:JsonLib.h中定义了一组映射到 Jansson 函数的 EDKII JSON API,作为 EDK II 与上游库之间的稳定适配边界。

从仓库结构看,JsonLib 的封装遵循 EDK II 标准库封装惯例:公开 API 头文件放在包级 Include 目录(RedfishPkg/Include/Library/JsonLib.h),并在 RedfishPkg.dec 中注册为JsonLib|Include/Library/JsonLib.h的库类映射;同时该 .dec 文件还将Library/JsonLib(私有头文件)与Library/JsonLib/jansson/src(供引用jansson.h)登记为 include 路径(RedfishPkg.dec)。

三、库封装与构建集成

JsonLib 作为 EDK II 库模块,其构建描述位于 JsonLib.inf。关键元数据如下:

字段值说明
BASE_NAMEJsonLib库名
MODULE_TYPEDXE_DRIVER模块类型
LIBRARY_CLASSJsonLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER允许被三类模块链接
CONSTRUCTORJsonLibConstructor构造函数,负责库初始化(见下文)

源码组成(JsonLib.inf)分三组:

  1. 第三方 jansson 源码:jansson/src/下的dump.c、error.c、hashtable.c、hashtable_seed.c、memory.c、pack_unpack.c、strbuffer.c、strconv.c、utf.c、value.c、version.c——覆盖了序列化(dump)、哈希表(hashtable)、内存分配钩子(memory)、打包/解包(pack_unpack)、UTF-8 处理(utf)与核心值模型(value)等全部模块。jansson 目录本身以 git 子模块形式挂载(submodule 指向上游提交e9ebfa7e)。
  2. edk2 封装层:JsonLib.c、jansson_config.h、jansson_private_config.h。
  3. 本地修复覆盖文件:load.c(解决上游构建问题,详见第六节)。

依赖的库类(JsonLib.inf):BaseLib、BaseMemoryLib、Ucs2Utf8Lib、RedfishCrtLib、DebugLib、MemoryAllocationLib、PrintLib、UefiRuntimeServicesTableLib、UefiLib。其中RedfishCrtLib为 Redfish 包内的 C 运行时替代库(RedfishPkg.dec 注释说明 CRT 库供 edk2 JsonLib 使用),用于在固件环境补齐fopen、strtol、snprintf等标准 C 函数;JsonLib 与 RedfishCrtLib 均被纳入 RedfishPkg.dsc 参与包级构建。

3.1 编译选项与警告抑制

由于 Jansson 是面向宿主系统的 C 代码,直接编入 EDK II 需要专门处理工具链差异。JsonLib.inf 的[BuildOptions]给出了 MSFT 与 GCC 两套策略(JsonLib.inf):

  • MSFT(VS):/wd4204 /wd4244 /wd4090 /wd4334 /wd4706抑制 const 限定符不一致、类型转换截断、32 位移位隐式转 64 位、非标准非 const 聚合初始化、条件表达式内赋值等警告,避免在/WX下构建失败;同时-DHAVE_CONFIG_H=1让 jansson 源码包含jansson_private_config.h,并通过/U_WIN32 /UWIN64 /U_MSC_VER屏蔽 Windows 预定义宏,防止 jansson 走 MSVC 专用分支。
  • GCC:-Wno-unused-function -Wno-unused-but-set-variable容忍未使用函数与变量警告;同样定义HAVE_CONFIG_H=1并取消WIN32/_WIN32/WIN64/_MSC_VER;X64 额外追加-DNO_MSABI_VA_FUNCS(关闭 MS ABI 可变参数函数约定,适配 GCC 的 SysV ABI 实现)。

3.2 配置头文件:UEFI 环境的裁剪开关

Jansson 原生通过 autotools/CMake 生成jansson_config.h,而 JsonLib 用两份手工维护的头文件完成等价配置:

jansson_config.h(文件本体)声明了 UEFI 下的关键能力取舍:

宏值含义
JSON_INLINE(定义)使用内联而非static inline,适配 EDK II 编译环境
JSON_INTEGER_IS_LONG_LONG1整数类型采用 64 位 long long,对应封装层EDKII_JSON_INT_T为INT64
JSON_HAVE_LOCALECONV0不支持 locale 相关转换(避免依赖宿主 locale)
JSON_HAVE_ATOMIC_BUILTINS0禁用 GCC 原子内建函数
JSON_HAVE_SYNC_BUILTINS0禁用 GCC 同步内建函数(UEFI 单任务环境无需原子同步)
JSON_PARSER_MAX_DEPTH2048解析器最大嵌套深度限制

jansson_private_config.h(文件本体)补充:

宏值含义
HAVE_SYS_TIME_H1声明存在<sys/time.h>
HAVE_SYS_TYPES_H1声明存在<sys/types.h>
INITIAL_HASHTABLE_ORDER3对象哈希表初始容量阶(2^3 = 8 个桶),控制小对象的内存开销

HAVE_UNISTD_H未在此定义,这一细节正是第六节所述构建问题的修复开关所在。

四、EDKII JSON API 封装(JsonLib.h)

公开接口定义在 RedfishPkg/Include/Library/JsonLib.h,共 945 行,是 EDK II 侧唯一需要包含的头文件。其核心设计是将 Jansson 的json_t*句柄抽象为不透明指针:

typedef VOID *EDKII_JSON_VALUE; typedef VOID *EDKII_JSON_ARRAY; typedef VOID *EDKII_JSON_OBJECT;

同时以typedef INT64 EDKII_JSON_INT_T;映射 Jansson 的json_int_t(头文件注释明确对应JSON_INTEGER_IS_LONG_LONG置 1 的配置,JsonLib.h)。

4.1 类型与错误模型

  • EDKII_JSON_TYPE枚举(JsonLib.h):Object、Array、String、Integer、Real、True、False、Null八种类型,与json_type一一对应;
  • EDKII_JSON_ERROR结构(JsonLib.h):映射json_error_t,字段包括Line、Column、Position、Source(80 字节,错误来源标识,如<string>/<buffer>)与Text(160 字节,错误消息文本),可用于定位解析失败的具体行列位置。

4.2 解码标志(Decoding Flags)

对应 Jansson 2.13 的json_loads/loadb系列标志(JsonLib.h):

EDKII 宏值对应行为
EDKII_JSON_REJECT_DUPLICATES0x1拒绝重复对象键(默认允许后者覆盖前者)
EDKII_JSON_DISABLE_EOF_CHECK0x2禁用 EOF 检查,允许解析多个 JSON 值
EDKII_JSON_DECODE_ANY0x4允许根节点为任意 JSON 类型(否则必须是对象或数组)
EDKII_JSON_DECODE_INT_AS_REAL0x8将整数按实数解码
EDKII_JSON_ALLOW_NUL0x10允许字符串中出现\u0000

4.3 编码标志(Encoding Flags)

对应json_dumps/dumpf系列(JsonLib.h):

EDKII 宏值对应行为
EDKII_JSON_MAX_INDENT/EDKII_JSON_INDENT(n)0x1F /(n)&0x1F缩进控制(0 为压缩,1~31 为空格缩进量)
EDKII_JSON_COMPACT0x20紧凑输出(去掉多余空白)
EDKII_JSON_ENSURE_ASCII0x40非 ASCII 字符转义为\uXXXX输出
EDKII_JSON_SORT_KEYS0x80按键排序输出
EDKII_JSON_PRESERVE_ORDER0x100保持插入顺序(需要哈希表支持有序遍历)
EDKII_JSON_ENCODE_ANY0x200允许编码任意根类型
EDKII_JSON_ESCAPE_SLASH0x400转义/为\/
EDKII_JSON_REAL_PRECISION(n)((n)&0x1F)<<11实数打印精度控制
EDKII_JSON_EMBED0x10000嵌入模式(JsonLib 扩展)

4.4 便利宏

头文件还提供两个遍历宏(JsonLib.h):

  • EDKII_JSON_ARRAY_FOREACH(Array, Index, Value):按索引遍历数组元素;
  • EDKII_JSON_OBJECT_FOREACH_SAFE(Object, N, Key, Value):通过迭代器安全遍历对象键值对,N保存迭代游标以支持遍历中安全操作。

4.5 函数族概览

JsonLib.c(文件本体,32 KB)实现全部封装函数,覆盖:值创建与释放(JsonValueInitArray/Object/String/Integer/Real/True/False/Null、JsonValueFree)、类型判断与取值(JsonValueGetType、JsonValueGetString/Integer/Real/Boolean)、对象操作(JsonObjectSetValue/GetValue/Remove/ContainsKey、迭代器系列)、数组操作(JsonArrayAppend/Insert/Set/Get/Remove/Count)、序列化与反序列化(JsonDumpString、JsonLoadString等),以及深拷贝/比较工具。所有创建型 API 遵循引用计数策略:新值引用计数为 1,由调用方通过JsonValueFree()释放,与 Jansson 的json_incref/decref语义保持一致(参见 JsonLib.h 中JsonValueInitArray的接口注释)。

五、构造函数与内存管理

JsonLib 定义了JsonLibConstructor构造函数(JsonLib.inf),在模块加载时完成库级初始化。结合 Jansson 的memory.c设计可知,Jansson 支持通过json_set_alloc_funcs()注入自定义内存分配器——这正是 UEFI 环境的关键适配点:JsonLib 在构造函数中为 jansson 挂接 EDK II 的AllocatePool/FreePool体系,确保第三方库的内存分配纳入固件的内存管理域,避免与 UEFI 内存模型冲突(这一结论由 JsonLib 依赖MemoryAllocationLib以及 jansson 可配置分配器机制共同推断)。

六、已知问题与本地修复:load.c 的 stdin 条件编译

Readme.rst 记录了 JsonLib 在集成过程中遇到并解决的唯一已知问题:

构建失败出现在jansson/src/load.c。修复方式是在load.c中增加代码,根据HAVE_UNISTD_H宏条件性地使用 stdin。该修复 PR 已提交至 Jansson 开源社区(akheron/jansson#558)。

在仓库中,这一修复以独立覆盖文件RedfishPkg/Library/JsonLib/load.c 的形式存在(1424 行),并在 JsonLib.inf 中显式标注为"修复构建问题的源码覆盖",编译时替换上游同名文件参与构建。

从源码看,修复的实际落点非常清晰:

  1. 头文件条件包含:load.c 用#ifdef HAVE_UNISTD_H包裹#include <unistd.h>,避免在无 POSIX 环境的固件工具链中因缺失头文件而编译失败;
  2. json_loadf的 stdin 判定:load.c 中,只有定义了HAVE_UNISTD_H时才将input == stdin映射为错误来源<stdin>,否则统一归为<stream>——UEFI 环境没有标准stdin概念,此判定可防止对全局stdin符号的隐式依赖;
  3. json_loadfd的 STDIN_FILENO 判定:load.c 同样以HAVE_UNISTD_H保护对STDIN_FILENO宏的引用,并在 fd_get_func 中把read()调用整体置于该宏保护之下。

由于 edk2 的 jansson_private_config.h 刻意不定义HAVE_UNISTD_H(只定义HAVE_SYS_TIME_H/HAVE_SYS_TYPES_H),上述 stdin/read 相关代码路径在固件构建中会被整体剔除,从而实现"既不破坏编译、又保留宿主平台完整功能"的双重目标。

七、解析器实现纵深:从 JSON 文本到 json_t

深入本地 load.c 可以还原 Jansson 解析器的完整工作流,这对理解 JsonLib 行为与错误报告至关重要:

  1. 词法分析(lexer):stream_t结构(load.c)按字节流驱动,stream_get(load.c)负责多字节 UTF-8 序列的切分与校验(utf8_check_first/utf8_check_full),任何非法字节都会以json_error_invalid_utf8终止解析;lex_scan_string(load.c)处理转义序列、\uXXXX及 UTF-16 代理对合成;
  2. 语法分析(parser):parse_json(load.c)要求根节点为[或{(除非置位JSON_DECODE_ANY),随后递归调用parse_object/parse_array/parse_value构建对象树;parse_value(load.c)以lex->depth与JSON_PARSER_MAX_DEPTH(edk2 配置为 2048)配合检测栈溢出,超过即报json_error_stack_overflow;
  3. 错误上下文:错误对象记录行/列/位置,并附带出错位置附近的文本片段(error_set,load.c),非标准错误码(如文件提前结束)会细化映射为json_error_premature_end_of_input;
  4. 多种输入源:本地 load.c 实现了六种入口——json_loads(以\0结尾的 C 字符串,load.c)、json_loadb(定长缓冲区,load.c)、json_loadf(FILE*)、json_loadfd(文件描述符)、json_load_file(路径打开文件)与json_load_callback(回调式增量读取,内置 1024 字节缓冲,load.c)。其中json_loadb与json_loads最贴合固件场景——Redfish 消息通常以内存缓冲区形式到达,无需文件系统支持。

这也解释了为何 JsonLib 能在无文件系统的 UEFI 阶段正常工作:JsonLib 封装层主要面向字符串/缓冲区输入,文件与 fd 入口保留给宿主侧工具链或具备文件系统的运行阶段使用。

八、如何在 EDK II 项目中启用 JsonLib

若要在自定义平台中使用 JsonLib,通常需要以下三步(依据仓库现有配置整理):

  1. 包依赖:确保平台 .dsc 的[Packages]包含MdePkg/MdePkg.dec、MdeModulePkg/MdeModulePkg.dec与RedfishPkg/RedfishPkg.dec(参见 JsonLib.inf);
  2. 库引用:在模块 .inf 的[LibraryClasses]声明JsonLib,或在平台 .dsc 的[LibraryClasses.common]中指定JsonLib|RedfishPkg/Library/JsonLib/JsonLib.inf(JsonLib 支持被 DXE_DRIVER、UEFI_APPLICATION、UEFI_DRIVER 三类模块链接);
  3. 包含头文件:源码中#include <Library/JsonLib.h>即可使用EDKII_JSON_VALUE等全部 API,无需直接引用 jansson 头文件。

包级构建时,RedfishPkg.dsc 已默认编译 JsonLib 与 RedfishCrtLib,Redfish 系驱动(如 RedfishDiscoverDxe、RedfishRestExDxe)均在此基础上获得统一的 JSON 处理能力。

九、小结

JsonLib 是 edk2 中 Redfish 功能栈与第三方 Jansson 之间的桥梁:上游提供成熟稳定的 JSON 引擎(MIT 许可、零依赖、UTF-8 完备、测试充分),JsonLib 通过 JsonLib.inf 的精细化构建配置、jansson_config.h 与 jansson_private_config.h 的能力裁剪、JsonLib.h 的类型/标志映射,以及 load.c 的本地修复,将这一通用库无缝嵌入 UEFI 固件环境。理解这一层的设计,无论是排查 Redfish 数据解析问题,还是为其他固件场景引入 JSON 能力,都能直接复用本文所述的移植方法论。

  • 固件
  • 操作系统
  • 驱动开发
  • 嵌入式

【免费下载链接】edk2

EDK II

项目地址:https://gitcode.com/gh_mirrors/ed/edk2
点击查看免费下载
上一篇:Melody:你的私人音乐管理精灵
下一篇:Google Code Search 使用指南

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

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

【C++进阶】02 Linux基本指令

目录 1 Linux 目录树、绝对路径与相对路径 2 ls pwd cd 目录基础命令 pwd&#xff1a;打印当前工作目录 ls&#xff1a;列出目录内容 cd&#xff1a;切换目录 change directory 3 touch mkdir rmdir rm 文件目录增删 touch&#xff1a;创建普通空文件&#xff1b;修改文件…

作者头像 李华
网站建设 2026/10/4 1:37:21

MATLAB实现泽尼克多项式:从原理到工程绘图

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:37:21

八邻域算法在智能车图像处理中的边界追踪与补线实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:37:21

深度学习中的卷积核(kernel)与滤波器(filter)本质辨析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:37:06

MR25H40CDF+STM32F756ZG:SPI接口实现MRAM掉电不丢数据

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 1:37:04

Linux UVC驱动开发实战:从uvc_driver.rar编译到v4l2出图全链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华