hnpcli 适配 OpenHarmony PC 完整指南
源码获取:使用 Git 克隆而非压缩包版本控制:通过 Git 标签精确控制版本依赖管理:明确声明并自动构建依赖路径处理:通过环境变量传递源码路径静态链接:使用静态库简化部署。
hnpcli 适配 OpenHarmony PC 完整指南
项目概述
什么是 hnpcli?
hnpcli (HarmonyOS Native Package CLI) 是一个用于制作 OpenHarmony Native Package (HNP) 的命令行工具。它是 OpenHarmony 生态系统中用于打包和分发原生应用的重要工具。
适配版本
-
目标版本: OpenHarmony-v6.0.0.1-Release
-
架构支持: arm64-v8a
-
构建系统: CMake
-
许可证: Apache-2.0
核心功能
-
📦 打包原生应用为 HNP 格式
-
🔍 验证 HNP 包完整性
-
📋 管理 HNP 包元数据
-
🗜️ 压缩和解压缩 HNP 包
技术架构
依赖关系
hnpcli ├── cJson (JSON 解析库) ├── libboundscheck (边界检查库) └── zlib_static (压缩库,静态链接)
源码结构
hnpcli 的源码来自 OpenHarmony 的 startup_appspawn 仓库,主要包含以下组件:
startup_appspawn/ └── service/ └── hnp/ ├── base/ # 基础功能模块 │ ├── hnp_file.c # 文件操作 │ ├── hnp_json.c # JSON 处理 │ ├── hnp_log.c # 日志系统 │ └── hnp_zip.c # ZIP 压缩 ├── pack/ # 打包功能 │ ├── src/ │ │ └── hnp_pack.c # 打包实现 │ └── include/ └── hnpcli_main.c # 主程序入口
适配过程详解
步骤 1:配置外部仓库
在 outerrepo/module.json 中添加 hnpcli 的配置:
{
"name": "hnpcli",
"branch": "ohos_6.0.0.1",
"version": "6.0.0.1",
"type": "git",
"url": "https://gitcode.com/OpenHarmonyPCDeveloper/ohos_hnpcli.git"
}
配置说明:
-
name: 模块名称,对应目录名 -
branch: Git 分支名,对应适配版本 -
version: 版本号,用于构建和打包 -
type: 源码获取方式,git表示使用 Git 克隆 -
url: 源码仓库地址
步骤 2:创建 HPKBUILD 文件
在 outerrepo/hnpcli/HPKBUILD 中定义构建流程:
# 包基本信息
pkgname=hnpcli
pkgver=6.0.0.1
fullpkgver=OpenHarmony-v${pkgver}-Release
pkgrel=0
pkgdesc="hnp打包工具"
url="https://gitcode.com/openharmony/startup_appspawn"
archs=("arm64-v8a")
license=("Apache-2.0")
# 依赖声明
depends=("cJson" "libboundscheck" "zlib_static")
makedepends=()
# 源码配置
source="https://gitcode.com/openharmony/startup_appspawn.git"
autounpack=false # 不使用自动解压
downloadpackage=false # 不使用自动下载
builddir=$pkgname-${pkgver}
download_and_patch_flag=true
licensefile=${builddir}/LICENSE
关键配置说明:
-
autounpack=false:-
因为使用 Git 克隆,不需要自动解压压缩包
-
源码通过
prepare()函数中的git clone获取
-
-
downloadpackage=false:-
不使用标准的下载机制
-
源码通过 Git 直接克隆
-
-
depends:-
声明运行时依赖
-
Lycium 会自动构建这些依赖库
-
步骤 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-v6.0.0.1-Release)
-
-
构建目录管理:
mkdir -p ${builddir}/$ARCH-build-
为每个架构创建独立的构建目录
-
支持多架构并行构建
-
-
环境变量设置:
setarm64ENV
-
设置交叉编译工具链(CC, CXX, AR 等)
-
设置编译选项(CFLAGS, CXXFLAGS, LDFLAGS)
-
步骤 4:实现 build() 函数
build() 函数执行实际的编译过程:
build() {
# 设置构建目录环境变量(供 CMakeLists.txt 使用)
export HNPCLI_BUILD_DIR=${builddir}
# 配置 CMake
${CMAKE} "$@" \
-DCMAKE_PREFIX_PATH="$LYCIUM_ROOT/usr/cJson/$ARCH:$LYCIUM_ROOT/usr/libboundscheck/$ARCH:$LYCIUM_ROOT/usr/zlib_static/$ARCH" \
-B$ARCH-build -S./ -L
# 执行编译
pushd ${ARCH}-build
${MAKE} VERBOSE=1
ret=$?
popd
return $ret
}
关键点:
-
环境变量传递:
export HNPCLI_BUILD_DIR=${builddir}-
CMakeLists.txt 需要使用源码目录路径
-
通过环境变量传递给 CMake
-
-
依赖路径配置:
-DCMAKE_PREFIX_PATH="$LYCIUM_ROOT/usr/cJson/$ARCH:$LYCIUM_ROOT/usr/libboundscheck/$ARCH:$LYCIUM_ROOT/usr/zlib_static/$ARCH"
-
告诉 CMake 在哪里查找依赖库
-
使用冒号分隔多个路径
-
-
CMake 参数:
-
-B$ARCH-build: 指定构建目录 -
-S./: 指定源码目录(当前目录) -
-L: 列出所有 CMake 变量(调试用)
-
步骤 5:CMakeLists.txt 配置
CMakeLists.txt 定义了如何构建 hnpcli:
cmake_minimum_required(VERSION 3.10)
project(hnpcli)
set(CMAKE_C_STANDARD 17)
add_definitions(-DHNP_CLI)
# 查找依赖库
find_library(MYBOUNDS_CHECK libboundscheck.a)
find_library(MYJSON libcjson.a)
find_library(MYZLIB libz_static.a)
# 查找头文件目录
find_path(BOUNDS_CHECK_INCLUDE_DIR securec.h)
find_path(CJSON_INCLUDE_DIR cjson/cJSON.h)
find_path(ZLIB_INCLUDE_DIR zlib.h)
# 获取源码路径
set(STARTUP_APPSPAWN_PATH $ENV{HNPCLI_BUILD_DIR})
# 设置包含目录
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/pack/src
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/pack/include
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base
${BOUNDS_CHECK_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${CJSON_INCLUDE_DIR}/cjson
)
# 添加可执行文件
add_executable(hnpcli
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base/hnp_file.c
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base/hnp_json.c
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base/hnp_log.c
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base/hnp_zip.c
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/hnpcli_main.c
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/pack/src/hnp_pack.c
)
# 链接库
target_link_libraries(hnpcli
${MYBOUNDS_CHECK}
${MYJSON}
${MYZLIB}
)
# 安装规则
install(TARGETS hnpcli
DESTINATION bin
)
关键点:
-
依赖库查找:
find_library(MYBOUNDS_CHECK libboundscheck.a) find_library(MYJSON libcjson.a) find_library(MYZLIB libz_static.a)
-
查找静态库文件
-
通过
CMAKE_PREFIX_PATH指定的路径搜索
-
-
源码路径处理:
set(STARTUP_APPSPAWN_PATH $ENV{HNPCLI_BUILD_DIR})-
从环境变量获取源码目录
-
因为源码在 Git 仓库的子目录中
-
-
源文件路径:
${CMAKE_CURRENT_SOURCE_DIR}/${STARTUP_APPSPAWN_PATH}/service/hnp/base/hnp_file.c-
使用完整路径引用源文件
-
CMakeLists.txt 在
outerrepo/hnpcli/目录 -
源文件在
hnpcli-6.0.0.1/service/hnp/目录
-
步骤 6:实现 package() 函数
package() 函数安装编译产物:
package() {
pushd $ARCH-build
$MAKE VERBOSE=1 install PREFIX=$LYCIUM_ROOT/usr/$pkgname/$ARCH >> $buildlog 2>&1
ret=$?
popd
return $ret
}
说明:
-
使用 CMake 的
install目标 -
安装到
lycium/usr/hnpcli/arm64-v8a/bin/hnpcli -
日志输出到构建日志文件
步骤 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
-
步骤 8:配置 hnp.json
hnp.json 定义 HNP 包的元数据:
{
"type": "hnp-config",
"name": "hnpcli",
"version": "6.0.0.1",
"install": {}
}
字段说明:
-
type: 固定为"hnp-config" -
name: 包名称,必须与pkgname一致 -
version: 版本号,必须与pkgver一致 -
install: 安装规则(空对象表示安装所有文件)
构建流程
完整构建命令
cd lycium ./build.sh hnpcli
构建过程详解
开始构建
读取 module.json
Git 克隆源码
切换到指定版本
构建依赖库
cJson
libboundscheck
zlib_static
准备构建环境
配置 CMake
编译 hnpcli
安装到usr目录
生成tar.gz
生成hnp包
完成
构建日志示例
Build OS Darwin OHOS_SDK=/Users/jianguo/Library/OpenHarmony/Sdk/20 CLANG_VERSION=15.0.4 Start building hnpcli 6.0.0.1! Compileing OpenHarmony arm64-v8a hnpcli 6.0.0.1 libs... hnpcli-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 -- BOUNDS_CHECK library found at: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/libboundscheck/arm64-v8a/lib/libboundscheck.a -- CJSON library found at: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/cJson/arm64-v8a/lib/libcjson.a -- ZLIB library found at: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/zlib_static/arm64-v8a/lib/libz_static.a -- Configuring done -- Generating done -- Build files have been written to: arm64-v8a-build [ 14%] Building C object CMakeFiles/hnpcli.dir/hnpcli-6.0.0.1/service/hnp/base/hnp_file.c.o [ 28%] Building C object CMakeFiles/hnpcli.dir/hnpcli-6.0.0.1/service/hnp/base/hnp_json.c.o [ 42%] Building C object CMakeFiles/hnpcli.dir/hnpcli-6.0.0.1/service/hnp/base/hnp_log.c.o [ 57%] Building C object CMakeFiles/hnpcli.dir/hnpcli-6.0.0.1/service/hnp/base/hnp_zip.c.o [ 71%] Building C object CMakeFiles/hnpcli.dir/hnpcli-6.0.0.1/service/hnp/hnpcli_main.c.o [ 85%] Building C object CMakeFiles/hnpcli.dir/hnpcli-6.0.0.1/service/hnp/pack/src/hnp_pack.c.o [100%] Linking C executable hnpcli [100%] Built target hnpcli Install the project... -- Install configuration: "" -- Installing: /Users/jianguo/Desktop/harmony/tpc/lycium_plusplus/lycium/usr/hnpcli/arm64-v8a/bin/hnpcli Build hnpcli 6.0.0.1 end! ALL JOBS DONE!!!
构建产物
目录结构
lycium/
├── output/
│ └── arm64-v8a/
│ ├── hnpcli.hnp # HNP 归档包
│ └── hnpcli_6.0.0.1.tar.gz # 二进制归档包
└── usr/
└── hnpcli/
└── arm64-v8a/
├── bin/
│ └── hnpcli # 可执行文件
└── hnp.json # HNP 配置文件
产物说明
1. 可执行文件
$ file lycium/usr/hnpcli/arm64-v8a/bin/hnpcli hnpcli: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-aarch64.so.1, with debug_info, not stripped
特点:
-
ARM64 架构
-
动态链接到 musl C 库
-
包含调试信息
2. tar.gz 归档包
$ tar -tzf lycium/output/arm64-v8a/hnpcli_6.0.0.1.tar.gz bin/hnpcli hnp.json
用途:
-
二进制分发
-
手动安装
-
备份和归档
3. HNP 包
$ file lycium/output/arm64-v8a/hnpcli.hnp hnpcli.hnp: Zip archive data, at least v2.0 to extract, compression method=deflate
用途:
-
HarmonyOS 系统直接安装
-
包管理工具使用
-
应用分发
关键技术点
1. Git 源码管理
为什么使用 Git 而不是压缩包?
-
✅ 源码在大型仓库的子目录中(startup_appspawn)
-
✅ 需要精确的版本控制(特定标签)
-
✅ 便于后续更新和维护
-
✅ 支持补丁和修改
实现方式:
# 克隆仓库 git clone https://gitcode.com/openharmony/startup_appspawn.git hnpcli-6.0.0.1 # 切换到指定版本 cd hnpcli-6.0.0.1 git reset --hard OpenHarmony-v6.0.0.1-Release
2. 环境变量传递
问题:CMakeLists.txt 需要知道源码目录路径
解决方案:通过环境变量传递
# HPKBUILD 中
export HNPCLI_BUILD_DIR=${builddir}
# CMakeLists.txt 中
set(STARTUP_APPSPAWN_PATH $ENV{HNPCLI_BUILD_DIR})
3. 依赖路径配置
问题:CMake 需要找到依赖库
解决方案:使用 CMAKE_PREFIX_PATH
-DCMAKE_PREFIX_PATH="$LYCIUM_ROOT/usr/cJson/$ARCH:$LYCIUM_ROOT/usr/libboundscheck/$ARCH:$LYCIUM_ROOT/usr/zlib_static/$ARCH"
工作原理:
-
CMake 会在这些路径下搜索
lib/和include/目录 -
find_library()和find_path()会自动搜索
4. 静态库链接
为什么使用静态库?
-
✅ 减少运行时依赖
-
✅ 简化部署
-
✅ 提高兼容性
链接方式:
target_link_libraries(hnpcli
${MYBOUNDS_CHECK} # libboundscheck.a
${MYJSON} # libcjson.a
${MYZLIB} # libz_static.a
)
常见问题与解决方案
问题 1:Git 克隆失败
症状:
git clone $source $builddir ERROR: Failed to clone repository
解决方案:
-
检查网络连接
-
验证仓库 URL
-
检查 Git 凭据
# 手动测试 git clone https://gitcode.com/openharmony/startup_appspawn.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 Error: Could not find libboundscheck.a
解决方案:
-
确保依赖库已构建
-
检查 CMAKE_PREFIX_PATH
-
验证库文件路径
# 检查依赖库是否存在 ls -lh lycium/usr/libboundscheck/arm64-v8a/lib/ # 验证 CMake 路径 cmake -DCMAKE_PREFIX_PATH="..." -L | grep CMAKE_PREFIX_PATH
问题 4:源文件路径错误
症状:
CMake Error: Cannot find source file: hnp_file.c
解决方案:
-
检查 HNPCLI_BUILD_DIR 环境变量
-
验证源文件路径
-
确认 Git 克隆成功
# 检查环境变量 echo $HNPCLI_BUILD_DIR # 验证源文件 ls -lh hnpcli-6.0.0.1/service/hnp/base/hnp_file.c
问题 5:HNP 打包失败
症状:
[ERROR][HNP] source dir path is invalid
解决方案:
-
检查产物目录是否存在
-
验证 hnp.json 文件
-
确认 HNP_TOOL 环境变量
# 检查产物目录 ls -lh lycium/usr/hnpcli/arm64-v8a/ # 验证 hnp.json cat lycium/usr/hnpcli/arm64-v8a/hnp.json # 检查 HNP_TOOL echo $HNP_TOOL
最佳实践
1. 版本管理
-
✅ 使用 Git 标签管理版本
-
✅ 在 HPKBUILD 中明确指定版本
-
✅ 保持版本号一致性
2. 依赖管理
-
✅ 明确声明所有依赖
-
✅ 使用静态库减少运行时依赖
-
✅ 验证依赖库版本兼容性
3. 构建优化
-
✅ 使用并行编译加速构建
-
✅ 缓存构建产物
-
✅ 清理中间文件
4. 测试验证
-
✅ 验证可执行文件格式
-
✅ 测试基本功能
-
✅ 检查产物完整性
使用示例
构建 hnpcli
cd lycium ./build.sh hnpcli
使用 hnpcli 打包应用
# 设置环境变量 export HNP_TOOL=lycium/usr/hnpcli/arm64-v8a/bin/hnpcli # 打包应用 $HNP_TOOL pack -i /path/to/app -o /path/to/output
验证 HNP 包
# 查看包信息 $HNP_TOOL info /path/to/app.hnp # 解压包 $HNP_TOOL unpack -i /path/to/app.hnp -o /path/to/output
总结
适配要点
-
源码获取:使用 Git 克隆而非压缩包
-
版本控制:通过 Git 标签精确控制版本
-
依赖管理:明确声明并自动构建依赖
-
路径处理:通过环境变量传递源码路径
-
静态链接:使用静态库简化部署
技术亮点
-
✅ 灵活的源码管理方式
-
✅ 完善的依赖处理机制
-
✅ 标准化的构建流程
-
✅ 多样化的产物格式
适用场景
-
OpenHarmony 原生应用打包
-
命令行工具开发
-
系统工具构建
-
依赖 CMake 的项目
适配版本: OpenHarmony-v6.0.0.1-Release 关键词: hnpcli, OpenHarmony, HNP, 打包工具, CMake, 交叉编译, Lycium
更多推荐


所有评论(0)