鸿蒙三方库适配读懂 HPKBUILD:lycium 怎么知道「下载谁、怎么编、装到哪」?
前言
在 OpenHarmony 三方库 lycium 体系里,每个库目录下会有一个 HPKBUILD 文件。你可以把它理解成 「构建说明书」 :用 Shell 变量 描述 包是谁、版本多少、从哪下载 ,再用若干个 函数 描述 解压后要改什么、怎么交叉编译、产物拷贝到哪、要不要打 HNP 包。
本文件由 lycium/script/build_hpk.sh 通过 source HPKBUILD 读入并调用其中的函数;你在 lycium 根目录 执行 ./build.sh AES 时,脚本会进入 thirdparty/AES (或你工程里对应路径),在该目录下 source 本 HPKBUILD 并执行 build_hpk.sh 里的主流程。
本文在 变量(字段) 、各函数职责 之外,补充:脚本真实调用顺序 、传入 build() 的 CMake 参数从哪来 、常见目录长什么样 、排错与升级时要改哪些地方 ,方便对照仓库里的 HPKBUILD 原文 阅读。
工作目录与路径约定(读脚本前先建立空间感)
| 概念 | 本仓库典型值 | 说明 |
|---|---|---|
库根目录(PKGBUILD_ROOT) |
.../thirdparty/AES |
build_hpk.sh 所在目录;PWD 在执行 prepare/build/package 的多数时刻会 cd 到 builddir 再返回,但 archive() 里复制 hnp.json 用的是 ${PWD}/hnp.json ,要求 在库根执行(与 lycium 设计一致)。 |
LYCIUM_ROOT |
.../lycium |
lycium/build.sh 里导出;安装产物 在 $LYCIUM_ROOT/usr/AES/<ARCH>/ ,archive 输出 在 $LYCIUM_ROOT/output/<ARCH>/。 |
builddir |
tiny-AES-c-1.0.0 |
与 packagename 解压结果一致,位于 库根下 (与 HPKBUILD 同级)。 |
| CMake 构建目录 | tiny-AES-c-1.0.0/arm64-v8a-build |
-B"$ARCH-build" 相对 源码根 ;HPKCHECK 必须 cd "${builddir}/${ARCH}-build",与此严格一致。 |
引号习惯: builddir 含连字符 ,凡 cd、rm -rf、路径拼接 建议写 "$builddir" 、"${PWD}/$builddir",避免被 shell 拆成多个词(社区 HPK 规范里这是常见坑)。
上半部分:变量(字段)一览
下面这些不是 JSON 字段,而是 Bash 变量 ,供 build_hpk.sh 使用。
| 变量名 | 本仓库取值 | 通俗含义 |
|---|---|---|
pkgname |
AES |
包 / 库在 lycium 里的名字 ,必须与 thirdparty/ 下文件夹名 一致,否则 ./build.sh AES 找不到。同时决定安装根路径 $LYCIUM_ROOT/usr/AES/。 |
pkgver |
1.0.0 |
上游源码版本号 ,与 tag v1.0.0 、builddir、packagename、hnp.json 的 version 等应对齐。 |
pkgrel |
0 |
适配脚本发布号(第几次打 HPK 包),与上游版本独立;只改适配脚本未改上游时,通常会递增它。 |
pkgdesc |
英文短描述 | 一句话说明这个包是干什么的,给人读和维护用。 |
url |
GitHub 上游地址 | 上游主页,溯源、文档链接用。 |
archs |
armeabi-v7a、arm64-v8a |
要编哪些 CPU 架构 ;数组里 每个架构 都会完整跑一遍 prepare → build → package → archive(若有)→ check(若开启)。 |
license |
Unlicense |
上游许可证 (tiny-AES-c);本仓库另有 MIT 的适配文件,见 LICENSE / README.OpenSource。 |
depends |
空数组 | 运行时依赖的其他 HPK 包名 (目录名)。本库无。若有依赖,./build.sh A B 里 要先写被依赖的 B ,否则 A 会因 builddepends 返回 101 而推迟构建。 |
makedepends |
空数组 | 本机构建前要用到的可执行命令名 (如 python3);脚本会对每个元素 which,找不到就退出。本库依赖 cmake/make 由 lycium 全局检查,此处可空。 |
source |
codeload 的 tar.gz URL | 源码下载地址 ;用 ${pkgver} 拼出版本。codeload.github.com 在 macOS wget 下往往比 github.com/.../archive/refs/tags/... 更稳。 |
downloadpackage |
true |
是否自动下载 packagename ;设为 false 时需自行把源码放到约定位置并在 prepare 里处理。 |
autounpack |
true |
是否自动解压 ;false 时在 prepare 里自己 tar/unzip。 |
buildtools |
cmake |
构建方式 。为 cmake (或空,默认 cmake)时,build_hpk.sh 在 build 前 调用 cmakedependpath $ARCH ,拼出传给 build "$@" 的 buildargs。 |
builddir |
tiny-AES-c-${pkgver} |
解压后的源码根目录名 ;含连字符 ,cd 务必加引号。 |
packagename |
${builddir}.tar.gz |
磁盘上的源码压缩包文件名 ;wget -O 的目标名,且应与 SHA512SUM 第二列一致。 |
第一行注释 # Maintainer: ... 仅说明维护关系,不参与逻辑。
SHA512SUM 与下载:和 HPKBUILD 怎么配合?
build_hpk.sh 在 download $source $packagename 之后:若库目录下存在 SHA512SUM 文件,会执行 sha512sum -c SHA512SUM。
- 作用 :防止下载损坏或被劫持的 tarball,与
sourceURL 变更后内容是否仍一致。 - 你要做的 :更换
pkgver/source/packagename后,用新包算一遍 SHA512 ,更新SHA512SUM里对应行。 - 校验失败 :脚本会提示失败并退出,不会自动删包,方便你比对后决定是重下还是修正哈希。
下载日志在库根 download.log (wget 的 -o 输出),体积异常或 404 时可打开查看。
build_hpk.sh 里真实发生的事(按时间顺序)
下面与 lycium/script/build_hpk.sh 中 main → cleanhpk → builpackage 逻辑对应,便于你把 变量 和 函数 对上号。
否 exit 101
是
是
否
是
否
是
否
cleanhpk: cleanbuild + 可选删坏包
builpackage: builddepends 检查 depends
依赖齐全?
写入待编译依赖列表
download source -> packagename
存在 SHA512SUM?
sha512sum -c
unpack packagename
for arch in archs
ARCH=arch 设置 buildlog
prepare
cmakedependpath 拼 buildargs
build buildargs
package
定义了 archive?
archive
跳过
LYCIUM_BUILD_CHECK=true?
check
跳过 check
recordbuildlibs
要点摘要:
cleanbuild()会先删掉$builddir和$packagename,保证本次是干净树(若你本地想保留已下载的 tar,需知每次 full build 会清掉,与 lycium 一致)。depends:在builpackage入口 用builddepends与「已编译列表」比对;缺依赖时 exit 101 ,不会进入prepare。prepare在每个arch循环里都执行一次 :本库prepare幂等 (整文件覆盖CMakeLists.txt),重复执行不会叠加坏内容;若某库用cat >>追加 CMake,则要自己grep -q做幂等(别的库的坑,此处顺带提醒)。build $buildargs:这里的$buildargs来自cmakedependpath,不是HPKBUILD里手写的 ;HPKBUILD的build()里用"$@"接住。declare -F archive:只有HPKBUILD里定义了archive函数 才会调用;本仓库 有。check:仅当LYCIUM_BUILD_CHECK为true时执行;在 Darwin 上lycium/build.sh常把LYCIUM_BUILD_CHECK设为false,则 不会跑check(),这是环境行为,不是HPKBUILD写错。recordbuildlibs:往$LYCIUM_ROOT/usr/hpk_build.csv记一笔,供依赖解析与跳过已构建使用。
传给 build() 的 CMake 参数(cmakedependpath 摘要)
buildtools="cmake" 时,cmakedependpath $ARCH 会构造 buildargs,核心包括(具体以你 SDK 路径为准):
| 片段 | 作用 |
|---|---|
-DCMAKE_TOOLCHAIN_FILE=${OHOS_SDK}/native/build/cmake/ohos.toolchain.cmake |
指定 OHOS 交叉编译工具链。 |
-DCMAKE_INSTALL_PREFIX=$LYCIUM_ROOT/usr/$pkgname/$ARCH/ |
CMake 语义上的安装前缀;本库 package() 仍 手动 cp ,与此前缀 对齐同一套目录结构。 |
-G "Unix Makefiles" |
生成 Makefile ,后续 $MAKE -C $ARCH-build。 |
-DOHOS_ARCH=$ARCH |
目标架构,与 armeabi-v7a / arm64-v8a 对应。 |
-DCMAKE_BUILD_TYPE=Release 等 |
Release、跳过 RPATH 等,减少设备上多余依赖。 |
本库 depends=() ,因此 不会 追加 -DCMAKE_FIND_ROOT_PATH=... (有依赖时才会把其它库的 usr/<dep>/$ARCH 拼进搜索路径)。
build() 里 又额外传入 -B"$ARCH-build" -S. ,与 buildargs 合并后交给 ${OHOS_SDK}/native/build-tools/cmake/bin/cmake ,并把 stdout/stderr 追加到 buildlog。
关键函数是干什么的?
prepare():解压后、编译前的「准备工作」
什么时候调? archs 循环里,每个 ARCH 在 build() 之前都会执行(见上一节流程图)。
本库做了两件事:
-
统一换行符
对
aes.c、aes.h、test.c做sed 's/\r$//',去掉可能的 Windows CRLF 。在 HPK 实践里,CRLF 会导致source HPKBUILD报错 、prepare里 heredoc 异常 或 编译器解析奇怪,属于高频坑。 -
重写
CMakeLists.txt(cat <<'EOF')- 上游 v1.0.0 自带 CMake 将
target_include_directories指到不存在的tiny-AES-c/子目录,交叉编译会 找不到aes.h。 - 本适配直接写入完整 CMake,实现:静态库
tiny-aes(libtiny-aes.a) 、tiny_aes_test、CTest 用例名tiny_aes_upstream_tests、以及与标准布局一致的install(...)(与package()手动拷贝 语义对齐)。
- 上游 v1.0.0 自带 CMake 将
为何用单引号 heredoc <<'EOF'? 防止 shell 提前展开 ${CMAKE_CURRENT_SOURCE_DIR} 等,应原样交给 CMake。
最后 cd "$OLDPWD" 回到进入 prepare 前的目录(库根)。
build():用 OHOS 工具链跑 CMake + Make
cd "$builddir"。cmake ... "$@" -B"$ARCH-build" -S. >> "$buildlog" 2>&1。- 失败则
return;成功则$MAKE -C "$ARCH-build",同样追加到buildlog。 cd "$OLDPWD",返回 make 退出码。
buildlog 文件名 形如 AES-1.0.0-arm64-v8a-lycium_build.log ,在 库根 ;cmake 详细报错、未找到编译器、链接失败等 优先打开此文件。
package():把编好的东西摆到 lycium 标准「安装树」
在 $builddir 下执行:
| 目标路径 | 内容 |
|---|---|
$LYCIUM_ROOT/usr/AES/$ARCH/lib/ |
libtiny-aes.a |
.../include/ |
aes.h |
.../bin/ |
tiny_aes_test(若生成) |
应用链接:-I$LYCIUM_ROOT/usr/AES/$ARCH/include -L.../lib -ltiny-aes (静态库目标名为 tiny-aes ,产物文件 libtiny-aes.a)。
archive():打发布包 + 可选 HNP
mkdir -p "${LYCIUM_ROOT}/output/$ARCH"。cp "${PWD}/hnp.json"→usr/AES/$ARCH/(与lib同级)。- 在
usr/AES/$ARCH内tar -zvcf .../${pkgname}_${pkgver}.tar.gz *,即AES_1.0.0.tar.gz,落在lycium/output/$ARCH/。 hnpcli pack:若可执行则调用;否则 写buildlog,不使整次构建失败。
注意: output 路径相对 LYCIUM_ROOT(lycium 根) ;若你在 独立 git 仓库 thirdparty/AES 里另外维护 output/ 拷贝,属于 发布策略 ,与 lycium 默认 lycium/output 不是同一路径,文档里不要混为一谈。
check():仅提示,不跑测试
打印说明:交叉编译出的测试二进制不能在宿主机上跑 ;设备上 ctest / ./tiny_aes_test 。
HPKCHECK + test.sh 才是设备侧自动化入口。
cleanbuild():清理,方便下次干净构建
rm -rf "${PWD}/$builddir" 、rm -f "${PWD}/$packagename" 。
cleanhpk 还会在校验失败时 删掉坏的 packagename (见 build_hpk.sh ),与 cleanbuild 略有叠加,都是为 可重复构建 服务。
上游 CMake 与本适配的差异(一眼对照)
| 项目 | 上游 tiny-AES-c v1.0.0(节选问题) | 本 prepare() 写入的 CMake |
|---|---|---|
| include 路径 | PRIVATE tiny-AES-c/(解压后不存在) |
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} |
| 库类型 / 测试 | 仅 add_library,无测试目标 |
STATIC + tiny_aes_test + CTest |
| 安装 | 无完整 install 语义 | install(TARGETS/FILES ...) 与 package() 对齐 |
构建成功后,目录「长什么样」(示意)
库根 thirdparty/AES(节选):
text
thirdparty/AES/
├── HPKBUILD
├── SHA512SUM
├── tiny-AES-c-1.0.0.tar.gz # cleanbuild 后可能不存在,需重新下载
├── tiny-AES-c-1.0.0/
│ ├── aes.c, aes.h, test.c
│ ├── CMakeLists.txt # 已被 prepare 覆盖
│ ├── arm64-v8a-build/ # cmake + make 产物
│ │ ├── libtiny-aes.a
│ │ ├── tiny_aes_test
│ │ └── ...
│ └── armeabi-v7a-build/
└── AES-1.0.0-arm64-v8a-lycium_build.log
lycium 安装树(节选):
text
lycium/usr/AES/arm64-v8a/
├── bin/tiny_aes_test
├── include/aes.h
├── lib/libtiny-aes.a
└── hnp.json # archive 前复制进来
排错速查(和 HPKBUILD 强相关)
| 现象 | 建议排查 |
|---|---|
ERROR during : download |
download.log 、网络、URL;可改 source 为 codeload(本库已用)。 |
SHA512SUM 校验失败 |
下载包是否更新、SHA512SUM 是否与新包一致。 |
| cmake 报找不到编译器 / sysroot | OHOS_SDK 是否设置、SDK 是否完整。 |
prepare / source HPKBUILD 奇怪语法错误 |
CRLF :对 HPKBUILD 本身 也应用 LF(本技能常见要求)。 |
pack: command not found(旧问题) |
archive 里应对 hnpcli 做 -x 判断(本仓库已处理)。 |
设备上 ctest 找不到目录 |
HPKCHECK 必须 cd "${builddir}/${ARCH}-build" ,与 -B"$ARCH-build" 一致。 |
库根 last_error 文件在 sure 失败时由 build_hpk.sh 写入一行错误信息,可与 buildlog 对照。
升级上游或改架构时:建议核对清单
-
pkgver、source中的版本片段、builddir、packagename一致。 -
SHA512SUM已用新 tarball 更新。 -
hnp.json的version、README.OpenSource的 Version Number、文档中的版本号。 -
archs增删后,HPKCHECK的cd仍指向${builddir}/${ARCH}-build(若你改成嵌套$builddir/ohos_build/${ARCH}-build等,两边必须一起改)。 - 上游
test.c/aes.c文件名变更 时,prepare里 CRLF 列表 与 CMakeadd_library源文件 同步。
内嵌的 CMake 片段(在 prepare 里)在说什么?
add_library(tiny-aes STATIC aes.c):单文件静态库。target_include_directories(... PUBLIC ...):对外暴露头文件路径,修正上游错误。tiny_aes_test:链接tiny-aes,跑上游自测。enable_testing+add_test:注册 CTest ,与HPKCHECK中ctest对应。install(...):与package()的lib/include/bin布局一致,便于以后若改为cmake --install时少改脚本。
总结
HPKBUILD= 变量(谁、版本、从哪下、编哪些架构、依赖谁) + 函数(准备、编译、安装、打包、提示、清理) ;真正 下载/校验/多架构循环 在build_hpk.sh里,HPKBUILD只声明「做什么」。build()的"$@"来自cmakedependpath,核心是指定 OHOS toolchain、安装前缀、OHOS_ARCH;本库 无depends,故无CMAKE_FIND_ROOT_PATH拼接。prepare解决 CRLF + 上游 CMake 路径错误 ,并打通 CTest ;package把产物落到usr/AES/$ARCH;archive做 tar + 可选 HNP。- 排错优先看 库根
*-lycium_build.log、download.log、last_error;升级时 版本号与SHA512SUM、hnp.json、OpenSource 一并改。
更偏「流程叙述」的图文可继续阅读仓库内 鸿蒙PC tiny-AES-c三方库适配实践.md。