基於 OpenHarmony 的 libzip 適配與交叉編譯實踐:構建系統、依賴管理與 HNP 打包全解析
前言
推動 PC 端 OpenHarmony 生態快速完善的過程中,大量三方開源庫需要完成適配、編譯鏈路打通與 HNP 組件化發佈,而 libzip 則是文件壓縮類庫中最基礎、使用最廣的工具之一。無論是文件管理工具、更新包解析、應用安裝器,還是後台資源解壓,幾乎都會依賴 ZIP 能力。因此,將 libzip 成功遷移到 OpenHarmony 不僅是單一庫的適配,更是構建完整開發環境的重要一環。
本文基於實際的 PC 端鴻蒙開發環境,完整演示 libzip 的 交叉編譯流程、CMake 構建配置、依賴聲明、HNP 元數據定義、產物安裝目錄處理 以及最終的 HNP 打包產出流程。同時也補充了 GitCode 託管與適配倉庫維護方法,幫助開發者從零到一完成一個第三方庫在鴻蒙上的全流程適配。希望本文能作為你後續適配更多三方開源庫的標準模版參考。
libzip 鴻蒙適配與構建全流程指南
切換到build/code目錄,通過 Git 從指定 GitCode 倉庫地址克隆 libzip 工具的源碼,在當前目錄生成libzip文件夾存放源碼,為後續開源鴻蒙適配準備基礎源碼
# 進入build目錄下的code子目錄 cd code # 從GitCode倉庫克隆libzip工具的源碼到當前目錄,創建名為libzip的文件夾 git clone https://gitcode.com/gh_mirrors/li/libzip.git
dependency.json 配置:聲明 libzip 的鴻蒙依賴信息
在 dependency.json 配置文件中,定義 libzip 的依賴信息,指定其名稱、適配鴻蒙的 1.11.4_ohos 分支,以及對應的 GitCode 倉庫地址,供構建流程拉取指定版本的 libzip 源碼
{ "dependency": [ { "name" : "libzip", "branch" : "1.11.4_ohos", "url" : "https://gitcode.com/weixin_62765017/libzip.git" } ] }
build.sh 主構建腳本:環境初始化與鴻蒙交叉編譯配置
這是 libzip 鴻蒙適配的主構建腳本,先校驗並傳入鴻蒙 SDK 路徑,根據構建系統配置編譯工具鏈,檢查 Python 依賴並給出系統適配的安裝指引,配置編譯相關環境變量及鴻蒙編譯參數;默認進入 libzip 目錄執行專屬構建腳本,也可通過參數按 dependency.json 拉取依賴構建
#!/bin/bash
SDK_PATH=""
while [[ $# -gt 0 ]]; do
case "$1" in
--sdk)
SDK_PATH="$2"
shift 2
;;
*)
echo "Error: unknow param $1"
echo "Usage: $0 --sdk <SDK path>"
exit 1
;;
esac
done
if [ -z "$SDK_PATH" ]; then
echo "Error: SDK path must be specified with the \"--sdk\" option"
echo "Usage: $0 --sdk <SDK path>"
exit 1
fi
if [ ! -d "$SDK_PATH" ]; then
echo "Error: SDK path is not exist or no permossion: [$SDK_PATH]"
exit 2
fi
export OHOS_SDK="$SDK_PATH"
export HNP_PERFIX=
BUILD_OS=$(uname)
case $BUILD_OS in
'OpenHarmony')
echo "Build in: <$(uname -a)> by local tool chains."
export COMPILER_TOOLCHAIN=${OHOS_TOOL_CHAIN_PATH}
;;
'HarmonyOS')
echo "Build in: <$(uname -a)> by local tool chains."
export COMPILER_TOOLCHAIN=${HMOS_TOOL_CHAIN_PATH}
export HNP_PERFIX=${PWD}/hnp
;;
*)
echo "Build in: <$(uname -a)> by cross tool chains."
export COMPILER_TOOLCHAIN=${OHOS_SDK}/native/llvm/bin/
;;
esac
if [ -z "${HNP_PERFIX}" ]; then
export HNP_PERFIX="${PWD}/hnp"
fi
if [ -n "${HNP_PERFIX}" ]; then
mkdir -p "${HNP_PERFIX}"
fi
PYTHON=$(python --version)
echo "python : $PYTHON"
if [ -z "$PYTHON" ]; then
echo "You need install python in your system"
case "$BUILD_OS" in
OpenHarmony|HarmonyOS)
echo "${BUILD_OS} install by url://www.xxx.xxx.com"
;;
Linux* )
if command -v apt-get &> /dev/null; then
echo "1. sudo apt update"
echo "2. sudo apt install python3 python3-pip"
elif command -v yum &> /dev/null; then
echo "1. sudo yum install python3 python3-pip"
else
echo "Please install python3 and pip using your system's package manager."
fi
;;
Darwin*)
echo "1. Use Homebrew: brew install python"
echo "or"
echo "2. Download by python org: https://www.python.org/downloads/macos/"
;;
CYGWIN*|MINGW32*|MSYS*|MINGW*)
echo "1. Download by python org: https://www.python.org/downloads/windows/"
echo "2. Check the \"Add Python to PATH\" option during installation."
;;
*)
echo "Unable to determine the appropriate Python installation method for your system."
;;
esac
exit 1
fi
export CC=${COMPILER_TOOLCHAIN}clang && echo "CC : ${CC}"
export CXX=${COMPILER_TOOLCHAIN}clang++ && echo "CXX : ${CXX}"
export HOSTCC=${CC} && echo "HOSTCC : ${HOSTCC}"
export HOSTCXX=${CXX} && echo "HOSTCXX : ${HOSTCXX}"
export CPP=${CXX} && echo "CPP : ${CPP}"
export AS=${COMPILER_TOOLCHAIN}llvm-as && echo "AS : ${AS}"
export LD=${COMPILER_TOOLCHAIN}ld.lld && echo "LD : ${LD}"
export STRIP=${COMPILER_TOOLCHAIN}llvm-strip && echo "STRIP : ${STRIP}"
export RANLIB=${COMPILER_TOOLCHAIN}llvm-ranlib && echo "RANLIB : ${RANLIB}"
export OBJDUMP=${COMPILER_TOOLCHAIN}llvm-objdump && echo "OBJDUMP : ${OBJDUMP}"
export OBJCOPY=${COMPILER_TOOLCHAIN}llvm-objcopy && echo "OBJCOPY : ${OBJCOPY}"
export NM=${COMPILER_TOOLCHAIN}llvm-nm && echo "NM : ${NM}"
export AR=${COMPILER_TOOLCHAIN}llvm-ar && echo "AR : ${AR}"
export SYSROOT=${OHOS_SDK}/native/sysroot
export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}/usr/lib/aarch64-linux-ohos
export PKG_CONFIG_PATH=${PKG_CONFIG_SYSROOT_DIR}
export PKG_CONFIG_EXECUTABLE=${PKG_CONFIG_SYSROOT_DIR}
export HNP_TOOL=${OHOS_SDK}/toolchains/hnpcli
export CMAKE=${OHOS_SDK}/native/build-tools/cmake/bin/cmake
export TOOLCHAIN_FILE=${OHOS_SDK}/native/build/cmake/ohos.toolchain.cmake
export WORK_ROOT=${PWD}
export ARCHIVE_PATH=${WORK_ROOT}/output
export COMM_DEP_PATH=${WORK_ROOT}/deps_install
export HNP_PUBLIC_PATH=${HNP_PERFIX}/data/service/hnp/
export MAKE_QUITE_PARAM=" -s "
export CONFIGURE_QUITE_PARAM=" --quiet "
export TARGET_PLATFORM=aarch64-linux-ohos
export CFLAGS="-fPIC -D__MUSL__=1 -D__OHOS__ -fstack-protector-strong --target=${TARGET_PLATFORM} -fuse-ld=${LD} --sysroot=${SYSROOT}"
export CXXFLAGS="${CFLAGS} "
export LD_LIBRARY_PATH=${SYSROOT}/usr/lib:${LD_LIBRARY_PATH}
export LDFLAGS="${LDFLAGS} -fuse-ld=${LD} --target=${TARGET_PLATFORM} --sysroot=${SYSROOT}"
export HOST_TYPE="--host=aarch64-linux --build=aarch64-linux"
mkdir -p ${HNP_PUBLIC_PATH}
mkdir -p ${ARCHIVE_PATH}
mkdir -p code
# 默認直接構建指定目錄,除非顯式要求按 dependency.json 走
BUILD_BY_DEPENDENCY="${BUILD_BY_DEPENDENCY:-false}"
# 需要構建的組件名稱(默認構建 libzip)
SPECIFIC_DIR="${SPECIFIC_DIR:-libzip}"
if [[ "${BUILD_BY_DEPENDENCY}" == "true" ]]; then
python build_dependency.py
else
pushd "code/${SPECIFIC_DIR}"
chmod +x build_ohos.sh
./build_ohos.sh
popd
fi
hnp.json 配置:HNP 組件元信息定義
在 hnp.json 配置文件中,定義 libzip 的 HNP 配置信息,指定配置類型為 hnp-config、組件名稱和版本號,為空的 install 字段預留安裝相關配置空間,用於鴻蒙 HNP 打包時識別組件基礎信息
{ "type":"hnp-config", "name":"libzip", "version":"1.11.4", "install":{} }
build_ohos.sh:libzip 的鴻蒙平台專屬構建腳本
libzip 針對鴻蒙的專屬構建腳本,定義組件名稱版本及安裝路徑,清理並創建構建目錄;通過 CMake 配置鴻蒙編譯參數(指定工具鏈、關閉非必要功能、配置編譯器 / 鏈接器參數),編譯並安裝 libzip 到指定路徑;接着拷貝文檔和 hnp.json 配置文件,最後用 HNP 工具打包組件並生成壓縮包,完成鴻蒙適配的構建產物輸出
#!/bin/bash
set -euo pipefail
component_name="libzip"
component_version="1.11.4"
install_prefix="/usr"
export LIBZIP_INSTALL_HNP_PATH="${HNP_PUBLIC_PATH}/${component_name}.org/${component_name}_${component_version}"
echo "Install root: ${LIBZIP_INSTALL_HNP_PATH}"
mkdir -p "${LIBZIP_INSTALL_HNP_PATH}"
# 清理之前的構建
if [ -d "build" ]; then
rm -rf build
fi
mkdir -p build
# 使用 CMake 配置和構建
pushd build
${CMAKE} .. \
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" \
-DCMAKE_SYSROOT="${SYSROOT}" \
-DCMAKE_INSTALL_PREFIX="${install_prefix}" \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TOOLS=ON \
-DENABLE_OPENSSL=OFF \
-DENABLE_GNUTLS=OFF \
-DENABLE_MBEDTLS=OFF \
-DENABLE_COMMONCRYPTO=OFF \
-DENABLE_WINDOWS_CRYPTO=OFF \
-DENABLE_BZIP2=OFF \
-DENABLE_LZMA=OFF \
-DENABLE_ZSTD=OFF \
-DBUILD_REGRESS=OFF \
-DBUILD_EXAMPLES=OFF \
-DBUILD_DOC=OFF \
-DCMAKE_C_COMPILER="${CC}" \
-DCMAKE_CXX_COMPILER="${CXX}" \
-DCMAKE_C_FLAGS="${CFLAGS}" \
-DCMAKE_CXX_FLAGS="${CXXFLAGS}" \
-DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}" \
-DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}" \
-DCMAKE_STATIC_LINKER_FLAGS="${LDFLAGS}"
${CMAKE} --build . --config Release --parallel $(nproc)
DESTDIR="${LIBZIP_INSTALL_HNP_PATH}" ${CMAKE} --install . --prefix "${install_prefix}"
popd
# 安裝文檔
doc_dir="${LIBZIP_INSTALL_HNP_PATH}/usr/share/doc/${component_name}"
mkdir -p "${doc_dir}"
if [ -f "README.md" ]; then
install -m 644 README.md "${doc_dir}/"
fi
if [ -f "LICENSE" ]; then
install -m 644 LICENSE "${doc_dir}/"
fi
if [ -f "NEWS.md" ]; then
install -m 644 NEWS.md "${doc_dir}/"
fi
# 安裝 hnp.json
install -m 644 hnp.json "${LIBZIP_INSTALL_HNP_PATH}/"
pushd "${LIBZIP_INSTALL_HNP_PATH}/../"
${HNP_TOOL} pack -i "${LIBZIP_INSTALL_HNP_PATH}" -o "${ARCHIVE_PATH}/"
tar -zvcf "${ARCHIVE_PATH}/ohos_${component_name}_${component_version}.tar.gz" "${component_name}_${component_version}/"
popd
構建與打包流程:生成 HNP 產物並輸出安裝包
進入本地 build 目錄,執行主構建腳本 build.sh 並傳入鴻蒙 SDK 的 Linux 版本路徑,觸發 libzip 針對鴻蒙系統的完整構建流程,生成適配的構建產物
cd ~/build ./build.sh --sdk ~/ohos-sdk/linux
推送至 GitCode:開源共建及遠程倉庫維護流程
1、GitCode 創建代碼倉庫
2、本地 Git 關聯遠程倉庫(可能會報錯,錯誤是 Git 的安全機制檢測到倉庫目錄的所有者有問題因為是 WSL 跨系統目錄,按照提示添加安全目錄例外即可)
git config --global --add safe.directory '%(prefix)///wsl$/Ubuntu-24.04/home/weishuo/build/code/libzip'
3、拉取遠程 main 分支同步
# 拉取遠程main分支到本地(如果本地沒有main分支,會自動創建) git pull origin main
4、暫存所有本地修改和未追蹤文件
# 暫存所有本地修改(android/do.sh 等)+ 未追蹤的 hnp.json git add . # 驗證:確認無未合併路徑、所有修改已暫存 git status
5、完成合並提交
git commit -m "合併遠程main分支:以本地代碼為主,覆蓋README.md衝突"
6、強制推送本地代碼到遠程
git push -u origin main --force
libzip 鴻蒙構建安裝錯誤解決方案總覽
錯誤現象描述
在鴻蒙系統上構建 libzip 1.11.4 時,安裝階段出現以下錯誤:
Unknown argument --
Usage: cmake --install <dir> [options]
...
錯誤原因定位與觸發點分析
錯誤發生在構建腳本的安裝命令中:
${CMAKE} --install . --prefix "${install_prefix}" -- DESTDIR="${LIBZIP_INSTALL_HNP_PATH}"
CMake 3.20+ 版本不再接受 – DESTDIR= 這種參數傳遞方式
最終解決方案
修改文件:code/libzip/build_ohos.sh
修改行號:第 48 行
修改前(錯誤):
${CMAKE} --install . --prefix "${install_prefix}" -- DESTDIR="${LIBZIP_INSTALL_HNP_PATH}"
修改後(正確):
DESTDIR="${LIBZIP_INSTALL_HNP_PATH}" ${CMAKE} --install . --prefix "${install_prefix}"
修改説明
- 將 DESTDIR 從命令行參數改為環境變量
- 刪除無效的 – 分隔符
- 保持其他參數不變
構建結果驗證方法
執行構建腳本後,檢查 libzip 是否成功安裝到指定目錄:
# 查看安裝目錄 ls -la ${LIBZIP_INSTALL_HNP_PATH} # 檢查庫文件 ls -la ${LIBZIP_INSTALL_HNP_PATH}/usr/local/lib/*.a
構建與安裝的注意事項
- 此修改隻影響 CMake 3.20+ 版本的構建
- 編譯過程中的 “warning: argument unused during compilation” 是無害警告,不影響最終結果
- 修改後的命令遵循 CMake 官方推薦的環境變量傳遞方式
這個解決方案已在實際的鴻蒙系統構建中驗證通過,能夠成功完成 libzip 的構建和安裝