前言

在 HarmonyOS 生态系统中,将传统的 Linux 命令行工具移植并打包为原生应用是一个常见需求。本文将以 tree 工具为例,深入解析如何使用 build_ohos.sh 脚本完成从源码编译到 HNP(HarmonyOS Native Package)打包的完整流程。

什么是 HNP?

HNP(HarmonyOS Native Package)是 HarmonyOS 的原生包格式,类似于 Linux 的 RPM 或 DEB 包。它包含了编译好的二进制文件、配置文件、元数据等信息,可以方便地在 HarmonyOS 设备上安装和管理。

构建脚本架构概览

build_ohos.sh 脚本是整个构建流程的核心,它负责:

  1. 环境配置:设置正确的安装路径和编译环境
  2. 源码编译:使用交叉编译工具链编译 tree 工具
  3. 文件安装:将编译产物安装到指定目录
  4. 包生成:创建 HNP 格式包和 tar.gz 压缩包

详细流程解析

1. HNP 路径规范

export TREE_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/tree.org/tree_2.2.1

HNP 包的路径遵循严格的命名规范:

  • 格式:${HNP_PUBLIC_PATH}/<部件名称>.org/<部件名称>_<版本号>
  • 示例:/data/service/hnp/tree.org/tree_2.2.1

这种规范化的路径设计有以下优势:

  • 唯一性:确保不同版本和不同组件的包不会冲突
  • 可追溯性:从路径就能看出包的来源和版本信息
  • 标准化:符合 HarmonyOS 的包管理规范

2. PREFIX 环境变量的巧妙使用

sys_prefix=${PREFIX}              # 保存原始值
export PREFIX=${TREE_INSTALL_HNP_PATH}  # 临时修改
# ... 执行构建和安装 ...
export PREFIX=${sys_prefix}       # 恢复原始值

这是一个经典的"保存-修改-恢复"模式:

为什么需要这样做?

  • Makefile 的 install 目标使用 PREFIX 变量来确定安装位置
  • 我们需要将文件安装到 HNP 路径,而不是系统默认路径(通常是 /usr/local
  • 临时修改后必须恢复,避免影响其他构建任务

设计亮点

  • 非侵入性:不修改 Makefile,只通过环境变量控制行为
  • 可恢复性:确保构建过程不会污染全局环境

3. 构建三部曲:清理、编译、安装

3.1 清理阶段
make clean

清理之前的构建产物(.o 目标文件和可执行文件),确保:

  • 每次构建都是干净的状态
  • 避免旧文件干扰新构建
  • 发现潜在的依赖问题
3.2 编译阶段
make VERBOSE=1

VERBOSE=1 参数的作用:

  • 显示完整的编译命令(包括编译器、标志、源文件等)
  • 便于调试编译错误
  • 帮助理解交叉编译过程

交叉编译的关键

  • 编译器:使用 HarmonyOS SDK 提供的 clang(通过 CC 环境变量设置)
  • 目标平台:aarch64-linux-ohos(ARM 64 位架构)
  • 系统根目录:--sysroot=${SYSROOT} 指向 HarmonyOS 的系统库
3.3 安装阶段
make install

安装过程会创建以下目录结构:

${TREE_INSTALL_HNP_PATH}/
├── bin/
│   └── tree          # 可执行文件
├── man/
│   └── man1/
│       └── tree.1    # 手册页
└── hnp.json          # HNP 配置文件(后续复制)

4. HNP 配置文件

cp hnp.json ${TREE_INSTALL_HNP_PATH}/

hnp.json 是 HNP 包的元数据文件,包含:

{
    "type": "hnp-config",
    "name": "tree",
    "version": "2.2.1",
    "install": {}
}

这个文件告诉 HNP 打包工具:

  • 包的名称和版本
  • 包的配置信息
  • 安装规则(如果有)

5. 双重打包策略

脚本采用了双重打包策略,同时生成两种格式:

5.1 HNP 格式包
${HNP_TOOL} pack -i ${TREE_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/

生成 tree.hnp 文件,这是:

  • HarmonyOS 的原生包格式
  • 可以被 HarmonyOS 包管理器直接安装
  • 包含完整的元数据和依赖信息
5.2 tar.gz 压缩包
tar -zvcf ${ARCHIVE_PATH}/ohos_tree_2.2.1.tar.gz tree_2.2.1/

生成传统的 tar.gz 压缩包,优势:

  • 通用性强:可以在任何支持 tar 的系统上解压
  • 便于手动部署和分发
  • 作为 HNP 包的备用方案

为什么需要两种格式?

  • HNP:面向 HarmonyOS 生态,支持包管理器的自动化安装
  • tar.gz:面向通用场景,便于手动部署和跨平台分发

环境变量依赖关系

脚本依赖以下环境变量(由主构建脚本 build.sh 设置):

环境变量 说明 示例值
HNP_PUBLIC_PATH HNP 公共路径 /data/service/hnp
HNP_TOOL HNP 打包工具路径 ${OHOS_SDK}/toolchains/hnpcli
ARCHIVE_PATH 输出归档路径 ${WORK_ROOT}/output
PREFIX 安装前缀(临时修改) /usr/local${TREE_INSTALL_HNP_PATH}
CC, CFLAGS 交叉编译工具链配置 build.sh 设置

构建输出

成功执行后,会在 ${ARCHIVE_PATH} 目录下生成:

output/
├── tree.hnp                    # HNP 格式包
└── ohos_tree_2.2.1.tar.gz     # tar.gz 压缩包

使用场景

场景 1:开发调试

# 在源码目录直接执行
cd code/cmdtree
source build_ohos.sh

场景 2:集成到构建系统

# 由主构建脚本调用
./build.sh --sdk /path/to/ohos-sdk

主构建脚本会:

  1. 设置所有必需的环境变量
  2. 配置交叉编译工具链
  3. 调用 build_ohos.sh 执行构建

最佳实践

1. 路径管理

  • 始终使用环境变量,避免硬编码路径
  • 遵循 HNP 路径规范:<组件>.org/<组件>_<版本>
  • 使用 pushd/popd 管理目录切换

2. 环境隔离

  • 保存和恢复 PREFIX 等关键环境变量
  • 使用 sys_prefix 变量保存原始值
  • 确保构建过程不影响全局环境

3. 错误处理

虽然当前脚本没有显式的错误处理,但在生产环境中建议添加:

set -e  # 遇到错误立即退出
set -u  # 使用未定义变量时报错

4. 日志记录

  • 使用 VERBOSE=1 获取详细编译信息
  • 输出关键路径信息便于调试
  • 记录构建时间和版本信息

常见问题排查

问题 1:找不到 HNP_TOOL

症状${HNP_TOOL} pack 命令失败

解决

  • 检查 OHOS_SDK 环境变量是否正确设置
  • 确认 SDK 中是否存在 toolchains/hnpcli 工具
  • 验证工具是否有执行权限

问题 2:编译失败

症状make VERBOSE=1 报错

解决

  • 检查交叉编译工具链是否正确配置
  • 查看 CCCFLAGSSYSROOT 等环境变量
  • 确认源码是否已进行 HarmonyOS 适配

问题 3:安装路径错误

症状:文件安装到了错误的位置

解决

  • 检查 TREE_INSTALL_HNP_PATH 是否正确设置
  • 确认 PREFIX 环境变量是否被正确覆盖
  • 验证目录权限是否足够

总结

build_ohos.sh 脚本虽然只有短短几十行,但体现了 HarmonyOS 原生应用构建的核心思想:

  1. 标准化:遵循 HNP 路径和命名规范
  2. 模块化:通过环境变量实现灵活的配置
  3. 兼容性:同时支持 HNP 和传统 tar.gz 格式
  4. 可维护性:清晰的步骤划分和注释说明

通过这个脚本,我们可以将任何符合标准的 Linux 工具移植到 HarmonyOS 平台,为 HarmonyOS 生态系统的丰富性贡献力量。

参考资料

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐