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
构建过程详解
构建日志示例
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)