开源鸿蒙终端工具Termony增加外部HNP包合入base.hnp的设计与实现实战教程
本文介绍了如何将 external-hnp 目录下的预构建 HNP 包自动合并到最终产物 base.hnp 中。主要内容包括: 目标与范围:自动合并三种格式的外部 HNP 包到 base.hnp 中 现有打包规则回顾:分析 Makefile 结构和依赖关系 合入策略设计:按优先级处理不同格式的 HNP 包,定义目录映射规则 具体实现:修改 Makefile 添加外部包检测和合并逻辑。
本文面向将 external-hnp 目录下的已构建 HNP 包,按照项目现有打包规则,自动合入到最终产物 base.hnp 中。教程覆盖设计目标、格式差异、Makefile 改造、合入策略、验证方法与常见问题排查,确保在同一套 HNP 流水线下实现稳定、可维护的外部包整合。
🎯 目标与范围
- 🎯 目标:在完成
build-hnp内所有包的构建后,自动将external-hnp/*.hnp的内容合并进build-hnp/sysroot,并随base.hnp一并打包分发。 - 📋 范围:兼容三类外部 HNP 格式:
- 📁 标准
sysroot/结构:归档内顶层为sysroot/(与本工程一致) - 📂
usr/目录结构:归档内顶层为供应商自定义路径,实际内容位于其中的usr/(例如:dog_1.0.0/usr/bin/dog、jq_1.7/usr/bin/jq、whois_5.5.10/usr/bin/whois) - 🗂️ 顶层标准目录结构:归档内顶层为供应商自定义路径,但直接在顶层包含标准目录(例如:
autoconf_1.0.0/bin/、autoconf_1.0.0/share/、icu_1.0.0/lib/)
- 📁 标准
📚 现有打包规则回顾
🔧 Makefile 结构
# build-hnp/Makefile
STAMP=$(patsubst %,%/.stamp,$(PKGS))
EXTERNAL_HNP=$(wildcard ../external-hnp/*.hnp)
PKGS_MARKER=.pkgs-$(OHOS_ARCH)
all: copy
copy: base.hnp
rm -f ../entry/hnp/$(OHOS_ABI)/*.hnp
cp $^ ../entry/hnp/$(OHOS_ABI)
cp $^ ../entry/hnp/$(OHOS_ABI)/base-public.hnp
.PHONY: check-pkgs
check-pkgs:
@echo "$(PKGS)" > $(PKGS_MARKER).tmp
@if [ -f $(PKGS_MARKER) ]; then \
if ! cmp -s $(PKGS_MARKER) $(PKGS_MARKER).tmp; then \
echo "PKGS changed from '$$(cat $(PKGS_MARKER))' to '$(PKGS)', removing base.hnp to force rebuild..."; \
rm -f base.hnp; \
fi; \
else \
echo "Creating PKGS marker file with: $(PKGS)"; \
fi
@mv $(PKGS_MARKER).tmp $(PKGS_MARKER)
base.hnp: check-pkgs $(STAMP) utils/pbcopy utils/pbpaste utils/empty.a Makefile $(EXTERNAL_HNP)
# ... 构建步骤 ...
🔗 依赖关系说明
- 📌
$(STAMP):所有内部包的构建标记,例如gettext/.stamp、bash/.stamp,由PKGS变量生成 - 📦
$(EXTERNAL_HNP):使用wildcard函数自动发现external-hnp目录下的所有.hnp文件 - ✅
check-pkgs:.PHONY目标,每次构建时都会检查PKGS变量是否改变,如果改变则删除base.hnp强制重新构建 - 🔄 自动依赖检测:
- 当
external-hnp目录下新增、删除或修改.hnp文件时,base.hnp会自动重新构建 - 当
PKGS变量改变时(例如添加或删除包),check-pkgs会检测到变化并删除base.hnp,强制重新构建
- 当
- ⚡ 增量构建:无需手动触发,新增外部 HNP 包或修改
PKGS后,直接执行create-hnp.sh即可自动重新构建
📦 打包流程
- 🧹 清理阶段:删除
sysroot/share/{man,doc,info}减小体积 - 🔧 工具注入:复制
pbcopy/pbpaste与工具链运行时对象 - 📥 外部包合入:合并
external-hnp目录下的所有 HNP 包到sysroot - 🔐 权限设置:确保二进制文件具有执行权限
- 🧹 再次清理:删除外部包可能引入的文档文件
- 📦 打包:使用
zip -r base.hnp sysroot创建最终包 - 📋 拷贝:将
base.hnp复制到entry/hnp/$(OHOS_ABI),同时生成base-public.hnp
🎨 合入策略设计
⚡ 处理优先级
在 base.hnp 规则中,完成工具注入后、打包前执行外部 HNP 合入,按以下优先级处理:
- 🥇 优先处理
sysroot/目录:若归档内存在sysroot/,则直接合并其内容到当前sysroot/根目录(避免出现sysroot/sysroot嵌套) - 🥈 处理
usr/目录结构:若归档内不存在sysroot/,但存在一个或多个usr/目录,则将其中的usr/bin、usr/lib、usr/include、usr/share、usr/lib/pkgconfig映射合入到当前sysroot/bin、sysroot/lib、sysroot/include、sysroot/share、sysroot/lib/pkgconfig - 🥉 处理顶层标准目录结构:若两者均不存在,检查顶层目录(如
包名/bin/、包名/lib/等)中是否存在标准目录(bin、lib、include、share),如果存在,将这些目录的内容合并到sysroot对应目录 - 🔄 兜底策略:若以上情况均不匹配,则将归档内所有内容合并到当前
sysroot/
🗺️ 目录映射规则
usr/bin→sysroot/binusr/lib→sysroot/libusr/include→sysroot/includeusr/share→sysroot/shareusr/lib/pkgconfig→sysroot/lib/pkgconfig- 顶层
bin/、lib/、include/、share/等目录同样映射到sysroot对应目录
🧹 清理策略
- 🧹 合入前清理:删除
sysroot/share/{man,doc,info}减小体积 - 🧹 合入后再次清理:外部包可能包含大量手册与文档,合并后再次删除
sysroot/share/{man,doc,info}缩小体积
💻 具体实现
🔧 Makefile 修改
📝 修改文件:build-hnp/Makefile
✨ 关键修改点:
- 📦 添加外部包依赖检测:
EXTERNAL_HNP=$(wildcard ../external-hnp/*.hnp)
- ✅ 添加 PKGS 变化检测:
PKGS_MARKER=.pkgs-$(OHOS_ARCH)
.PHONY: check-pkgs
check-pkgs:
@echo "$(PKGS)" > $(PKGS_MARKER).tmp
@if [ -f $(PKGS_MARKER) ]; then \
if ! cmp -s $(PKGS_MARKER) $(PKGS_MARKER).tmp; then \
echo "PKGS changed from '$$(cat $(PKGS_MARKER))' to '$(PKGS)', cleaning build artifacts to force rebuild..."; \
rm -f base.hnp; \
old_pkgs="$$(cat $(PKGS_MARKER))"; \
for pkg in $$old_pkgs; do \
if ! echo "$(PKGS)" | grep -qw "$$pkg"; then \
echo " Removing stale stamp file: $$pkg/.stamp"; \
rm -f "$$pkg/.stamp"; \
fi; \
done; \
for pkg in $(PKGS); do \
if ! echo "$$old_pkgs" | grep -qw "$$pkg"; then \
echo " Removing stamp file for new package: $$pkg/.stamp"; \
rm -f "$$pkg/.stamp"; \
fi; \
done; \
fi; \
else \
echo "Creating PKGS marker file with: $(PKGS)"; \
fi
@mv $(PKGS_MARKER).tmp $(PKGS_MARKER)
- 🔗 更新 base.hnp 依赖:
base.hnp: check-pkgs $(STAMP) utils/pbcopy utils/pbpaste utils/empty.a Makefile $(EXTERNAL_HNP)
- 📥 外部包合入逻辑:
# merge external hnp packages
@if ls ../external-hnp/*.hnp >/dev/null 2>&1; then \
echo "Merging external HNP packages into sysroot..."; \
tmpdir="sysroot/.external_merge"; rm -rf "$$tmpdir"; mkdir -p "$$tmpdir"; \
for pkg in ../external-hnp/*.hnp; do \
echo " -> $$pkg"; \
if command -v ditto >/dev/null 2>&1; then \
ditto -x -k "$$pkg" "$$tmpdir" 2>/dev/null || unzip -q -o "$$pkg" -d "$$tmpdir" 2>/dev/null || true; \
else \
unzip -q -o "$$pkg" -d "$$tmpdir" 2>/dev/null || true; \
fi; \
if [ -d "$$tmpdir/sysroot" ]; then \
echo " Found sysroot/, merging directly..."; \
cp -a "$$tmpdir/sysroot/." sysroot/; \
else \
usr_dirs="$$(find "$$tmpdir" -type d -name usr 2>/dev/null)"; \
if [ -n "$$usr_dirs" ]; then \
for ud in $$usr_dirs; do \
if [ -n "$$ud" ] && [ -d "$$ud" ]; then \
echo " Found usr directory: $$ud"; \
for comp in bin lib include share; do \
if [ -d "$$ud/$$comp" ] && [ -n "$$(ls -A "$$ud/$$comp" 2>/dev/null)" ]; then \
mkdir -p "sysroot/$$comp"; \
cp -a "$$ud/$$comp/." "sysroot/$$comp/" 2>/dev/null || true; \
fi; \
done; \
if [ -d "$$ud/lib/pkgconfig" ] && [ -n "$$(ls -A "$$ud/lib/pkgconfig" 2>/dev/null)" ]; then \
mkdir -p "sysroot/lib/pkgconfig"; \
cp -a "$$ud/lib/pkgconfig/." "sysroot/lib/pkgconfig/" 2>/dev/null || true; \
fi; \
fi; \
done; \
else \
top_dirs="$$(find "$$tmpdir" -maxdepth 1 -type d ! -path "$$tmpdir" 2>/dev/null)"; \
merged=0; \
for top_dir in $$top_dirs; do \
if [ -n "$$top_dir" ] && [ -d "$$top_dir" ]; then \
for comp in bin lib include share; do \
if [ -d "$$top_dir/$$comp" ] && [ -n "$$(ls -A "$$top_dir/$$comp" 2>/dev/null)" ]; then \
echo " Found $$comp/ in $$(basename "$$top_dir"), merging to sysroot/$$comp/..."; \
mkdir -p "sysroot/$$comp"; \
cp -a "$$top_dir/$$comp/." "sysroot/$$comp/" 2>/dev/null || true; \
merged=1; \
fi; \
done; \
if [ -d "$$top_dir/lib/pkgconfig" ] && [ -n "$$(ls -A "$$top_dir/lib/pkgconfig" 2>/dev/null)" ]; then \
mkdir -p "sysroot/lib/pkgconfig"; \
cp -a "$$top_dir/lib/pkgconfig/." "sysroot/lib/pkgconfig/" 2>/dev/null || true; \
merged=1; \
fi; \
fi; \
done; \
if [ "$$merged" = "0" ]; then \
echo " No standard directories found, merging all content..."; \
cp -a "$$tmpdir/." sysroot/ 2>/dev/null || true; \
fi; \
fi; \
fi; \
rm -rf "$$tmpdir"; mkdir -p "$$tmpdir"; \
done; \
rm -rf "$$tmpdir"; \
echo " Ensuring executable permissions for binaries..."; \
find sysroot/bin -type f -exec chmod +x {} \; 2>/dev/null || true; \
else \
echo "No external HNP packages found, skipping merge"; \
fi
✨ 关键改进点
-
🔄 自动依赖检测:
- 使用
EXTERNAL_HNP=$(wildcard ../external-hnp/*.hnp)自动发现所有外部 HNP 包 - 将
$(EXTERNAL_HNP)添加到base.hnp的依赖中,实现增量构建 - 使用
check-pkgs.PHONY目标检测PKGS变量的变化,如果改变则删除base.hnp强制重新构建
- 使用
-
🍎 优先使用
ditto解压:- 在 macOS 上优先使用
ditto命令解压,能够正确处理所有 ZIP 格式,包括有 “volume label” 问题的包 - 如果系统不支持
ditto,则回退到unzip
- 在 macOS 上优先使用
-
📁 支持三种包结构:
- 标准
sysroot/结构:直接合并 usr/目录结构:将usr/bin、usr/lib等映射到sysroot/bin、sysroot/lib- 顶层标准目录结构:检查顶层目录中的
bin/、lib/、include/、share/等,合并到sysroot对应目录
- 标准
-
🧠 智能目录映射:
- 使用
merged标志跟踪是否成功合并了标准目录 - 只有在完全没有标准目录时才使用兜底策略,避免将整个包目录复制到
sysroot/根目录
- 使用
-
🛡️ 增强错误处理:
- 为所有关键操作添加
2>/dev/null || true,确保单个包失败不影响整体流程
- 为所有关键操作添加
-
🔐 确保文件权限:
- 合入后统一为
sysroot/bin下的所有文件添加执行权限,避免运行时出现权限问题
- 合入后统一为
-
📝 详细日志输出:
- 添加更详细的处理日志,包括目录发现和合并过程,便于问题排查
✅ 验证方法
1. 🚀 执行全量构建
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
2. 🔍 检查合入是否生效
📋 典型外部包结构示例:
external-hnp/dog.hnp:dog_1.0.0/usr/bin/dogexternal-hnp/autoconf.hnp:autoconf_1.0.0/bin/autoconfexternal-hnp/icu.hnp:icu_1.0.0/lib/libicu*.so
✅ 验证映射到 sysroot:
# 检查二进制文件是否在正确位置(应该在 sysroot/bin/ 下,而不是 sysroot/包名/usr/bin/)
ls -la build-hnp/sysroot/bin | grep -E "(dog|jq|whois|exa|hashdeep|autoconf|icu)"
# 检查文件权限(应该具有执行权限)
ls -l build-hnp/sysroot/bin/dog
ls -l build-hnp/sysroot/bin/jq
# 检查库文件
ls -la build-hnp/sysroot/lib | grep -E "(libicu|libjq)"
# 检查库文件和头文件
ls -la build-hnp/sysroot/lib/pkgconfig | grep -E "(icu|jq)"
ls -la build-hnp/sysroot/include | head -20
3. 📦 验证打包结果
# 检查打包产物
ls -la entry/hnp/arm64-v8a
# 预期:base.hnp 与 base-public.hnp
# 验证打包后的文件结构(确保文件在 sysroot/bin/ 下,而不是嵌套在其他目录中)
unzip -l entry/hnp/arm64-v8a/base.hnp | grep "sysroot/bin/dog"
unzip -l entry/hnp/arm64-v8a/base.hnp | grep "sysroot/bin/jq"
unzip -l entry/hnp/arm64-v8a/base.hnp | grep "sysroot/lib/libicu"
# 应该看到类似:sysroot/bin/dog 而不是 sysroot/dog_1.0.0/usr/bin/dog
4. 🔗 验证依赖关系
# 检查 base.hnp 的依赖关系
OHOS_ARCH=aarch64 make -C build-hnp -p | grep "^base.hnp:"
# 应该看到 base.hnp 依赖了 external-hnp 目录下的所有 .hnp 文件
# 测试新增文件后的自动重建
touch external-hnp/test.hnp
OHOS_ARCH=aarch64 make -C build-hnp -n base.hnp
# 应该会触发重新构建(显示构建命令)
5. 🎮 运行时验证(在应用启动后)
# 在终端中执行外部包命令
dog --version
jq --version
whois --version
icu-config --version # 如果 icu.hnp 包含此工具
# 如果仍然提示 command not found,检查:
# - PATH 环境变量是否包含 /data/app/bin
# - 文件是否确实在 base.hnp 的 sysroot/bin/ 目录下
# - 文件权限是否正确(应该具有执行权限)
💡 说明:部分外部包可能仅提供库与头文件等,而非二进制;请根据各自
hnp.json与包目录结构确认合入内容。
🐛 常见问题与排查
1. ❌ command not found 问题
🔍 症状:应用启动后,执行外部 HNP 包命令(如 dog、jq、whois 等)提示 command not found。
🔎 根本原因:
- 📦 解压工具兼容性问题:在 macOS 上,
unzip命令遇到某些 HNP 包的 “volume label” 问题时,会显示 “skipping” 但实际上跳过了文件解压,导致临时目录为空,后续复制操作失败 - 📂 路径处理问题:早期实现中使用
while read在子shell中执行,可能导致复制操作失败 - 🔐 文件权限问题:二进制文件可能缺少执行权限
✅ 解决方案:
- 🍎 优先使用
ditto解压:在 macOS 上,ditto命令能够正确处理所有 ZIP 格式的 HNP 包,包括有 “volume label” 问题的包。实现中优先检测并使用ditto,如果不可用则回退到unzip - 📋 简化复制逻辑:直接使用
cp -a "$$ud/$$comp/." "sysroot/$$comp/"复制整个目录内容,避免通配符匹配失败的问题 - 🔐 确保文件权限:在合入后统一执行
find sysroot/bin -type f -exec chmod +x {} \;确保所有二进制文件具有执行权限
✅ 验证方法:
# 检查文件是否在正确位置
ls -la build-hnp/sysroot/bin | grep -E "(dog|jq|whois|exa|hashdeep)"
# 检查文件权限
ls -l build-hnp/sysroot/bin/dog # 应该显示 -rwxr-xr-x 或类似的可执行权限
# 检查打包后的内容
unzip -l entry/hnp/arm64-v8a/base.hnp | grep "sysroot/bin/dog"
# 应该看到:sysroot/bin/dog 而不是 sysroot/dog_1.0.0/usr/bin/dog
# 验证解压是否成功(在构建过程中检查临时目录)
# 如果看到 "skipping: ... volume label" 但文件仍然存在,说明解压成功
# 如果目录为空,说明解压失败,需要使用 ditto

2. 📁 sysroot/sysroot 重复目录
归档内包含顶层 sysroot/,需走"直接合并其内容到当前 sysroot 根"的分支;本实现已覆盖该情况。
3. ⚠️ 解包兼容性问题(关键问题)
🔍 "volume label"问题:在 macOS 上,某些 HNP 包使用非标准的 ZIP 格式(包含 volume label),unzip 命令会显示 “skipping: … volume label” 警告,并且实际上跳过了文件解压,导致临时目录为空。
✅ 解决方案:
- 🍎 优先使用
ditto:ditto是 macOS 系统自带的解压工具,能够正确处理所有 ZIP 格式,包括有 volume label 问题的包 - 实现中检测系统是否支持
ditto,如果支持则优先使用,否则回退到unzip
🔍 排查方法:
# 方法1:使用 ditto(推荐)
mkdir -p /tmp/test_extract
ditto -x -k external-hnp/dog.hnp /tmp/test_extract
find /tmp/test_extract -type f -name "dog"
# 应该能找到文件
# 方法2:使用 unzip(可能失败)
mkdir -p /tmp/test_extract
unzip -q external-hnp/dog.hnp -d /tmp/test_extract
ls -la /tmp/test_extract
# 如果目录为空或只有目录结构没有文件,说明解压失败
# 如果看到 "skipping: ... volume label" 但文件存在,说明解压成功(虽然显示警告)
4. 📦 文档体积膨胀
外部包合入后再次清理 man/doc/info,并在必要时对 share/ 下的样例或多余资源做裁剪。
5. ⚔️ 覆盖冲突
若外部包与本地构建产物存在同名文件,合并以外部包为后写入;如需优先保留本地产物,可在 cp -a 前增加存在性判断或采用版本号目录避免覆盖。
6. 🗺️ 文件路径映射错误
🔍 症状:打包后的 base.hnp 中包含 sysroot/包名/usr/bin/ 或 sysroot/包名/bin/ 这样的路径,而不是 sysroot/bin/。
🔎 原因:
- 合入逻辑未正确识别和处理
usr目录结构 - 对于顶层直接包含标准目录的包(如
autoconf_1.0.0/bin/),未正确映射到sysroot/bin/
✅ 解决方案:
- 确保正确处理
usr/目录结构:将usr/bin、usr/lib等映射到sysroot/bin、sysroot/lib - 对于顶层标准目录结构:检查顶层目录中是否存在
bin/、lib/、include/、share/等标准目录,如果存在,将这些目录的内容合并到sysroot对应目录 - 验证复制操作确实将文件复制到了目标位置:
ls -la build-hnp/sysroot/bin | grep -E "(dog|autoconf)"
7. 📂 顶层目录结构未正确映射
🔍 症状:某些外部包(如 autoconf.hnp、automake.hnp、icu.hnp)的内容没有被正确合并到 sysroot 对应目录,而是整个包目录被复制到了 sysroot/ 根目录下。
🔎 原因:这些包的目录结构是 包名/bin/、包名/lib/ 等,而不是 包名/usr/bin/,之前的实现只处理了 usr/ 目录结构的情况。
✅ 解决方案:
- 在找不到
usr/目录时,检查顶层目录中是否存在标准目录(bin、lib、include、share) - 如果存在,将这些目录的内容合并到
sysroot对应目录,而不是复制整个包目录 - 使用
merged标志跟踪是否成功合并了标准目录,只有在完全没有标准目录时才使用兜底策略
8. 🔄 新增外部包后未自动重新构建
🔍 症状:在 external-hnp 目录下新增了 .hnp 文件(如 icu.hnp、less.hnp),执行 create-hnp.sh 后,base.hnp 没有重新构建,新增的包没有被包含进去。
🔎 原因:base.hnp 的依赖中没有包含 external-hnp 目录下的文件,make 无法检测到新增文件,认为 base.hnp 已经是最新的。
✅ 解决方案:
- 在 Makefile 中添加
EXTERNAL_HNP=$(wildcard ../external-hnp/*.hnp)自动发现所有外部 HNP 包 - 将
$(EXTERNAL_HNP)添加到base.hnp的依赖中:base.hnp: check-pkgs $(STAMP) ... $(EXTERNAL_HNP) - 这样当
external-hnp目录下新增、删除或修改.hnp文件时,base.hnp会自动重新构建
✅ 验证方法:
# 检查依赖关系
OHOS_ARCH=aarch64 make -C build-hnp -p | grep "^base.hnp:"
# 应该看到 base.hnp 依赖了 external-hnp 目录下的所有 .hnp 文件
# 新增文件后测试
touch external-hnp/test.hnp
OHOS_ARCH=aarch64 make -C build-hnp -n base.hnp
# 应该会触发重新构建(显示构建命令)
# 删除文件后测试
rm external-hnp/test.hnp
OHOS_ARCH=aarch64 make -C build-hnp -n base.hnp
# 应该会触发重新构建(因为依赖文件被删除)
🔄 增量重建与维护
📦 新增外部 HNP 包后的自动重建
- 🔄 自动检测:
base.hnp的依赖中包含$(EXTERNAL_HNP),会自动检测external-hnp目录下的所有.hnp文件 - ⚡ 自动重建:当
external-hnp目录下新增、删除或修改.hnp文件时,执行create-hnp.sh会自动重新构建base.hnp - ✨ 无需手动操作:新增外部包后,直接执行:
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
✅ PKGS 改变后的自动重建
- 🔄 自动检测:
base.hnp的依赖中包含check-pkgs,每次构建时都会检查PKGS变量是否改变 - ⚡ 自动重建:当
PKGS变量改变时(例如添加或删除包),check-pkgs会检测到变化并删除base.hnp,强制重新构建 - ✨ 无需手动操作:修改
PKGS后,直接执行:
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
⚙️ 工作原理:
check-pkgs是一个.PHONY目标,每次构建时都会执行- 将当前的
PKGS值写入.pkgs-$(OHOS_ARCH).tmp临时文件 - 如果
.pkgs-$(OHOS_ARCH)文件存在,比较新旧值是否相同 - 如果不同,说明
PKGS改变了,执行清理操作:- 删除
base.hnp强制重新构建 - 遍历旧的 PKGS 列表,删除不再需要的
.stamp文件(从 PKGS 中移除的包) - 遍历新的 PKGS 列表,删除新添加的包的
.stamp文件(强制重新构建)
- 删除
- 将临时文件重命名为正式文件,记录当前的
PKGS值
✨ 关键改进:
- 🧹 清理旧的
.stamp文件:当包从 PKGS 中移除时,删除对应的.stamp文件,避免 make 误判 - 🔄 清理新包的
.stamp文件:当包添加到 PKGS 时,删除对应的.stamp文件,强制重新构建并复制到sysroot
📋 示例场景:
- ➕ 添加包:
PKGS从bash改为gettext bashcheck-pkgs检测到变化- 删除
base.hnp和gettext/.stamp(新包) - 重新构建时会构建
gettext和bash两个包,并复制到sysroot
- ➖ 删除包:
PKGS从gettext bash改为bashcheck-pkgs检测到变化- 删除
base.hnp和gettext/.stamp(旧包) - 重新构建时只构建
bash包,sysroot中不再包含gettext的内容
- 🔄 重新排序:
PKGS从bash gettext改为gettext bash- 虽然包相同但顺序不同,
check-pkgs也会检测到变化 - 删除
base.hnp和所有相关.stamp文件 - 重新构建所有包,确保
sysroot内容与 PKGS 一致
- 虽然包相同但顺序不同,
📦 仅重新执行打包与合入
在所有包已构建的前提下,直接调用:
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
🔧 重建单个内部包
若需要只重建某一包,再执行对应 rebuild-<pkg> 后再次打包;例如:
make -C build-hnp rebuild-yyjson
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
🔄 强制重新构建所有外部包
如果需要强制重新合入所有外部包(例如修改了合入逻辑),可以删除 base.hnp 后重新构建:
rm -f build-hnp/base.hnp
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
🧹 清理构建产物
如果需要完全重新构建,可以清理所有构建产物:
make -C build-hnp clean
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh
💡 实现细节与最佳实践
🛠️ 解压工具选择
- 🍎 macOS 平台:优先使用
ditto,能够正确处理所有 ZIP 格式,包括有 volume label 问题的包 - 🐧 其他平台:使用
unzip作为主要解压工具 - 🛡️ 错误处理:如果主要解压工具失败,自动尝试备用工具
📁 目录结构识别
- 🥇 优先检查
sysroot/:如果存在,直接合并,避免嵌套 - 🥈 其次检查
usr/:如果存在,映射标准目录到sysroot - 🥉 最后检查顶层标准目录:如果存在
bin/、lib/等,合并到对应位置 - 🔄 兜底策略:只有在完全没有标准目录时才使用
🔐 文件权限管理
- ✅ 合入后统一设置:使用
find sysroot/bin -type f -exec chmod +x {} \;确保所有二进制文件具有执行权限 - 🛡️ 避免权限问题:确保运行时能够正常执行外部包的命令
🛡️ 错误处理策略
- 🔄 单个包失败不影响整体:使用
2>/dev/null || true确保单个包解压或复制失败时,其他包仍能正常处理 - 📝 详细日志输出:记录每个包的处理过程,便于问题排查
📝 总结
- 🤖 自动化整合:通过在
base.hnp规则中引入"外部 HNP 合入"阶段,实现对不同归档结构的自动识别与映射,最终统一收敛到项目内的sysroot目录布局 - ⚡ 增量构建机制:
- 通过
$(EXTERNAL_HNP)依赖,实现新增外部包时的自动重新构建 - 通过
check-pkgs机制,实现PKGS变量改变时的自动重新构建 - 无需手动操作,修改外部包或内部包列表后,直接执行
create-hnp.sh即可自动重新构建
- 通过
- 🍎 兼容性保障:优先使用
ditto解压,确保在 macOS 平台上能够正确处理所有 ZIP 格式的 HNP 包,包括有 volume label 问题的包 - 📦 体积控制:合入后再次清理冗余文档,有效控制包体积
- 🔗 无缝衔接:与现有流水线无缝衔接,便于后续维护与扩展
- 🛡️ 健壮性:增强的错误处理和权限管理,确保构建过程的稳定性和运行时的一致性
- 🧠 智能检测:自动检测外部包和内部包列表的变化,确保构建产物始终与配置保持一致
📚 相关资源
- 📝 Makefile 实现:
build-hnp/Makefile - 📦 外部 HNP 包目录:
external-hnp/ - 🔧 构建脚本:
create-hnp.sh - 📋 产物目录:
entry/hnp/$(OHOS_ABI)/
更多推荐




所有评论(0)