HPKCHECK 深度解读:编译通过只是第一步,测试通过才是成功
前言
在 OpenHarmony 三方库适配中,HPKBUILD 负责把源码编译成产物,HPKCHECK 负责验证产物是否真的能用。
你可能会想:编译没报错不就行了?问题是,交叉编译出的 ARM 可执行文件无法在 x86 开发机上运行,你根本不知道它编译出来能不能正常工作。HPKCHECK 就是把测试程序推到真实 OpenHarmony 设备上执行,确保功能正确。
这篇文章把 HPKCHECK 的结构、执行流程、编写方法讲清楚。
HPKCHECK 文件内容
SHA 库的 HPKCHECK 内容如下:
# Copyright (c) 2023 Huawei Device Co., Ltd.# Licensed under the Apache License, Version 2.0 (the "License");# ...# Contributor: huangminzhong <huangminzhong2@huawei.com># Maintainer: huangminzhong <huangminzhong2@huawei.com>source HPKBUILD > /dev/null 2>&1logfile=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${pkgname}_${ARCH}_${OHOS_SDK_VER}_test.logopenharmonycheck() {cd$builddir/$ARCH-build ctest > ${logfile} 2>&1 res=$?cd$OLDPWDreturn$res}
只有三个有效部分,下面逐个拆解。
逐部分解读
1. source HPKBUILD — 加载构建配置
source HPKBUILD > /dev/null 2>&1
通俗理解:把 HPKBUILD 里的变量和函数"搬"过来,这样 HPKCHECK 就能知道包名、构建目录等信息。
source:在当前 Shell 环境中执行文件(不是启动子进程)> /dev/null 2>&1:静默执行,不输出 HPKBUILD 的内容
加载后可用的关键变量:
| | |
|---|
pkgname | | sha |
builddir | | sha-3ee0d88... |
ARCH | | arm64-v8a |
2. logfile — 测试日志路径
logfile=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${pkgname}_${ARCH}_${OHOS_SDK_VER}_test.log
通俗理解:定义测试日志文件的位置和名称。
展开后类似:thirdparty/sha/sha_arm64-v8a_10_test.log
日志文件名包含三个关键信息:
这样不同配置的测试结果不会混在一起。
3. openharmonycheck() — 核心测试函数
openharmonycheck() {cd$builddir/$ARCH-build ctest > ${logfile} 2>&1 res=$?cd$OLDPWDreturn$res}
通俗理解:进入构建目录,运行 CTest,记录结果,返回原目录。
| | |
|---|
| cd $builddir/$ARCH-build | |
| ctest > ${logfile} 2>&1 | |
| res=$? | |
| cd $OLDPWD | |
| return $res | |
CTest 会执行什么? 由 CMakeLists.txt 中的 add_test() 定义:
enable_testing()add_test(NAME test_hmac COMMAND hmac)add_test(NAME test_pwd2key COMMAND pwd2key)add_test(NAME test_sha COMMAND sha_test)
三个测试用例分别验证 HMAC、密钥派生和 SHA 算法的正确性。
为什么需要单独的 HPKCHECK?
HPKBUILD 中的 check() 为什么不够?
HPKBUILD 里确实有个 check() 函数:
check() {echo"The test must be on an OpenHarmony device!"# ctest}
但 ctest 被注释掉了,因为交叉编译环境无法运行测试:
HPKCHECK 的设计就是为了在真实设备上执行测试,而不是在开发机上。
完整的测试生命周期
开发机上: HPKBUILD prepare() → build() → package() → archive() (编译完成,但无法运行测试)OpenHarmony 设备上: HPKCHECK openharmonycheck() (部署产物,运行测试,收集结果)
执行流程详解
HPKCHECK 通过 test.sh 脚本触发执行:
cd lycium && ./test.sh sha
完整执行流程
./test.sh sha │ ├─ 1. 设置环境变量(LYCIUM_ROOT、LYCIUM_THIRDPARTY_ROOT、OHOS_SDK_VER) │ ├─ 2. checktestenv():检查 cmake/make/ctest/perl 是否存在 │ ├─ 3. getcpuarchitecture():检测 CPU 架构(arm64-v8a 或 armeabi-v7a) │ ├─ 4. setloaddynamiclibrarypath():设置 LD_LIBRARY_PATH │ ├─ 5. 查找 sha 库目录 │ └─ 6. checkhpk():遍历测试 │ ├─ 进入 thirdparty/sha/ ├─ source ./HPKCHECK │ ├─ source HPKBUILD(加载变量) │ ├─ 设置 logfile │ └─ 定义 openharmonycheck() │ ├─ 检查是否有 checkprepare()(可选的测试前准备) │ ├─ 调用 openharmonycheck() │ ├─ cd$builddir/$ARCH-build │ ├─ ctest > ${logfile} 2>&1 │ ├─ res=$? │ └─ cd$OLDPWD │ ├─ 判断结果:成功 → successlibs / 失败 → failedlibs │ └─ 收集日志到 LOG_PATH
执行前提条件
- 已编译:先在开发机上执行
./build.sh sha - 已部署:将编译产物推送到 OpenHarmony 设备
- 工具就绪:设备上有 cmake、make、ctest、perl(可通过 CItools 部署)
规范写法与模板
标准 HPKCHECK 模板
# Copyright (c) 2023 Huawei Device Co., Ltd.# Licensed under the Apache License, Version 2.0 (the "License");# ...source HPKBUILD > /dev/null 2>&1logfile=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${pkgname}_${ARCH}_${OHOS_SDK_VER}_test.log# 可选:测试前的准备工作checkprepare() {return 0}# 必需:在 OpenHarmony 设备上执行测试openharmonycheck() {cd$builddir/$ARCH-build ctest > ${logfile} 2>&1 res=$?cd$OLDPWDreturn$res}
不同测试框架的写法
| | |
|---|
| ctest > ${logfile} 2>&1 | |
| make test > ${logfile} 2>&1 | |
| ./run_tests.sh > ${logfile} 2>&1 | |
常见问题
Q1:测试必须在 OpenHarmony 设备上运行吗?
是的。 交叉编译出的 ARM 可执行文件无法在 x86 开发机上运行。如果开发机也是 ARM 架构的鸿蒙 PC,则可以直接运行。
Q2:如何部署测试工具到设备?
cd lycium/CItools && ./env_build.sh
这会把 cmake、make、ctest 等工具部署到 OpenHarmony 设备上。
Q3:测试失败如何调试?
Q4:如果三方库没有测试用例怎么办?
- 在
HPKCHECK 中跳过测试,但要在文档中说明原因
Q5:checkprepare() 什么时候需要?
当测试前需要做额外准备时,比如:
对于 SHA 这种简单库,不需要 checkprepare()。
与其他文件的关系
HPKCHECK │ ├─ source HPKBUILD ← 加载构建变量 │ ├─ ctest ← 执行 CMakeLists.txt 中定义的测试 │ └─ test.sh ← 被 test.sh 调用
总结
HPKCHECK 是 OpenHarmony 三方库质量把关的关键文件:
| |
|---|
source HPKBUILD | |
logfile=... | |
openharmonycheck() | |
核心要点:
HPKCHECK 必须在 OpenHarmony 设备上执行,因为交叉编译的产物无法在开发机运行openharmonycheck() 是必须定义的函数,由 test.sh 调用checkprepare() 是可选的测试前准备函数- 测试结果通过返回码传递:0 表示成功,非 0 表示失败
编译通过只是第一步,测试通过才是真正的成功。