cJSON 适配 OpenHarmony PC 完整指南
零依赖优势:cJSON 无外部依赖,集成简单双库支持:同时提供静态库和动态库标准兼容:完全符合 JSON 标准易于使用:API 简洁,文档完善高性能:解析速度快,内存占用小。
cJSON 适配 OpenHarmony PC 完整指南
项目概述
什么是 cJSON?
cJSON 是一个超轻量级的 JSON 解析库,使用 ANSI C 编写,具有以下特点:
- 📦 超轻量级:单文件实现,代码简洁高效
- 🚀 高性能:解析速度快,内存占用小
- 🔧 易于集成:纯 C 实现,无外部依赖
- ✅ 标准兼容:完全符合 JSON 标准(RFC 7159)
- 🌐 跨平台:支持多种操作系统和架构
适配版本
- 目标版本: OpenHarmony-v6.0.0.1-Release
- cJSON 版本: 1.7.17
- 架构支持: arm64-v8a
- 构建系统: CMake
- 许可证: MIT
核心功能
- ✅ JSON 解析和生成
- ✅ 内存管理
- ✅ UTF-8 支持
- ✅ 流式解析(可选)
- ✅ 线程安全(可选)
技术架构
项目结构
cJSON/
├── cJSON.c # 核心实现文件
├── cJSON.h # 公共头文件
├── cJSON_Utils.c # 工具函数(可选)
├── cJSON_Utils.h # 工具函数头文件
├── CMakeLists.txt # CMake 构建配置
├── tests/ # 测试套件
└── fuzzing/ # 模糊测试
库类型
cJSON 支持两种库类型:
-
静态库 (
libcjson.a)- 编译时链接
- 无运行时依赖
- 适合嵌入式系统
-
动态库 (
libcjson.so)- 运行时链接
- 节省磁盘空间
- 支持版本控制
依赖关系
cJSON
└── (无依赖) # 纯 C 实现,无外部依赖
💡 优势:cJSON 是零依赖库,这使得它在 OpenHarmony PC 上的集成非常简单。
适配过程详解
步骤 1:配置外部仓库
在 outerrepo/module.json 中添加 cJSON 的配置:
{
"name": "cJson",
"branch": "ohos_6.0.0.1",
"version": "6.0.0.1",
"type": "git",
"url": "https://gitcode.com/OpenHarmonyPCDeveloper/ohos_cJson.git"
}
配置说明:
name: 模块名称,对应目录名(注意大小写:cJson)branch: Git 分支名,对应适配版本version: 版本号,用于构建和打包type: 源码获取方式,git表示使用 Git 克隆url: 源码仓库地址
步骤 2:创建 HPKBUILD 文件
在 outerrepo/cJson/HPKBUILD 中定义构建流程:
# 包基本信息
pkgname=cJson
pkgver=6.0.0.1
fullpkgver=OpenHarmony-v${pkgver}-Release
pkgrel=0
pkgdesc="Ultralightweight JSON parser in ANSI C."
url="https://gitcode.com/openharmony/third_party_cJSON"
archs=("arm64-v8a")
license=("MIT")
# 依赖声明(cJSON 无依赖)
depends=()
makedepends=()
# 源码配置
source="https://gitcode.com/openharmony/third_party_cJSON.git"
autounpack=false # 不使用自动解压
downloadpackage=false # 不使用自动下载
builddir=$pkgname-${pkgver}
download_and_patch_flag=true
licensefile=${builddir}/LICENSE
关键配置说明:
-
depends=():- cJSON 是零依赖库,不需要任何依赖
- 这使得构建过程非常简单
-
autounpack=false:- 使用 Git 克隆,不需要自动解压
- 源码通过
prepare()函数中的git clone获取
-
license=("MIT"):- MIT 许可证,非常宽松
- 适合商业和开源项目使用
步骤 3:实现 prepare() 函数
prepare() 函数负责准备构建环境:
prepare() {
# 检查源码目录是否存在
if [ -d $builddir ]
then
echo ${builddir} is already exist
rm -rf ${builddir}/$ARCH-build
else
if [ "$download_and_patch_flag" == true ]
then
# Git 克隆源码
git clone $source $builddir
if [ $? -ne 0 ]
then
return -1
fi
# 切换到指定版本标签
pushd $builddir
git reset --hard $fullpkgver
if [ $? -ne 0 ]
then
popd
return -2
fi
popd
download_and_patch_flag=false
fi
fi
# 创建构建目录
mkdir -p ${builddir}/$ARCH-build
# 设置交叉编译环境
if [ $ARCH == "arm64-v8a" ]
then
export TARGET_PLATFORM=aarch64-linux-ohos
setarm64ENV
else
echo "${ARCH} not support"
return -1
fi
}
关键点:
-
Git 版本控制:
git clone $source $builddir git reset --hard $fullpkgver- 克隆 OpenHarmony 的 cJSON 适配版本
- 切换到指定的版本标签(
OpenHarmony-v6.0.0.1-Release)
-
构建目录管理:
mkdir -p ${builddir}/$ARCH-build- 为每个架构创建独立的构建目录
- 支持多架构并行构建
-
环境变量设置:
setarm64ENV- 设置交叉编译工具链(CC, CXX, AR 等)
- 设置编译选项(CFLAGS, CXXFLAGS, LDFLAGS)
步骤 4:实现 build() 函数
build() 函数执行实际的编译过程:
build() {
pushd ${builddir}
# 配置 CMake
${CMAKE} "$@" \
-DBUILD_SHARED_AND_STATIC_LIBS=ON \
-DENABLE_CJSON_TEST=OFF \
-B$ARCH-build -S./ -L
# 执行编译
pushd ${ARCH}-build
${MAKE} VERBOSE=1
ret=$?
popd
popd
return $ret
}
关键点:
-
CMake 配置选项:
-DBUILD_SHARED_AND_STATIC_LIBS=ON- 同时构建静态库和动态库
- 静态库:
libcjson.a - 动态库:
libcjson.so.1.7.17(带版本号)
-
禁用测试:
-DENABLE_CJSON_TEST=OFF- 构建时不需要运行测试套件
- 加快构建速度
- 测试可以在目标设备上进行
-
CMake 参数:
-B$ARCH-build: 指定构建目录-S./: 指定源码目录(当前目录)-L: 列出所有 CMake 变量(调试用)
步骤 5:CMakeLists.txt 配置分析
cJSON 的 CMakeLists.txt 提供了丰富的配置选项:
5.1 编译器标志
option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags" ON)
if (ENABLE_CUSTOM_COMPILER_FLAGS)
if (("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
list(APPEND custom_compiler_flags
-std=c89
-pedantic
-Wall
-Wextra
-Werror
# ... 更多警告选项
)
endif()
endif()
说明:
- 使用 C89 标准,确保最大兼容性
- 启用严格的警告检查
- 使用
-Werror将警告视为错误
5.2 库类型配置
option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" OFF)
选项说明:
ON: 同时构建静态库和动态库(本适配使用)OFF: 只构建静态库或动态库(取决于BUILD_SHARED_LIBS)
5.3 符号可见性
option(ENABLE_PUBLIC_SYMBOLS "Export library symbols." On)
if (ENABLE_PUBLIC_SYMBOLS)
list(APPEND custom_compiler_flags -fvisibility=hidden)
add_definitions(-DCJSON_EXPORT_SYMBOLS -DCJSON_API_VISIBILITY)
endif()
说明:
- 控制符号的可见性
- 减少符号冲突
- 提高库的安全性
步骤 6:实现 package() 函数
package() 函数安装编译产物:
package() {
pushd ${builddir}/$ARCH-build
$MAKE VERBOSE=1 install PREFIX=$LYCIUM_ROOT/usr/$pkgname/$ARCH >> $buildlog 2>&1
ret=$?
popd
return $ret
}
安装内容:
安装后的目录结构:
lycium/usr/cJson/arm64-v8a/
├── include/
│ └── cjson/
│ └── cJSON.h # 公共头文件
├── lib/
│ ├── libcjson.a # 静态库
│ ├── libcjson.so # 动态库符号链接
│ ├── libcjson.so.1 # 版本符号链接
│ ├── libcjson.so.1.7.17 # 实际动态库文件
│ ├── cmake/
│ │ └── cJSON/
│ │ ├── cJSONConfig.cmake
│ │ ├── cJSONConfigVersion.cmake
│ │ ├── cjson-release.cmake
│ │ └── cjson.cmake
│ └── pkgconfig/
│ └── libcjson.pc # pkg-config 配置文件
└── hnp.json # HNP 配置文件
文件说明:
| 文件/目录 | 说明 |
|---|---|
include/cjson/cJSON.h |
公共头文件,应用程序需要包含 |
lib/libcjson.a |
静态库,编译时链接 |
lib/libcjson.so.* |
动态库,运行时链接 |
lib/cmake/cJSON/ |
CMake 配置文件,用于 CMake 项目集成 |
lib/pkgconfig/libcjson.pc |
pkg-config 配置文件,用于查找库 |
步骤 7:实现 archive() 函数
archive() 函数生成最终的打包产物:
archive() {
# 创建输出目录
mkdir -p ${LYCIUM_ROOT}/output/$ARCH
# 创建 tar.gz 归档
pushd $LYCIUM_ROOT/usr/$pkgname/$ARCH
tar -zvcf ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz *
popd
# 复制 HNP 配置文件
cp hnp.json $LYCIUM_ROOT/usr/$pkgname/$ARCH
# 生成 HNP 包
${HNP_TOOL} pack -i ${LYCIUM_ROOT}/usr/$pkgname/$ARCH -o ${LYCIUM_ROOT}/output/$ARCH/
}
说明:
- 生成两种格式的包:
tar.gz: 二进制归档包,包含所有库文件和头文件.hnp: HarmonyOS Native Package,用于 HarmonyOS 系统安装
步骤 8:配置 hnp.json
hnp.json 定义 HNP 包的元数据:
{
"type": "hnp-config",
"name": "cJson",
"version": "1.7.17",
"install": {}
}
字段说明:
type: 固定为"hnp-config"name: 包名称,必须与pkgname一致(注意大小写)version: cJSON 的实际版本号(1.7.17),不是适配版本号install: 安装规则(空对象表示安装所有文件)
⚠️ 注意:
version字段使用的是 cJSON 的实际版本号(1.7.17),而不是适配版本号(6.0.0.1)。
构建流程
完整构建命令
cd lycium
./build.sh cJson
构建过程详解
构建日志示例
Build OS Darwin
OHOS_SDK=/Users/jianguo/Library/OpenHarmony/Sdk/20
CLANG_VERSION=15.0.4
Start building cJson 6.0.0.1!
Compileing OpenHarmony arm64-v8a cJson 6.0.0.1 libs...
cJson-6.0.0.1 is already exist
-- The C compiler identification is Clang 15.0.4
-- The CXX compiler identification is Clang 15.0.4
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Users/jianguo/Library/OpenHarmony/Sdk/20/native/llvm/bin/aarch64-linux-ohos-clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: arm64-v8a-build
[ 50%] Building C object CMakeFiles/cjson.dir/cJSON.c.o
[100%] Linking C shared library libcjson.so.1.7.17
[100%] Built target cjson
[ 50%] Building C object CMakeFiles/cjson-static.dir/cJSON.c.o
[100%] Linking C static library libcjson.a
[100%] Built target cjson-static
Install the project...
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/include/cjson/cJSON.h
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/libcjson.so.1.7.17
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/libcjson.so.1
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/libcjson.so
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/libcjson.a
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/cmake/cJSON/cJSONConfig.cmake
-- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/pkgconfig/libcjson.pc
Build cJson 6.0.0.1 end!
ALL JOBS DONE!!!
构建产物
目录结构
lycium/
├── output/
│ └── arm64-v8a/
│ ├── cJson.hnp # HNP 归档包
│ └── cJson_6.0.0.1.tar.gz # 二进制归档包
└── usr/
└── cJson/
└── arm64-v8a/
├── include/
│ └── cjson/
│ └── cJSON.h
├── lib/
│ ├── libcjson.a
│ ├── libcjson.so -> libcjson.so.1
│ ├── libcjson.so.1 -> libcjson.so.1.7.17
│ ├── libcjson.so.1.7.17
│ ├── cmake/
│ │ └── cJSON/
│ │ ├── cJSONConfig.cmake
│ │ ├── cJSONConfigVersion.cmake
│ │ ├── cjson-release.cmake
│ │ └── cjson.cmake
│ └── pkgconfig/
│ └── libcjson.pc
└── hnp.json
产物说明
1. 头文件
$ file lycium/usr/cJson/arm64-v8a/include/cjson/cJSON.h
cJSON.h: ASCII text
用途:
- 应用程序需要包含此头文件
- 包含所有 cJSON API 定义
2. 静态库
$ file lycium/usr/cJson/arm64-v8a/lib/libcjson.a
libcjson.a: current ar archive
特点:
- 编译时链接到应用程序
- 无运行时依赖
- 适合嵌入式系统
3. 动态库
$ file lycium/usr/cJson/arm64-v8a/lib/libcjson.so.1.7.17
libcjson.so.1.7.17: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-aarch64.so.1, with debug_info, not stripped
特点:
- ARM64 架构
- 动态链接到 musl C 库
- 包含版本号(1.7.17)
- 包含调试信息
4. CMake 配置文件
用途:
- 用于 CMake 项目集成
- 自动查找库和头文件
- 设置编译选项
使用示例:
find_package(cJSON REQUIRED)
target_link_libraries(myapp cjson)
5. pkg-config 配置文件
用途:
- 用于 pkg-config 工具查找库
- 自动设置编译和链接选项
使用示例:
pkg-config --cflags --libs libcjson
使用示例
示例 1:基本 JSON 解析
#include <cjson/cJSON.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
// JSON 字符串
const char *json_string = "{\"name\":\"cJSON\",\"version\":\"1.7.17\"}";
// 解析 JSON
cJSON *json = cJSON_Parse(json_string);
if (json == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error before: %s\n", error_ptr);
}
return 1;
}
// 获取字段值
cJSON *name = cJSON_GetObjectItemCaseSensitive(json, "name");
cJSON *version = cJSON_GetObjectItemCaseSensitive(json, "version");
if (cJSON_IsString(name) && (name->valuestring != NULL)) {
printf("Name: %s\n", name->valuestring);
}
if (cJSON_IsString(version) && (version->valuestring != NULL)) {
printf("Version: %s\n", version->valuestring);
}
// 释放内存
cJSON_Delete(json);
return 0;
}
编译命令:
aarch64-linux-ohos-clang \
-I$LYCIUM_ROOT/usr/cJson/arm64-v8a/include \
-L$LYCIUM_ROOT/usr/cJson/arm64-v8a/lib \
-lcjson \
example.c -o example
示例 2:创建 JSON 对象
#include <cjson/cJSON.h>
#include <stdio.h>
int main() {
// 创建 JSON 对象
cJSON *json = cJSON_CreateObject();
cJSON *name = cJSON_CreateString("cJSON");
cJSON *version = cJSON_CreateString("1.7.17");
cJSON *features = cJSON_CreateArray();
cJSON_AddItemToObject(json, "name", name);
cJSON_AddItemToObject(json, "version", version);
cJSON_AddItemToObject(json, "features", features);
// 添加数组元素
cJSON_AddItemToArray(features, cJSON_CreateString("lightweight"));
cJSON_AddItemToArray(features, cJSON_CreateString("portable"));
cJSON_AddItemToArray(features, cJSON_CreateString("standard"));
// 转换为字符串
char *json_string = cJSON_Print(json);
printf("%s\n", json_string);
// 释放内存
free(json_string);
cJSON_Delete(json);
return 0;
}
示例 3:使用 CMake 集成
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(myapp)
set(CMAKE_C_STANDARD 11)
# 查找 cJSON
find_path(CJSON_INCLUDE_DIR cjson/cJSON.h
PATHS ${LYCIUM_ROOT}/usr/cJson/arm64-v8a/include)
find_library(CJSON_LIBRARY
NAMES cjson
PATHS ${LYCIUM_ROOT}/usr/cJson/arm64-v8a/lib)
# 添加可执行文件
add_executable(myapp main.c)
# 链接库
target_include_directories(myapp PRIVATE ${CJSON_INCLUDE_DIR})
target_link_libraries(myapp ${CJSON_LIBRARY})
关键技术点
1. 零依赖设计
优势:
- ✅ 集成简单,无需处理依赖关系
- ✅ 编译快速,减少构建时间
- ✅ 部署方便,无运行时依赖
- ✅ 兼容性好,适合各种环境
实现:
- 纯 ANSI C 实现
- 只依赖标准 C 库
- 无第三方库依赖
2. 双库支持
静态库 (libcjson.a):
- 编译时链接
- 适合嵌入式系统
- 无运行时依赖
动态库 (libcjson.so):
- 运行时链接
- 节省磁盘空间
- 支持版本控制
配置:
-DBUILD_SHARED_AND_STATIC_LIBS=ON
3. CMake 集成支持
配置文件:
cJSONConfig.cmake: CMake 包配置cJSONConfigVersion.cmake: 版本配置cjson.cmake: 导入目标定义
使用方式:
find_package(cJSON REQUIRED)
target_link_libraries(myapp cjson)
4. pkg-config 支持
配置文件:lib/pkgconfig/libcjson.pc
使用方式:
pkg-config --cflags --libs libcjson
输出示例:
-I/usr/include/cjson -L/usr/lib -lcjson
常见问题与解决方案
问题 1:Git 克隆失败
症状:
git clone $source $builddir
ERROR: Failed to clone repository
解决方案:
- 检查网络连接
- 验证仓库 URL
- 检查 Git 凭据
# 手动测试
git clone https://gitcode.com/openharmony/third_party_cJSON.git test
问题 2:版本标签不存在
症状:
git reset --hard OpenHarmony-v6.0.0.1-Release
fatal: Could not resolve HEAD to a revision
解决方案:
- 检查标签是否存在
- 使用正确的标签格式
# 列出所有标签
git tag -l
# 检查特定标签
git show-ref --tags | grep 6.0.0.1
问题 3:CMake 配置失败
症状:
CMake Error: Could not find CMAKE_C_COMPILER
解决方案:
- 确保环境变量已设置
- 检查工具链路径
# 检查环境变量
echo $CC
echo $CMAKE
# 验证工具链
which aarch64-linux-ohos-clang
问题 4:链接错误
症状:
undefined reference to `cJSON_Parse'
解决方案:
- 确保链接了 cJSON 库
- 检查库路径
# 检查库文件
ls -lh lycium/usr/cJson/arm64-v8a/lib/
# 验证链接选项
aarch64-linux-ohos-clang ... -L/path/to/lib -lcjson
问题 5:头文件找不到
症状:
fatal error: 'cjson/cJSON.h' file not found
解决方案:
- 检查头文件路径
- 添加包含目录
# 检查头文件
ls -lh lycium/usr/cJson/arm64-v8a/include/cjson/
# 添加包含选项
-I$LYCIUM_ROOT/usr/cJson/arm64-v8a/include
最佳实践
1. 内存管理
- ✅ 使用
cJSON_Delete()释放 JSON 对象 - ✅ 使用
free()释放cJSON_Print()返回的字符串 - ✅ 检查返回值,避免空指针访问
- ✅ 使用
cJSON_GetErrorPtr()获取错误信息
2. 错误处理
cJSON *json = cJSON_Parse(json_string);
if (json == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error: %s\n", error_ptr);
}
return 1;
}
3. 类型检查
cJSON *item = cJSON_GetObjectItem(json, "key");
if (cJSON_IsString(item) && (item->valuestring != NULL)) {
// 安全使用字符串值
printf("%s\n", item->valuestring);
}
4. 性能优化
- ✅ 使用
cJSON_ParseWithOpts()进行流式解析 - ✅ 避免频繁创建和删除 JSON 对象
- ✅ 使用对象池管理 JSON 对象
- ✅ 合理使用
cJSON_Minify()压缩 JSON
总结
适配要点
- 零依赖优势:cJSON 无外部依赖,集成简单
- 双库支持:同时提供静态库和动态库
- 标准兼容:完全符合 JSON 标准
- 易于使用:API 简洁,文档完善
- 高性能:解析速度快,内存占用小
技术亮点
- ✅ 纯 C 实现,跨平台兼容
- ✅ CMake 和 pkg-config 支持
- ✅ 完善的错误处理机制
- ✅ 丰富的 API 接口
适用场景
- JSON 数据解析和生成
- 配置文件处理
- API 数据交换
- 日志格式化
- 数据序列化
关键词: cJSON, OpenHarmony, JSON解析, CMake, 零依赖, 静态库, 动态库, Lycium
欢迎大家加入鸿蒙pc开发者社区
更多推荐

所有评论(0)