通过开源鸿蒙终端工具Termony完成Zlib 命令行工具构建过程深度解读
本文详细记录了在 aarch64/arm64-v8a 架构下构建 Zlib 1.3.1 的完整流程。通过 create-hnp.sh 脚本启动构建,展示了从环境配置、源码下载、编译安装到产物验证的全过程。重点包括:构建命令 OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh 的执行细节,Zlib 包的 Autotools 配置参数,关键构
·
本文记录使用命令 OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh 构建 Zlib 1.3.1 的完整过程,包括环境、构建链路、关键日志、常见问题与解决方案、产物验证与重建方法,便于复现与运维。
📖 Zlib 简介
Zlib 是一个广泛使用的压缩库,提供了 DEFLATE 压缩算法的实现。它是许多应用程序和系统的基础组件,被广泛用于文件压缩、网络传输、数据库存储等场景。Zlib 是 gzip 格式的基础,也是 HTTP 压缩的标准实现。
🎯 Zlib 的作用与重要性
Zlib 是现代软件生态中压缩处理的核心组件,提供了:
- DEFLATE 压缩算法:高效的压缩和解压缩功能
- gzip 格式支持:与 gzip 工具兼容的压缩格式
- 流式压缩:支持流式压缩和解压缩,适合大文件处理
- 内存压缩:支持内存中的压缩和解压缩操作
- 开发库:提供
libz库供应用程序使用 - 广泛兼容性:被几乎所有主流软件和系统使用
🔧 Zlib 核心特性
1. 压缩算法
- DEFLATE 算法:结合了 LZ77 算法和霍夫曼编码
- 压缩级别:支持 0-9 的压缩级别(0=无压缩,9=最大压缩)
- 压缩格式:支持 zlib、gzip、raw deflate 格式
2. 性能特点
- 快速压缩:在压缩速度和压缩比之间取得良好平衡
- 快速解压:解压速度通常比压缩速度快
- 内存效率:内存占用小,适合嵌入式系统
3. 应用场景
- 文件压缩:gzip、zip 等工具的基础
- 网络传输:HTTP 压缩、FTP 压缩等
- 数据库存储:数据库压缩存储
- 游戏开发:资源文件压缩
- 嵌入式系统:固件压缩、日志压缩等
4. API 特性
- 流式 API:
z_stream结构支持流式压缩 - 简单 API:
compress/uncompress函数提供简单接口 - 文件 API:
gzopen/gzread/gzwrite等文件操作函数 - 错误处理:完善的错误码和错误处理机制
🚀 构建入口与环境
- 📝 执行命令:
OHOS_ARCH=aarch64 OHOS_ABI=arm64-v8a sh ./create-hnp.sh - 🔧 入口脚本:
create-hnp.sh- 检查必需的环境变量
OHOS_ARCH和OHOS_ABI - 导出
LC_CTYPE、TOOL_HOME、OHOS_SDK_HOME - 执行
make -C build-hnp
- 检查必需的环境变量
- 📦 顶层构建:
build-hnp/MakefilePKGS变量定义需要构建的包列表(包含zlib)- 通过
check-pkgs机制自动检测PKGS变化并触发重新构建 - 自动合并
external-hnp目录下的外部 HNP 包 base.hnp依赖所有包的.stamp和外部 HNP 包- 总目标
all: copy,打包base.hnp并拷贝到entry/hnp/$(OHOS_ABI)
⚙️ Zlib 包的构建配置
- 📁 包目录:
build-hnp/zlib/Makefile- 继承通用规则:
include ../utils/Makefrag - 源地址:
https://zlib.net/zlib-1.3.1.tar.gz - 版本:
1.3.1
- 继承通用规则:
- ⚙️ Autotools 配置参数:
--prefix=$(PREFIX)- 安装前缀(/data/app/base.org/base_1.0)--enable-shared- 构建共享库- 注意:zlib 使用自定义的 configure 脚本,不是标准的 Autotools
- 🔨 构建流程:
- 下载源码包(支持多镜像回退)
- 解包并进入
temp/zlib-1.3.1目录 - 运行
./configure配置构建系统 - 使用
make -j $(nproc)并行编译 - 使用
make install安装 - 执行 ELF strip 减小体积
- 复制到
../sysroot
- 🔧 通用工具链与路径:
build-hnp/utils/MakefragCC/CXX/LD/AR/RANLIB/...均指向 OHOS SDK 的 LLVM 工具链- 下载支持多镜像回退:
wget→curl,主镜像失败时自动尝试备用镜像
📋 关键日志与过程节点
- 📥 下载与解包:
- 从
zlib.net下载zlib-1.3.1.tar.gz(约 1.4MB) - 完成解包并进入
temp/zlib-1.3.1目录 - 下载规则支持多镜像回退:
wget→curl兜底
- 从
- ⚙️ 配置阶段:
- 运行
./configure --prefix=... --enable-shared - zlib 使用自定义的 configure 脚本,检测系统特性
- 配置成功,生成
Makefile和构建配置
- 运行
- 🔨 编译与安装:
- 使用
make -j $(nproc)并行编译 - 成功编译生成
libz.so.1.3.1、libz.a和头文件 - 使用
make install安装到临时前缀 - 执行
llvm-strip剥离共享库符号 - 复制到
../sysroot
- 使用
- 📦 打包:
- 完成
base.hnp重打包,拷贝产物到entry/hnp/arm64-v8a/ - Zlib 库已成功打包到
base.hnp中
- 完成
✅ 产物验证
📦 检查打包文件
ls build-hnp/base.hnp # 应存在
ls entry/hnp/arm64-v8a/*.hnp # 应包含 base.hnp 与 base-public.hnp
🔍 检查库文件
# 检查 zlib 库
ls -lh build-hnp/sysroot/lib/libz.so* build-hnp/sysroot/lib/libz.a
file build-hnp/sysroot/lib/libz.so.1.3.1
# 检查头文件
ls -lh build-hnp/sysroot/include/zlib.h build-hnp/sysroot/include/zconf.h
# 检查 pkg-config 文件
ls -lh build-hnp/sysroot/lib/pkgconfig/zlib.pc
cat build-hnp/sysroot/lib/pkgconfig/zlib.pc
✅ 构建验证结果:
- ✅ Zlib 库已成功安装:
libz.so.1.3.1(89K) - 主库文件libz.so.1- 版本符号链接libz.so- 通用符号链接libz.a(118K) - 静态库
- ✅ 文件类型:ELF 64-bit LSB shared object, ARM aarch64
- ✅ 头文件已安装:
zlib.h(95K)、zconf.h(17K) - ✅ pkg-config 文件已安装:
zlib.pc(275 bytes) - ✅ 版本信息:1.3.1
- ⚠️ 注意:Zlib 是库,不提供命令行工具,需要通过编程接口使用
💻 终端中执行的示例命令
📦 Zlib 编程接口使用
1. 基本压缩和解压缩(C 语言)
#include <stdio.h>
#include <zlib.h>
#include <string.h>
int main() {
const char *source = "Hello, Zlib! This is a test string.";
unsigned long sourceLen = strlen(source) + 1;
unsigned long destLen = compressBound(sourceLen);
unsigned char *dest = (unsigned char *)malloc(destLen);
// 压缩
if (compress(dest, &destLen, (unsigned char *)source, sourceLen) != Z_OK) {
fprintf(stderr, "Compression failed\n");
return 1;
}
printf("Original size: %lu bytes\n", sourceLen);
printf("Compressed size: %lu bytes\n", destLen);
printf("Compression ratio: %.2f%%\n",
(1.0 - (double)destLen / sourceLen) * 100);
// 解压缩
unsigned char *uncompressed = (unsigned char *)malloc(sourceLen);
unsigned long uncompressedLen = sourceLen;
if (uncompress(uncompressed, &uncompressedLen, dest, destLen) != Z_OK) {
fprintf(stderr, "Decompression failed\n");
return 1;
}
printf("Decompressed: %s\n", uncompressed);
free(dest);
free(uncompressed);
return 0;
}
2. 流式压缩(C 语言)
#include <stdio.h>
#include <zlib.h>
#include <string.h>
int compress_file(const char *source_file, const char *dest_file) {
FILE *source = fopen(source_file, "rb");
gzFile dest = gzopen(dest_file, "wb");
if (!source || !dest) {
if (source) fclose(source);
if (dest) gzclose(dest);
return 1;
}
char buffer[1024];
int bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
if (gzwrite(dest, buffer, bytes_read) != bytes_read) {
fclose(source);
gzclose(dest);
return 1;
}
}
fclose(source);
gzclose(dest);
return 0;
}
int decompress_file(const char *source_file, const char *dest_file) {
gzFile source = gzopen(source_file, "rb");
FILE *dest = fopen(dest_file, "wb");
if (!source || !dest) {
if (source) gzclose(source);
if (dest) fclose(dest);
return 1;
}
char buffer[1024];
int bytes_read;
while ((bytes_read = gzread(source, buffer, sizeof(buffer))) > 0) {
if (fwrite(buffer, 1, bytes_read, dest) != bytes_read) {
gzclose(source);
fclose(dest);
return 1;
}
}
gzclose(source);
fclose(dest);
return 0;
}
3. 使用 pkg-config 编译
# 编译使用 Zlib 的程序
gcc -o program program.c $(pkg-config --cflags --libs zlib)
# 查看 Zlib 版本
pkg-config --modversion zlib
# 查看编译标志
pkg-config --cflags zlib
# 查看链接标志
pkg-config --libs zlib
4. 使用 gzip 工具(依赖 zlib)
# 压缩文件
gzip file.txt # 生成 file.txt.gz
# 解压文件
gunzip file.txt.gz
# 或
gzip -d file.txt.gz
# 压缩并保留原文件
gzip -k file.txt
# 显示压缩信息
gzip -l file.txt.gz
# 压缩级别(1-9,默认 6)
gzip -1 file.txt # 最快压缩
gzip -9 file.txt # 最大压缩
# 压缩到标准输出
gzip -c file.txt > file.txt.gz
# 从标准输入压缩
cat file.txt | gzip > file.txt.gz
# 解压到标准输出
gunzip -c file.txt.gz
# 或
zcat file.txt.gz
5. 使用其他依赖 zlib 的工具
# 使用 curl 进行 HTTP 压缩传输(如果 curl 支持 zlib)
curl -H "Accept-Encoding: gzip" https://example.com
# 使用 tar 配合 gzip 压缩目录
tar czf archive.tar.gz directory/
# 解压 tar.gz 文件
tar xzf archive.tar.gz
# 查看 tar.gz 文件内容
tar tzf archive.tar.gz
# 使用 zip 工具(如果支持 zlib)
zip -r archive.zip directory/
unzip archive.zip
6. 压缩级别示例
#include <zlib.h>
// 设置压缩级别(0-9)
int compress_with_level(unsigned char *dest, unsigned long *destLen,
const unsigned char *source, unsigned long sourceLen,
int level) {
z_stream stream;
int err;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
stream.next_in = (unsigned char *)source;
stream.avail_in = sourceLen;
stream.next_out = dest;
stream.avail_out = *destLen;
err = deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
deflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = deflateEnd(&stream);
return err;
}
7. 错误处理示例
#include <stdio.h>
#include <zlib.h>
#include <string.h>
const char *zlib_error_string(int err) {
switch (err) {
case Z_OK: return "OK";
case Z_STREAM_END: return "Stream end";
case Z_NEED_DICT: return "Need dictionary";
case Z_ERRNO: return "File error";
case Z_STREAM_ERROR: return "Stream error";
case Z_DATA_ERROR: return "Data error";
case Z_MEM_ERROR: return "Memory error";
case Z_BUF_ERROR: return "Buffer error";
case Z_VERSION_ERROR: return "Version error";
default: return "Unknown error";
}
}
int main() {
const char *source = "test data";
unsigned long sourceLen = strlen(source) + 1;
unsigned long destLen = compressBound(sourceLen);
unsigned char *dest = (unsigned char *)malloc(destLen);
int err = compress(dest, &destLen, (unsigned char *)source, sourceLen);
if (err != Z_OK) {
fprintf(stderr, "Compression error: %s\n", zlib_error_string(err));
free(dest);
return 1;
}
printf("Compression successful\n");
free(dest);
return 0;
}
8. 实际应用示例
// 压缩日志文件
#include <stdio.h>
#include <zlib.h>
int compress_log(const char *log_file) {
FILE *source = fopen(log_file, "rb");
if (!source) return 1;
char gz_file[256];
snprintf(gz_file, sizeof(gz_file), "%s.gz", log_file);
gzFile dest = gzopen(gz_file, "wb9"); // 级别 9,最大压缩
if (!dest) {
fclose(source);
return 1;
}
char buffer[8192];
int bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
if (gzwrite(dest, buffer, bytes_read) != bytes_read) {
fclose(source);
gzclose(dest);
return 1;
}
}
fclose(source);
gzclose(dest);
return 0;
}
9. 内存压缩示例
#include <stdio.h>
#include <zlib.h>
#include <stdlib.h>
#include <string.h>
int main() {
// 原始数据
const char *data = "This is a test string for compression. "
"It contains multiple words and sentences. "
"The goal is to demonstrate zlib compression.";
unsigned long dataLen = strlen(data) + 1;
// 压缩
unsigned long compressedLen = compressBound(dataLen);
unsigned char *compressed = (unsigned char *)malloc(compressedLen);
if (compress(compressed, &compressedLen,
(unsigned char *)data, dataLen) != Z_OK) {
fprintf(stderr, "Compression failed\n");
free(compressed);
return 1;
}
printf("Original: %lu bytes\n", dataLen);
printf("Compressed: %lu bytes\n", compressedLen);
printf("Ratio: %.2f%%\n",
(1.0 - (double)compressedLen / dataLen) * 100);
// 解压缩
unsigned long decompressedLen = dataLen;
unsigned char *decompressed = (unsigned char *)malloc(decompressedLen);
if (uncompress(decompressed, &decompressedLen,
compressed, compressedLen) != Z_OK) {
fprintf(stderr, "Decompression failed\n");
free(compressed);
free(decompressed);
return 1;
}
printf("Decompressed: %s\n", decompressed);
free(compressed);
free(decompressed);
return 0;
}
10. 流式处理大文件
#include <stdio.h>
#include <zlib.h>
int compress_large_file(const char *input, const char *output) {
FILE *in = fopen(input, "rb");
gzFile out = gzopen(output, "wb6"); // 级别 6,平衡压缩
if (!in || !out) {
if (in) fclose(in);
if (out) gzclose(out);
return 1;
}
unsigned char buffer[64 * 1024]; // 64KB 缓冲区
int bytes_read;
unsigned long total_in = 0, total_out = 0;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), in)) > 0) {
total_in += bytes_read;
int written = gzwrite(out, buffer, bytes_read);
if (written != bytes_read) {
fclose(in);
gzclose(out);
return 1;
}
total_out += written;
}
printf("Compressed %lu bytes to %lu bytes\n", total_in, total_out);
fclose(in);
gzclose(out);
return 0;
}
🧪 功能验证脚本
#!/bin/bash
# Zlib 库验证脚本
ZLIB_LIB="build-hnp/sysroot/lib"
ZLIB_INCLUDE="build-hnp/sysroot/include"
echo "=== Zlib 库验证 ==="
# 检查库文件
echo ""
echo "=== 库文件验证 ==="
for lib in libz.so.1.3.1 libz.a; do
if [ -f "$ZLIB_LIB/$lib" ]; then
echo "✓ $lib: 存在"
file "$ZLIB_LIB/$lib"
echo "文件大小: $(ls -lh "$ZLIB_LIB/$lib" | awk '{print $5}')"
else
echo "✗ $lib: 缺失"
fi
done
# 检查符号链接
for link in libz.so libz.so.1; do
if [ -L "$ZLIB_LIB/$link" ]; then
echo "✓ $link: 符号链接 -> $(readlink "$ZLIB_LIB/$link")"
else
echo "✗ $link: 缺失"
fi
done
# 检查头文件
echo ""
echo "=== 头文件验证 ==="
for header in zlib.h zconf.h; do
if [ -f "$ZLIB_INCLUDE/$header" ]; then
echo "✓ $header: 存在"
echo " 文件大小: $(ls -lh "$ZLIB_INCLUDE/$header" | awk '{print $5}')"
else
echo "✗ $header: 缺失"
fi
done
# 检查 pkg-config 文件
echo ""
echo "=== pkg-config 验证 ==="
if [ -f "build-hnp/sysroot/lib/pkgconfig/zlib.pc" ]; then
echo "✓ zlib.pc: 存在"
cat build-hnp/sysroot/lib/pkgconfig/zlib.pc
else
echo "✗ zlib.pc: 缺失"
fi
# 注意:Zlib 是库,不提供命令行工具
echo ""
echo "注意:Zlib 是压缩库,不提供命令行工具"
echo "需要通过编程接口使用,或使用依赖 zlib 的工具(如 gzip)"
🐛 常见问题与处理
❌ 问题 1:下载失败
- 🔍 症状:从
zlib.net下载zlib-1.3.1.tar.gz失败 - 🔎 原因:网络问题或服务器不可达
- ✅ 解决方法:
- 使用通用下载规则中的
curl兜底机制 - 下载失败后清理坏归档再重试:
rm -f build-hnp/zlib/download/zlib-1.3.1.tar.gz - 位置:
build-hnp/utils/Makefrag(通用下载规则)
- 使用通用下载规则中的
❌ 问题 2:交叉编译工具链问题
- 🔍 症状:
configure或编译失败,提示找不到编译器或工具 - 🔎 原因:环境变量未正确设置或工具链路径不正确
- ✅ 解决方法:
- 确保
OHOS_SDK_HOME环境变量正确设置 - 确保使用
create-hnp.sh脚本执行构建(自动设置环境变量) - zlib 的 configure 脚本会自动检测交叉编译器
- 位置:
build-hnp/zlib/Makefile(使用define_autotools_package宏)
- 确保
❌ 问题 3:静态/共享库选择
- 🔍 症状:不确定应该构建静态库还是共享库
- 🔎 原因:不同应用场景需要不同的库类型
- ✅ 解决方法:
- 当前配置:
--enable-shared(构建共享库) - 如果需要静态库,可以添加
--enable-static - 如果需要仅静态库,可以使用
--disable-shared --enable-static - 位置:
build-hnp/zlib/Makefile:8
- 当前配置:
❌ 问题 4:链接错误
- 🔍 症状:编译使用 zlib 的程序时出现链接错误
- 🔎 原因:未正确链接 zlib 库
- ✅ 解决方法:
- 使用 pkg-config:
gcc -o program program.c $(pkg-config --cflags --libs zlib) - 手动链接:
gcc -o program program.c -lz - 确保库路径正确:
export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH
- 使用 pkg-config:
❌ 问题 5:版本兼容性
- 🔍 症状:使用不同版本的 zlib 编译的程序不兼容
- 🔎 原因:zlib 的 ABI 在不同版本间可能不兼容
- ✅ 解决方法:
- 确保使用相同版本的 zlib 编译和运行
- 检查 zlib 版本:
pkg-config --modversion zlib - 使用符号版本控制确保兼容性
🔄 重建与扩展
-
🔧 重建单包:
make -C build-hnp rebuild-zlib # 触发子包重新编译并刷新 .stamp -
🧹 清理:
make -C build-hnp clean # 清理 sysroot、所有 .stamp 和 PKGS_MARKER -
📦 扩展:Zlib 是许多应用程序的基础依赖(如
curl、libarchive、git等) -
🔄 自动重建机制:
- 修改
PKGS后,check-pkgs会自动检测变化并触发重新构建 - 新增外部 HNP 包到
external-hnp目录后,会自动合并到base.hnp
- 修改
💡 实践建议
- 🔧 压缩级别选择:根据应用场景选择合适的压缩级别
- 实时场景:级别 1-3(快速压缩)
- 存储场景:级别 6-9(高压缩比)
- 默认场景:级别 6(平衡)
- 🚀 性能优化:对于大文件,使用流式 API 可以显著减少内存占用
- 📦 依赖管理:Zlib 是许多包的基础依赖,确保正确构建和安装
- 🔗 压缩栈建设:建议与其他压缩库(
zstd/lz4/xz)一起构建,随后构建libarchive - 🌐 工具使用:虽然 zlib 本身不提供命令行工具,但可以使用依赖 zlib 的工具(如
gzip、curl等)
📝 结论与建议
- ✅ 本次已在 aarch64 环境下完成 Zlib 1.3.1 的交叉编译与打包,zlib 库已安装到
sysroot并纳入 HNP 包。 - 💡 为保证构建稳定:
- 固定可靠的上游镜像,避免下载阶段随机失败(已实现自动回退机制)
- 使用 Autotools 构建系统,支持共享库和静态库
- zlib 是库,不提供命令行工具,需要通过编程接口使用
- 利用
check-pkgs机制自动检测包列表变化,无需手动清理 - 将 Zlib 与其他压缩库(
zstd/lz4/xz)一并构建,随后构建libarchive,提升归档/解压生态的完整性 - 根据后续依赖选择静态或共享产物,兼顾体积与兼容性
📚 以上为 Zlib 构建的深度解读与实践记录。
更多推荐



所有评论(0)