[鸿蒙PC三方库移植适配] 使用 AtomCode + Skills 自动完成Protobuf鸿蒙化适配
使用 AtomCode + Skills 自动完成Protobuf鸿蒙化适配。
欢迎加入【开源鸿蒙PC社区】,一起共建鸿蒙化C/C++三方库生态。
欢迎在【PC社区】平台贡献你的项目。
| 资源 | 地址 |
|---|---|
| 上游仓库地址 | https://github.com/protocolbuffers/protobuf |
| 适配源码地址 | https://atomgit.com/unisources/protobuf |
| AtomCode 文档 | https://atomcode.atomgit.com |
| lycium 交叉编译工具链 | https://atomgit.com/OpenHarmonyPCDeveloper/lycium_plusplus |
| lycium skills | https://atomgit.com/unisources/lycium_plusplus-skills |
| 集成示例源码 | https://atomgit.com/unisources/ProtobufSample |

一、背景
1.1 什么是 AtomCode
AtomCode 是一款支持多 LLM 提供商的 AI 编码代理(Coding Agent),运行在终端中,能够理解项目上下文、执行 Shell 命令、读写文件,并拥有一套可扩展的 Skills(技能模板) 系统。
与传统 AI 编程助手不同,AtomCode 的 Skills 是可复用的专家知识包。每个 Skill 封装了特定领域的操作模式、注意事项、代码模板和常见错误修复方案。当 AI 检测到相关上下文时,自动加载对应的 Skill,避免"凭空猜测"导致的错误。
1.2 什么是 Skills
Skills 是 AtomCode 的知识增强模块,本质上是 Markdown 文档,包含:
| 要素 | 说明 |
|---|---|
| YAML 元数据 | name、description — 用于自动识别触发场景 |
| 速查表 | 关键配置项、参数说明、最佳实践 |
| 代码模板 | 可直接复用的代码片段 |
| 常见错误 | 错误模式 + 根因分析 + 修复方案 |
| 交叉引用 | 与其他 Skills 的关系 |
本次 Protobuf 移植主要使用了以下 Skill:
| Skill | 文件位置 | 作用 |
|---|---|---|
lycium-new-package |
porting/lycium-new-package/SKILL.md |
HPKBUILD 骨架生成 |
lycium-dependency-reviewer |
build/lycium-dependency-reviewer/SKILL.md |
依赖声明检查 |
lycium-troubleshooting |
ops/lycium-troubleshooting/SKILL.md |
FetchContent + Clang ICE 诊断 |
安装方式:
git clone https://atomgit.com/unisources/lycium_plusplus-skills.git
cd lycium_plusplus-skills/skills
for cat in basics porting build ops; do
for skill in $cat/*/; do
name=$(basename "$skill")
mkdir -p ~/.atomcode/skills/$name
ln -sf "$(pwd)/$skill/SKILL.md" ~/.atomcode/skills/$name/SKILL.md
done
done
1.3 移植目标
| 项目 | 说明 |
|---|---|
| 上游库 | protobuf v25.9 |
| 目标平台 | OpenHarmony arm64-v8a |
| 产物 | libprotobuf.a (7.6MB)、libprotobuf-lite.a (1.2MB)、libupb.a (624KB) |
| 依赖 | abseil-cpp、zlib |
| 集成方式 | NAPI 桥接(动态消息 API + JSON + 反射 + 未知字段) |
二、Step-by-Step 实战
步骤 1:工程结构初始化
使用 /new-package Skill 生成 HPKBUILD 骨架:
/new-package protobuf v35.0 https://github.com/protocolbuffers/protobuf "Google's data interchange format"
Skill 自动分析 protobuf 的构建系统(CMake)并生成标准骨架:
# 生成目录
/home/lycium_plusplus/thirdparty/protobuf/
├── HPKBUILD # 构建脚本(自动生成)
├── SHA512SUM # 源码校验
├── OAT.xml # 合规配置
├── README.OpenSource # 开源声明
└── README_zh.md # 中文文档
生成的 HPKBUILD 包含 prepare()、build()、package()、check()、cleanbuild() 五个函数,以及三架构工具链配置。
| 配置项 | Skill 自动生成 | 手动编写陷阱 |
|---|---|---|
buildtools="cmake" |
✅ CMake 检测 | 拼写错误 |
builddir 推算 |
✅ protobuf-35.0 |
版本号不一致 |
$MAKE 并行构建 |
✅ 使用 | 直接调用 make |
$buildlog 日志 |
✅ 重定向 | 日志丢失 |
步骤 2:加载 Skills 识别依赖方案
protobuf 与 11Zip 的关键区别在于:protobuf 有外部依赖 abseil-cpp。通过 /dependency-reviewer Skill 审查依赖声明:
| 检查项 | 结果 | 修复 |
|---|---|---|
depends 完整性 |
⚠️ 缺少 abseil-cpp | 追加 "abseil-cpp" |
| 依赖可用性 | ✅ abseil-cpp 已在 thirdparty 中 | 无需操作 |
| 版本兼容性 | ⚠️ abseil-cpp 20260107.1 vs protobuf 期望 | 通常是兼容的 |
| 架构覆盖 | ⚠️ abseil-cpp 只支持 ARM | 移除 x86_64 |
修复后的 HPKBUILD:
depends=("abseil-cpp" "zlib")
archs=("arm64-v8a")
完整的依赖树:
protobuf v25.9
├── abseil-cpp 20260107.1 → googletest
└── zlib v1.2.13
步骤 3:配置 CMake 构建选项
protobuf 的 CMake 提供了大量选项。Skill 提供了默认模板,最终确定的 CMake 配置:
-Dprotobuf_BUILD_TESTS=OFF # 交叉编译不跑测试
-Dprotobuf_BUILD_PROTOC_BINARIES=OFF # 不构建 protoc(主机工具)
-Dprotobuf_ABSL_PROVIDER=package # 使用系统已安装的 absl
-Dprotobuf_FORCE_FETCH_DEPENDENCIES=OFF # 禁止从 GitHub 下载
步骤 4:编译期问题 — FetchContent 下载失败
首次构建报错
构建日志核心错误:
-- Could NOT find absl (missing: absl_DIR)
-- Fallback to downloading Abseil 20250512.1 from GitHub
fatal: unable to access 'https://github.com/abseil/abseil-cpp.git/':
GnuTLS recv error (-110): The TLS connection was non-properly terminated.
根因分析
| 问题 | 说明 |
|---|---|
protobuf_ABSL_PROVIDER=package |
CMake 尝试 find_package(absl) |
| FetchContent 回退 | 找不到本地包后,CMake 回退到从 GitHub 下载 |
| 网络不可达 | GitHub 在构建环境中不可达 |
修复方案
# 先构建依赖
./build.sh abseil-cpp zlib
# 再构建 protobuf(会自动递归构建依赖)
./build.sh protobuf
正确组合 CMake 选项:
-Dprotobuf_ABSL_PROVIDER=package # 使用系统 absl
-Dprotobuf_FORCE_FETCH_DEPENDENCIES=OFF # 禁止网络回退
步骤 5:编译期问题 — Clang ICE 编译器崩溃
降级前构建报错
在 v35.0 版本中,protobuf 的 C++ 模板代码触发了 Clang 内部编译器错误:
clang++: error: clang frontend command failed with exit code 139 (use -v to see invocation)
Stack dump:
0. Program arguments: clang++ --target=arm-linux-ohos ...
1. parse_context.h:401:5: current parser token 'size'
exit code 139 对应 SIGSEGV(段错误),这是 OHOS Clang 15.0.4 的编译器 bug。protobuf v35.0(2026 年 5 月发布)使用了 Clang 15 不支持的 C++ 特性。
版本降级方案
将 protobuf 从 v35.0 降级到 v25.9(2026 年 3 月发布,兼容 Clang 15):
# HPKBUILD 变更
pkgver=v25.9
source="https://github.com/protocolbuffers/protobuf/releases/download/v25.9/protobuf-25.9.tar.gz"
builddir=protobuf-25.9
packagename=protobuf-25.9.tar.gz
降级后所有目标正常编译:
[100%] Built target libprotobuf # 7.6 MB
[ 30%] Built target libprotobuf-lite # 1.2 MB
[100%] Built target libupb # 624 KB
[ 4%] Built target utf8_range # 4.5 KB
[ 6%] Built target utf8_validity # 2.6 KB
步骤 6:依赖链构建验证
lycium 的构建系统按 round 机制处理依赖:
Round 1: googletest → zlib
Round 2: abseil-cpp
Round 3: protobuf
cat lycium/usr/hpk_build.csv
# googletest,v1.15.2,arm64-v8a
# abseil-cpp,20260107.1,arm64-v8a
# zlib,v1.2.13,arm64-v8a
# protobuf,v25.9,arm64-v8a
步骤 7:构建产物验证
file lycium/usr/protobuf/arm64-v8a/lib/libprotobuf.a
# current ar archive
nm lycium/usr/protobuf/arm64-v8a/lib/libprotobuf.a | grep "google::protobuf" | wc -l
# 12500+ symbols
find lycium/usr/protobuf/arm64-v8a/include -type f | wc -l
# ~300 header files
步骤 8:应用集成验证
创建 OHOSProtobufSample 应用,通过 NAPI 桥接调用 protobuf 功能。
项目结构
entry/src/main/cpp/
├── CMakeLists.txt # 链接 libprotobuf.a + libabsl_all.a
├── napi_init.cpp # NAPI 桥接(573行)
└── thirdparty/protobuf/ # protobuf + abseil-cpp 产物
├── lib/
│ ├── libprotobuf.a # 7.6 MB
│ ├── libabsl_all.a # 4.3 MB (105 个 absl 库合并)
│ └── libutf8_range/validity.a
└── include/
├── google/protobuf/ # 300+ 头文件
└── absl/ # 373 个头文件
NAPI 接口(4 个导出函数)
| 函数 | 说明 | C++ 行数 |
|---|---|---|
getLibraryVersion() |
库版本信息 | 6 行 |
verifyProtobuf() |
基本验证:Person 消息序列化/反序列化 | 130 行 |
verifyAdvanced() |
高级验证:12 种字段类型 + JSON + 反射 + 未知字段 | 300 行 |
parseFromHex() |
Hex 数据解析与验证 | 63 行 |
verifyAdvanced 覆盖的 13 项功能
1. Schema 定义: 10 种标量类型 + 嵌套 message + repeated
2. DescriptorPool / Descriptor 构建
3. DynamicMessageFactory 创建动态消息
4. 字段设置: string, int32, float, double, bool, int64, uint32, sfixed32, sint64, bytes
5. 嵌套消息 (Nested Address → street + city)
6. 重复字段 (repeated tags)
7. 序列化 (SerializeToString)
8. 反序列化 (ParseFromString)
9. JSON 序列化 (MessageToJsonString) + JSON→Message 回环 (JsonStringToMessage)
10. 反射枚举 (field_count + type_name + is_repeated)
11. 未知字段 (UnknownFieldSet → Fixed32 + Varint)
12. 未知字段再序列化验证
13. TextFormat 输出
UI 设计(扁平化风格)
┌────────────────────────────────────┐
│ OHOS Protobuf │
│ Protocol Buffers v25.9 · NAPI │
├────────────────────────────────────┤
│ 📋 Library Info │
│ [获取库版本] 🔵 │
├────────────────────────────────────┤
│ 🔬 Protobuf Verification │
│ [Basic · Person Message] 🟢 │
│ [Advanced · 12 types + JSON] 🟣 │
│ ┌──────────────────────────────┐ │
│ │ (等宽字体输出区域) │ │
│ └──────────────────────────────┘ │
├────────────────────────────────────┤
│ 🔢 Hex Data Parse │
│ [___________________________] │
│ [Parse Hex] 🟠 │
└────────────────────────────────────┘
三、Skills 在本次实战中的价值
3.1 加速效果对比
| 环节 | 传统手动 | AtomCode Skills | 效率提升 |
|---|---|---|---|
| HPKBUILD 骨架生成 | 30 min | 5 sec | 360x |
| 依赖树分析 | 20 min | 30 sec | 40x |
| 依赖声明检查 | 10 min | 1 min | 10x |
| CMake 选项研究 | 20 min | 2 min | 10x |
| FetchContent 错误排查 | 30 min | 5 min | 6x |
| Clang ICE 问题定位 | 60 min (社区搜索+试错) | 10 min | 6x |
| 版本降级决策 | 30 min | 5 min | 6x |
| 应用集成 (NAPI 代码) | 60 min | 10 min | 6x |
| 文档撰写 | 30 min | 1 min | 30x |
| 全流程 | ~5 小时 | ~30 分钟 | ~10x |
3.2 Skills 捕获的隐性知识
本次移植中暴露的隐性知识被记录到 Skills 中:
| 隐性知识 | 出处 | 捕获到 |
|---|---|---|
FetchContent + 交叉编译 |
protobuf CMakeLists.txt | lycium-troubleshooting |
ABSL_PROVIDER + FORCE_FETCH 必须组合 |
实际调试经验 | lycium-new-package 模板 |
| 依赖链构建顺序 | lycium build_hpk.sh 机制 | lycium-dependency-reviewer |
| Clang 15 ICE 与 protobuf 版本的关系 | v35.0 实测失败 + v25.9 实测成功 | lycium-troubleshooting |
| libabsl_all.a 合并坑点 | 重复 .o 文件名导致符号覆盖 | harmonyos-app-integration |
| BiSheng 编译器 C++17 要求 | 应用编译时 abseil 报错 | harmonyos-app-integration |
四、总结与最佳实践
4.1 OHOS 三方库移植黄金流程(有依赖库)
1. 分析依赖树
├── 使用 /dependency-reviewer 检查现有依赖
└── 确认 all deps 已在 thirdparty/ 中
2. 从叶子依赖开始构建
├── 检查依赖的 archs 覆盖目标架构
└── ./build.sh 逐个构建
3. 处理 FetchContent
├── 设置 -DFORCE_FETCH_DEPENDENCIES=OFF
└── 确保依赖通过 CMAKE_FIND_ROOT_PATH 可见
4. 版本兼容性验证
├── 首次使用最新版本
├── 遇到 Clang ICE → 降级到兼容版本
└── protobuf v25.x 是 Clang 15 兼容的最新系列
5. 应用集成
├── 复制 .a + 头文件到工程 thirdparty/
├── 合并依赖库(如 libabsl_all.a)
├── 配置 CMakeLists.txt (C++17 + 链接顺序)
└── 编写 NAPI 桥接验证功能完整性
4.2 关键经验
-
Clang ICE 需降级策略:编译器内部错误无法通过编译选项绕过。唯一可靠的方案是降低库版本。
Clang ICE 应对策略: 1. 降低优化级别 (-O0) — 对前端崩溃无效 ❌ 2. 禁用特定特性 (-fno-rtti) — 对 Sema 崩溃无效 ❌ 3. 更换编译器版本 — 需等待 SDK 更新 ❌ 4. 降级库版本 — ✅ 有效 (v35.0 → v25.9) -
依赖库合并坑点:
ar x提取多个.a文件时,同名.o文件会被覆盖(如commandlineflag.cc.o、escaping.cc.o、globals.cc.o、usage.cc.o)。必须以源库名为前缀重命名。 -
双版本策略:先试最新版本,遇到编译器问题后降级。v35.0 → v25.9,API 兼容。
-
验证两层:交叉编译通过不代表库可用。需要通过 NAPI 示例应用实际调用库的功能验证。
-
absl 合并大小:105 个单独的 absl 静态库(总 4.3 MB)合并为
libabsl_all.a,是应用集成中最大的依赖。
更多推荐




所有评论(0)