开源鸿蒙终端工具Termony增加外部HNP包合入base.hnp的设计与实现实战教程

本文面向将 external-hnp 目录下的已构建 HNP 包,按照项目现有打包规则,自动合入到最终产物 base.hnp 中。教程覆盖设计目标、格式差异、Makefile 改造、合入策略、验证方法与常见问题排查,确保在同一套 HNP 流水线下实现稳定、可维护的外部包整合。

🎯 目标与范围

  • 🎯 目标 :在完成 build-hnp 内所有包的构建后,自动将 external-hnp/*.hnp 的内容合并进 build-hnp/sysroot,并随 base.hnp 一并打包分发。
  • 📋 范围 :兼容三类外部 HNP 格式:
    1. 📁 标准 sysroot/ 结构 :归档内顶层为 sysroot/(与本工程一致)
    2. 📂 usr/ 目录结构 :归档内顶层为供应商自定义路径,实际内容位于其中的 usr/(例如:dog_1.0.0/usr/bin/dogjq_1.7/usr/bin/jqwhois_5.5.10/usr/bin/whois
    3. 🗂️ 顶层标准目录结构 :归档内顶层为供应商自定义路径,但直接在顶层包含标准目录(例如:autoconf_1.0.0/bin/autoconf_1.0.0/share/icu_1.0.0/lib/

📚 现有打包规则回顾

🔧 Makefile 结构

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/.stampbash/.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 即可自动重新构建

📦 打包流程

  1. 🧹 清理阶段 :删除 sysroot/share/{man,doc,info} 减小体积
  2. 🔧 工具注入 :复制 pbcopy/pbpaste 与工具链运行时对象
  3. 📥 外部包合入 :合并 external-hnp 目录下的所有 HNP 包到 sysroot
  4. 🔐 权限设置:确保二进制文件具有执行权限
  5. 🧹 再次清理:删除外部包可能引入的文档文件
  6. 📦 打包 :使用 zip -r base.hnp sysroot 创建最终包
  7. 📋 拷贝 :将 base.hnp 复制到 entry/hnp/$(OHOS_ABI),同时生成 base-public.hnp

🎨 合入策略设计

⚡ 处理优先级

base.hnp 规则中,完成工具注入后、打包前执行外部 HNP 合入,按以下优先级处理:

  1. 🥇 优先处理 sysroot/ 目录 :若归档内存在 sysroot/,则直接合并其内容到当前 sysroot/ 根目录(避免出现 sysroot/sysroot 嵌套)
  2. 🥈 处理 usr/ 目录结构 :若归档内不存在 sysroot/,但存在一个或多个 usr/ 目录,则将其中的 usr/binusr/libusr/includeusr/shareusr/lib/pkgconfig 映射合入到当前 sysroot/binsysroot/libsysroot/includesysroot/sharesysroot/lib/pkgconfig
  3. 🥉 处理顶层标准目录结构 :若两者均不存在,检查顶层目录(如 包名/bin/包名/lib/ 等)中是否存在标准目录(binlibincludeshare),如果存在,将这些目录的内容合并到 sysroot 对应目录
  4. 🔄 兜底策略 :若以上情况均不匹配,则将归档内所有内容合并到当前 sysroot/

🗺️ 目录映射规则

  • usr/binsysroot/bin
  • usr/libsysroot/lib
  • usr/includesysroot/include
  • usr/sharesysroot/share
  • usr/lib/pkgconfigsysroot/lib/pkgconfig
  • 顶层 bin/lib/include/share/ 等目录同样映射到 sysroot 对应目录

🧹 清理策略

  • 🧹 合入前清理 :删除 sysroot/share/{man,doc,info} 减小体积
  • 🧹 合入后再次清理 :外部包可能包含大量手册与文档,合并后再次删除 sysroot/share/{man,doc,info} 缩小体积

💻 具体实现

🔧 Makefile 修改

📝 修改文件build-hnp/Makefile

✨ 关键修改点

  1. 📦 添加外部包依赖检测
makefile 复制代码
EXTERNAL_HNP=$(wildcard ../external-hnp/*.hnp)
  1. ✅ 添加 PKGS 变化检测
makefile 复制代码
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)
  1. 🔗 更新 base.hnp 依赖
makefile 复制代码
base.hnp: check-pkgs $(STAMP) utils/pbcopy utils/pbpaste utils/empty.a Makefile $(EXTERNAL_HNP)
  1. 📥 外部包合入逻辑
makefile 复制代码
# 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

✨ 关键改进点

  1. 🔄 自动依赖检测

    • 使用 EXTERNAL_HNP=$(wildcard ../external-hnp/*.hnp) 自动发现所有外部 HNP 包
    • $(EXTERNAL_HNP) 添加到 base.hnp 的依赖中,实现增量构建
    • 使用 check-pkgs .PHONY 目标检测 PKGS 变量的变化,如果改变则删除 base.hnp 强制重新构建
  2. 🍎 优先使用 ditto 解压

    • 在 macOS 上优先使用 ditto 命令解压,能够正确处理所有 ZIP 格式,包括有 "volume label" 问题的包
    • 如果系统不支持 ditto,则回退到 unzip
  3. 📁 支持三种包结构

    • 标准 sysroot/ 结构:直接合并
    • usr/ 目录结构:将 usr/binusr/lib 等映射到 sysroot/binsysroot/lib
    • 顶层标准目录结构:检查顶层目录中的 bin/lib/include/share/ 等,合并到 sysroot 对应目录
  4. 🧠 智能目录映射

    • 使用 merged 标志跟踪是否成功合并了标准目录
    • 只有在完全没有标准目录时才使用兜底策略,避免将整个包目录复制到 sysroot/ 根目录
  5. 🛡️ 增强错误处理

    • 为所有关键操作添加 2>/dev/null || true,确保单个包失败不影响整体流程
  6. 🔐 确保文件权限

    • 合入后统一为 sysroot/bin 下的所有文件添加执行权限,避免运行时出现权限问题
  7. 📝 详细日志输出

    • 添加更详细的处理日志,包括目录发现和合并过程,便于问题排查

✅ 验证方法

1. 🚀 执行全量构建

bash 复制代码
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

2. 🔍 检查合入是否生效

📋 典型外部包结构示例

  • external-hnp/dog.hnpdog_1.0.0/usr/bin/dog
  • external-hnp/autoconf.hnpautoconf_1.0.0/bin/autoconf
  • external-hnp/icu.hnpicu_1.0.0/lib/libicu*.so

✅ 验证映射到 sysroot

bash 复制代码
# 检查二进制文件是否在正确位置(应该在 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. 📦 验证打包结果

bash 复制代码
# 检查打包产物
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. 🔗 验证依赖关系

bash 复制代码
# 检查 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. 🎮 运行时验证(在应用启动后)

bash 复制代码
# 在终端中执行外部包命令
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 包命令(如 dogjqwhois 等)提示 command not found

🔎 根本原因

  1. 📦 解压工具兼容性问题 :在 macOS 上,unzip 命令遇到某些 HNP 包的 "volume label" 问题时,会显示 "skipping" 但实际上跳过了文件解压,导致临时目录为空,后续复制操作失败
  2. 📂 路径处理问题 :早期实现中使用 while read 在子shell中执行,可能导致复制操作失败
  3. 🔐 文件权限问题:二进制文件可能缺少执行权限

✅ 解决方案

  1. 🍎 优先使用 ditto 解压 :在 macOS 上,ditto 命令能够正确处理所有 ZIP 格式的 HNP 包,包括有 "volume label" 问题的包。实现中优先检测并使用 ditto,如果不可用则回退到 unzip
  2. 📋 简化复制逻辑 :直接使用 cp -a "$$ud/$$comp/." "sysroot/$$comp/" 复制整个目录内容,避免通配符匹配失败的问题
  3. 🔐 确保文件权限 :在合入后统一执行 find sysroot/bin -type f -exec chmod +x {} \; 确保所有二进制文件具有执行权限

✅ 验证方法

bash 复制代码
# 检查文件是否在正确位置
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" 警告,并且实际上跳过了文件解压,导致临时目录为空。

✅ 解决方案

  • 🍎 优先使用 dittoditto 是 macOS 系统自带的解压工具,能够正确处理所有 ZIP 格式,包括有 volume label 问题的包
  • 实现中检测系统是否支持 ditto,如果支持则优先使用,否则回退到 unzip

🔍 排查方法

bash 复制代码
# 方法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/binusr/lib 等映射到 sysroot/binsysroot/lib
  • 对于顶层标准目录结构:检查顶层目录中是否存在 bin/lib/include/share/ 等标准目录,如果存在,将这些目录的内容合并到 sysroot 对应目录
  • 验证复制操作确实将文件复制到了目标位置:ls -la build-hnp/sysroot/bin | grep -E "(dog|autoconf)"

7. 📂 顶层目录结构未正确映射

🔍 症状 :某些外部包(如 autoconf.hnpautomake.hnpicu.hnp)的内容没有被正确合并到 sysroot 对应目录,而是整个包目录被复制到了 sysroot/ 根目录下。

🔎 原因 :这些包的目录结构是 包名/bin/包名/lib/ 等,而不是 包名/usr/bin/,之前的实现只处理了 usr/ 目录结构的情况。

✅ 解决方案

  • 在找不到 usr/ 目录时,检查顶层目录中是否存在标准目录(binlibincludeshare
  • 如果存在,将这些目录的内容合并到 sysroot 对应目录,而不是复制整个包目录
  • 使用 merged 标志跟踪是否成功合并了标准目录,只有在完全没有标准目录时才使用兜底策略

8. 🔄 新增外部包后未自动重新构建

🔍 症状 :在 external-hnp 目录下新增了 .hnp 文件(如 icu.hnpless.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 会自动重新构建

✅ 验证方法

bash 复制代码
# 检查依赖关系
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
  • ✨ 无需手动操作:新增外部包后,直接执行:
bash 复制代码
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

✅ PKGS 改变后的自动重建

  • 🔄 自动检测base.hnp 的依赖中包含 check-pkgs,每次构建时都会检查 PKGS 变量是否改变
  • ⚡ 自动重建 :当 PKGS 变量改变时(例如添加或删除包),check-pkgs 会检测到变化并删除 base.hnp,强制重新构建
  • ✨ 无需手动操作 :修改 PKGS 后,直接执行:
bash 复制代码
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

⚙️ 工作原理

  1. check-pkgs 是一个 .PHONY 目标,每次构建时都会执行
  2. 将当前的 PKGS 值写入 .pkgs-$(OHOS_ARCH).tmp 临时文件
  3. 如果 .pkgs-$(OHOS_ARCH) 文件存在,比较新旧值是否相同
  4. 如果不同,说明 PKGS 改变了,执行清理操作:
    • 删除 base.hnp 强制重新构建
    • 遍历旧的 PKGS 列表,删除不再需要的 .stamp 文件(从 PKGS 中移除的包)
    • 遍历新的 PKGS 列表,删除新添加的包的 .stamp 文件(强制重新构建)
  5. 将临时文件重命名为正式文件,记录当前的 PKGS

✨ 关键改进

  • 🧹 清理旧的 .stamp 文件 :当包从 PKGS 中移除时,删除对应的 .stamp 文件,避免 make 误判
  • 🔄 清理新包的 .stamp 文件 :当包添加到 PKGS 时,删除对应的 .stamp 文件,强制重新构建并复制到 sysroot

📋 示例场景

  • ➕ 添加包PKGSbash 改为 gettext bash
    • check-pkgs 检测到变化
    • 删除 base.hnpgettext/.stamp(新包)
    • 重新构建时会构建 gettextbash 两个包,并复制到 sysroot
  • ➖ 删除包PKGSgettext bash 改为 bash
    • check-pkgs 检测到变化
    • 删除 base.hnpgettext/.stamp(旧包)
    • 重新构建时只构建 bash 包,sysroot 中不再包含 gettext 的内容
  • 🔄 重新排序PKGSbash gettext 改为 gettext bash
    • 虽然包相同但顺序不同,check-pkgs 也会检测到变化
    • 删除 base.hnp 和所有相关 .stamp 文件
    • 重新构建所有包,确保 sysroot 内容与 PKGS 一致

📦 仅重新执行打包与合入

在所有包已构建的前提下,直接调用:

bash 复制代码
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

🔧 重建单个内部包

若需要只重建某一包,再执行对应 rebuild-<pkg> 后再次打包;例如:

bash 复制代码
make -C build-hnp rebuild-yyjson
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

🔄 强制重新构建所有外部包

如果需要强制重新合入所有外部包(例如修改了合入逻辑),可以删除 base.hnp 后重新构建:

bash 复制代码
rm -f build-hnp/base.hnp
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

🧹 清理构建产物

如果需要完全重新构建,可以清理所有构建产物:

bash 复制代码
make -C build-hnp clean
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh

💡 实现细节与最佳实践

🛠️ 解压工具选择

  • 🍎 macOS 平台 :优先使用 ditto,能够正确处理所有 ZIP 格式,包括有 volume label 问题的包
  • 🐧 其他平台 :使用 unzip 作为主要解压工具
  • 🛡️ 错误处理:如果主要解压工具失败,自动尝试备用工具

📁 目录结构识别

  1. 🥇 优先检查 sysroot/:如果存在,直接合并,避免嵌套
  2. 🥈 其次检查 usr/ :如果存在,映射标准目录到 sysroot
  3. 🥉 最后检查顶层标准目录 :如果存在 bin/lib/ 等,合并到对应位置
  4. 🔄 兜底策略:只有在完全没有标准目录时才使用

🔐 文件权限管理

  • ✅ 合入后统一设置 :使用 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)/
相关推荐
NocoBase7 小时前
6 个最佳开源 AI 仪表盘工具
低代码·开源·数据可视化
用户47949283569158 小时前
我只是给Typescript提个 typo PR,为什么还要签协议?
前端·后端·开源
国服第二切图仔10 小时前
DevUI Design中后台产品开源前端解决方案之Carousel 走马灯组件使用指南
前端·开源
遇到困难睡大觉哈哈10 小时前
HarmonyOS —— Remote Communication Kit 拦截器(Interceptor)高阶定制能力笔记
笔记·华为·harmonyos
遇到困难睡大觉哈哈11 小时前
HarmonyOS —— Remote Communication Kit 定制处理行为(ProcessingConfiguration)速记笔记
笔记·华为·harmonyos
氤氲息12 小时前
鸿蒙 ArkTs 的WebView如何与JS交互
javascript·交互·harmonyos
遇到困难睡大觉哈哈12 小时前
HarmonyOS支付接入证书准备与生成指南
华为·harmonyos
IvorySQL12 小时前
瀚高硬核助力 PG 社区:Postgres 19 迎来并行 TID 范围扫描,速度提升 3 倍
数据库·postgresql·开源
赵浩生12 小时前
鸿蒙技术干货10:鸿蒙图形渲染基础,Canvas绘图与自定义组件实战
harmonyos