从零开始写 HPKBUILD:以 MediaInfo 为例的三方库鸿蒙PC适配实战

前言

很多新手拿到一个三方库想适配到鸿蒙PC,面对空白的 HPKBUILD 文件不知道从何下手。本文以 MediaInfo CLI 为例,不直接给最终代码,而是带你走一遍真实的思考过程:从搭骨架、填函数、跑构建、排错误,最终得到一个健壮的脚本。读完本文,你应该能为其他三方库独立写出规范的 HPKBUILD。

欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/

HPKBUILD介绍

lycium_plusplus(简称 lycium)是鸿蒙PC官方推荐的 C/C++ 三方库标准化构建框架,核心定位是在 x86_64 Linux 开发主机上,为 ARM64 架构的鸿蒙PC设备提供一站式交叉编译能力。

框架屏蔽了交叉编译的底层技术壁垒,包括:CPU 架构差异(x86_64 ↔ ARM64)、操作系统差异(Linux ↔ 鸿蒙PC)、C 标准库差异(glibc ↔ musl libc)、编译工具链差异(gcc ↔ clang)。开发者无需关注底层交叉编译细节,只需编写一个HPKBUILD 配置脚本,声明库名称、源码地址、编译规则与打包逻辑,框架即可自动完成全流程构建。

HPKBUILD 本质是遵循框架规范的 bash 脚本,仅需实现框架约定的 5 个核心函数,lycium 会按照固定生命周期顺序自动调用,完成编译全流程:无需深入理解 lycium 框架源码,只需掌握这 5 个标准函数的用法,即可快速完成鸿蒙PC 三方库的适配与编译。

bash 复制代码
prepare() -> build() -> check() -> package() -> archive()

鸿蒙PC C/C++ 三方库移植适配资源表

已整理汇集社区鸿蒙PC C/C++ 三方库移植适配核心文档,结合本文 MediaInfo 实战案例配套学习,可快速掌握三方库完整适配流程,轻松上手移植开发

资源类型 描述 链接
三方库移植适配指导说明 介绍如何快速高效的移植一个 C/C++ 三方库到 OpenHarmony 上 👉 点击查看
lycium 交叉编译框架 lycium 交叉编译框架讲解 👉 点击查看
三方库适配模板文件 三方库适配模板文件可直接从仓库拷贝使用 👉 点击查看
标准化鸿蒙化适配方案 社区老师编写的通用适配方案,参考价值极强 👉 点击查看

MediaInfo适配前的调研

MediaInfo 三方库适配前期调研阶段,可借助 Vibe Code 高效完成全流程分析:只需将 MediaInfo 源码工程导入 Vibe Code,依托其代码检索、文件结构解析能力,快速自动识别项目 CMake、autotools 等多套构建系统;通过关键词全局检索一键筛选 CMake 编译配置选项,精准提取 BUILD_ZENLIB、BUILD_MEDIAINFOLIB 等关键编译开关;同时智能梳理项目模块层级与库依赖关系,自动识别 ZenLib、MediaInfoLib、zlib 等依赖组件,并可结合 鸿蒙PC系统环境快速判断 SDK 自带库与需手动适配的三方库,大幅缩减人工源码查阅、命令行检索与依赖梳理的时间,为后续 HPKBUILD 编写提供精准的调研依据

HPKBUILD 官方模板

HPKBUILD是Shell 编写的标准化编译构建脚本,也是 C/C++库鸿蒙化的核心,文件定义了:库的基础元信息、源码下载地址、交叉编译环境配置、编译构建逻辑、打包安装路径、测试准备、环境清理等所有核心流程。 鸿蒙官方提供了标准模板,同时业界已有大量实战案例(如 fftw3、tassl),所有适配均基于此模板修改,模板通用,案例可复用,如下是官方标准 HPKBUILD 模板

bash 复制代码
# This is an example HPKBUILD file. Use this as a start to creating your own,
# and remove these comments.
# NOTE: Please fill out the license field for your package! If it is unknown,
# then please put 'unknown'.

# Contributor: Your Name <youremail@domain.com>
# Maintainer: Your Name <youremail@domain.com>

pkgname=NAME # 库名,必填
pkgver=VERSION # 库版本,必填
pkgrel=0 # 发布号,固定为0即可
pkgdesc=""# 库功能描述,必填
url=""# 库官网地址,必填
archs=("armeabi-v7a""arm64-v8a") # 鸿蒙主流CPU架构,固定这两个即可
license=() # 开源协议,必填
depends=() # 运行依赖库,无则留空,依赖库需适配同架构
makedepends=() # 编译依赖工具,无则留空
source="https://downloads.sourceforge.net/$pkgname/$pkgname-$pkgver.tar.gz"# 源码下载链接

downloadpackage=true# 是否自动下载源码包,默认true
autounpack=true# 是否自动解压源码包,默认true
buildtools= # 编译方式,支持cmake/configure/make,必填

builddir= # 源码解压后的目录名
packagename=$builddir.tar.gz # 源码包文件名

# 编译前环境准备:创建目录、设置环境变量、源码预处理
prepare() {
    cd$builddir
    cd${OLDPWD}
}

# 核心编译逻辑:交叉编译核心步骤,架构判断、编译命令执行
build() {
    cd$builddir
    ${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" -DOHOS_ARCH=$ARCH -B$ARCH-build -S./ -L
    make -j4 -C $ARCH-build
    ret=$?
    cd$OLDPWD
    return$ret
}

# 打包安装:将编译产物安装到鸿蒙指定目录
package() {
    cd$builddir
    make -C $ARCH-build install
    cd$OLDPWD
}

# 测试说明:鸿蒙设备端测试的前置说明
check() {
    echo"The test must be on an 鸿蒙PC device!"
}

# 环境清理:编译完成后清理构建产物
cleanbuild() {
    rm -rf ${PWD}/$builddir
}

MediaInfo 适配 HPKBUILD案例

前提准备,需要提前准备源码放在Projects目录下 MediaInfo源码GitHub地址: https://github.com/MediaArea/MediaInfo

bash 复制代码
#!/bin/bash
# 编译构建脚本:MediaInfo CLI 工具 (适配 鸿蒙PC 鸿蒙系统)
# 贡献者/维护者信息
# Contributor: Your Name <youremail@domain.com>
# Maintainer: Your Name <youremail@domain.com>

# 基础包配置
# 包名
pkgname=mediainfo
# 包版本
pkgver=25.03
# 包发布版本号
pkgrel=0
# 包描述:音视频文件技术信息和标签数据查看工具(命令行版)
pkgdesc="A convenient unified display of the most relevant technical and tag data for video and audio files (CLI version)"
# 项目源码地址
url="https://github.com/MediaArea/MediaInfo"
# 支持的架构:32位ARM / 64位ARM
archs=("armeabi-v7a" "arm64-v8a")
# 开源协议
license=("BSD-2-Clause")
# 运行依赖(无)
depends=()
# 编译依赖:需要cmake
makedepends=("cmake")

# 源码配置
# 使用本地源码,不自动解压
autounpack=false
# 不自动下载源码包
downloadpackage=false

# 编译工具
buildtools="cmake"

# 本地源码路径(从环境变量 LYCIUM_ROOT 指向项目目录)
srcpath="${LYCIUM_ROOT}/../Projects/MediaInfo"
# 编译目录名称 = 包名+版本
builddir=${pkgname}-${pkgver}

# 准备阶段:复制源码、打补丁
prepare() {
    # 判断本地源码目录是否存在
    if [ -d "$srcpath" ]; then
        # 创建编译目录
        mkdir -p "$builddir"
        # 复制本地所有源码到编译目录
        cp -rf "$srcpath"/* "$builddir/"
        # 删除备份文件 .bak
        find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
        # 删除 Windows 系统遗留的区域标识符文件
        find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
        
        # 如果存在musl兼容补丁,则自动打补丁
        if [ -f "../mediainfo-zenlib-musl.patch" ]; then
            cd "$builddir"
            patch -p1 < "../mediainfo-zenlib-musl.patch"
            cd "$OLDPWD"
        fi
    else
        # 源码不存在则报错退出
        echo "ERROR: Source not found at $srcpath"
        exit 1
    fi
}

# 编译阶段:cmake + make
build() {
    # 进入编译目录
    cd "$builddir"
    
    # cmake 配置
    cmake "$@" \
        -B"$ARCH-build" \          # 按架构区分构建目录
        -S./Project/CMake/CLI/ \    # CLI 版源码路径
        -D CMAKE_BUILD_TYPE=Release \ # 编译 Release 版本
        -D CMAKE_INSTALL_PREFIX="/usr" \ # 安装路径前缀
        -D BUILD_ZENLIB=ON \         # 编译依赖库 ZenLib
        -D BUILD_MEDIAINFOLIB=ON \   # 编译核心库 MediaInfoLib
        -D BUILD_ZLIB=ON \           # 编译 zlib
        -D ZLIB_BUILD_SHARED=OFF \   # zlib 编译为静态库
        -D ZLIB_BUILD_TESTING=OFF \   # 不编译 zlib 测试程序
        -D MediaInfoLib_BUILD_STATIC=ON # MediaInfoLib 编译为静态库
    
    # 多线程编译(4线程)
    make -j4 -C "$ARCH-build"
    # 记录 make 执行结果
    ret=$?
    
    # 返回原目录
    cd "$OLDPWD"
    # 返回编译结果状态码
    return $ret
}

# 安装阶段:将编译产物安装到指定目录
package() {
    cd "$builddir"
    # 安装到目标架构目录(用于后续打包)
    make -C "$ARCH-build" install DESTDIR="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}"
    cd "$OLDPWD"
}

# 测试阶段:提示需在真机/设备上运行
check() {
    echo "The test must be on an OpenHarmony device!"
}

# 归档打包阶段:生成 .tar.gz + .hnp 鸿蒙安装包
archive() {
    # 指定 hnp 工具路径(鸿蒙 SDK 工具链)
    export HNP_TOOL="${HNP_TOOL:-${OHOS_SDK}/toolchains/hnpcli}"
    
    # 创建输出目录
    mkdir -p "${LYCIUM_ROOT}/output/${ARCH}"
    
    # 进入安装目录并打包成 tar.gz
    pushd "${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}" > /dev/null 2>&1
    tar -zcf "${LYCIUM_ROOT}/output/${ARCH}/${pkgname}_${pkgver}.tar.gz" .
    echo "Archive completed: ${LYCIUM_ROOT}/output/${ARCH}/${pkgname}_${pkgver}.tar.gz"
    popd > /dev/null 2>&1
    
    # 如果 hnpcli 工具存在,则生成鸿蒙 .hnp 包
    if [ -f "${HNP_TOOL}" ]; then
        cp "${LYCIUM_ROOT}/../thirdparty/${pkgname}/hnp.json" "${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/"
        ${HNP_TOOL} pack -i "${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}" -o "${LYCIUM_ROOT}/output/${ARCH}/"
        echo "Archive completed: ${LYCIUM_ROOT}/output/${ARCH}/${pkgname}.hnp"
    else
        # 缺少工具则跳过 hnp 打包
        echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
    fi
}

# 清理构建目录
cleanbuild() {
    rm -rf "${PWD}/$builddir"
}

对比分析:MediaInfo HPKBUILD 相对于官方模板的代码增加

官方模板是通用骨架,只包含最基本的构建逻辑。MediaInfo 的 HPKBUILD 在官方模板基础上,针对实际项目需求做了必要的扩展。下面按函数逐个对比分析增加了哪些代码,以及为什么要增加。

prepare() 函数的增加项

官方模板

bash 复制代码
prepare() {
    cd $builddir
    cd ${OLDPWD}
}

MediaInfo 版本

bash 复制代码
# 准备构建环境函数:复制源码、清理冗余文件、应用补丁
prepare() {
    # 判断源码目录是否存在
    if [ -d "$srcpath" ]; then
        # 创建构建目录
        mkdir -p "$builddir"
        # 将源码完整复制到构建目录
        cp -rf "$srcpath"/* "$builddir/"
        
        # 清理备份文件(.bak),忽略删除失败的情况
        find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
        # 清理Windows系统产生的冗余标识文件,忽略删除失败
        find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
        
        # 检查适配补丁文件是否存在,存在则执行补丁应用
        if [ -f "../mediainfo-zenlib-musl.patch" ]; then
            # 进入构建目录
            cd "$builddir"
            # 应用musl兼容补丁(适配鸿蒙PC的musl libc)
            patch -p1 < "../mediainfo-zenlib-musl.patch"
            # 返回原工作目录
            cd "$OLDPWD"
        fi
    else
        # 源码不存在,打印错误并退出
        echo "ERROR: Source not found at $srcpath"
        exit 1
    fi
}

增加内容分析

增加代码 作用 必要性
srcpath="${LYCIUM_ROOT}/.../Projects/MediaInfo" 定义本地源码路径 必需。官方模板用远程下载,MediaInfo 使用本地源码
autounpack=false和downloadpackage=false 禁用自动下载和解压 必需。配合本地源码使用
mkdir -p "$builddir" 创建构建目录 必需。官方模板由框架自动解压创建目录
cp -rf " s r c p a t h " / ∗ " srcpath"/* " srcpath"/∗"builddir/" 复制本地源码到构建目录 必需。替代官方模板的自动下载解压
find ... -name "*.bak" -delete 清理备份文件 建议。避免 Windows 传输产生的垃圾文件干扰构建
find ... -name "*:Zone.Identifier" -delete 清理 Windows 标识文件 建议。Windows 复制过来的文件会带此后缀,可能导致编译异常
patch -p1 < ".../mediainfo-zenlib-musl.patch" 应用 musl 兼容性补丁 核心必需。修复 ZenLib 的 pthread_cancel 在 musl libc 下不可用的问题
if [ -d "$srcpath" ] ... else ... exit 1 源码存在性检查 建议。提前报错,避免后续编译出现更难以定位的错误

总结:prepare() 从官方模板的 2 行扩展到 16 行,核心变化是本地源码复制和musl 补丁应用

build() 函数的增加项

官方模板

bash 复制代码
build() {
    cd $builddir
    ${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" -DOHOS_ARCH=$ARCH -B$ARCH-build -S./ -L
    make -j4 -C $ARCH-build
    ret=$?
    cd $OLDPWD
    return $ret
}

MediaInfo 版本

bash 复制代码
# 编译函数:执行CMake配置与Make编译,完成库的构建
build() {
    # 进入源码构建目录
    cd "$builddir"

    # CMake配置:指定编译参数、依赖开关、安装路径,生成编译文件
    cmake "$@" \
        -B"$ARCH-build" \          # 指定架构专属构建目录
        -S./Project/CMake/CLI/ \    # 指定CMake源码路径(CLI工具)
        -D CMAKE_BUILD_TYPE=Release \  # 编译Release发布版本
        -D CMAKE_INSTALL_PREFIX="/usr" \  # 指定安装根路径为/usr
        -D BUILD_ZENLIB=ON \        # 自动构建依赖ZenLib
        -D BUILD_MEDIAINFOLIB=ON \  # 自动构建依赖MediaInfoLib
        -D BUILD_ZLIB=ON \          # 自动构建依赖zlib
        -D ZLIB_BUILD_SHARED=OFF \  # zlib编译为静态库
        -D ZLIB_BUILD_TESTING=OFF \ # 关闭zlib测试用例
        -D MediaInfoLib_BUILD_STATIC=ON  # MediaInfoLib编译为静态库

    # 多线程编译(-j4),进入架构构建目录执行make
    make -j4 -C "$ARCH-build"
    # 保存make命令的退出状态码(0=成功,非0=失败)
    ret=$?

    # 返回执行前的工作目录
    cd "$OLDPWD"
    # 将编译结果状态返回给框架
    return $ret
}

增加内容分析

增加代码 作用 必要性
-S./Project/CMake/CLI/ 指定 CMakeLists.txt 位置 必需。MediaInfo 的 CMakeLists.txt 不在源码根目录,而是在 Project/CMake/CLI/ 子目录中
-D CMAKE_BUILD_TYPE=Release 设置发布模式 建议。Release 模式生成优化后的产物,体积更小、运行更快
-D CMAKE_INSTALL_PREFIX="/usr" 设置安装前缀 建议。确保 make install 安装到正确的目录结构
-D BUILD_ZENLIB=ON 同时构建 ZenLib 必需。MediaInfo CLI 依赖 ZenLib,此选项让 CMake 自动处理
-D BUILD_MEDIAINFOLIB=ON 同时构建 MediaInfoLib 必需。MediaInfo CLI 依赖 MediaInfoLib
-D BUILD_ZLIB=ON 同时构建 zlib 建议。确保 zlib 能找到并正确链接
-D ZLIB_BUILD_SHARED=OFF 静态链接 zlib 建议。避免运行时依赖动态库,产物更独立
-D ZLIB_BUILD_TESTING=OFF 跳过 zlib 测试 建议。减少构建时间
-D MediaInfoLib_BUILD_STATIC=ON 静态链接 MediaInfoLib 建议。避免运行时依赖问题
cmake 替代绝对路径 使用环境 PATH 中的 cmake 可选。lycium 已配置 PATH,两种写法均可

总结:build() 的核心增加是指定 CMakeLists.txt 子目录位置和MediaInfo 特有的 7 个 CMake 选项。这些选项决定了依赖库如何构建、如何链接,是适配成功的关键。

package() 函数的增加项

官方模板

bash 复制代码
package() {
    cd $builddir
    make -C $ARCH-build install
    cd $OLDPWD
}

MediaInfo 版本

bash 复制代码
# 安装打包函数:将编译好的文件安装到框架指定的输出目录
package() {
    # 进入构建目录
    cd "$builddir"
    
    # 执行安装命令:将编译产物安装到 Lycium 框架的库输出目录
    # DESTDIR 指定最终安装根目录,用于后续打包
    make -C "$ARCH-build" install DESTDIR="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}"
    
    # 返回原工作目录
    cd "$OLDPWD"
}

增加内容分析

增加代码 作用 必要性
DESTDIR=" L Y C I U M R O O T / u s r / {LYCIUM_ROOT}/usr/ LYCIUMROOT/usr/{pkgname}/${ARCH}" 指定安装目标目录 必需,官方模板的 make install 会直接安装到系统目录,加上 DESTDIR 后安装到 lycium 指定的产物目录,便于后续打包

补充说明

官方模板没有 DESTDIR,这在某些场景下会导致产物安装到错误位置。lycium 框架期望产物统一放在

bash 复制代码
${LYCIUM_ROOT}/usr/<pkgname>/<ARCH>/

目录中,所以 DESTDIR 是实际适配中的必要补充。

check() 函数

官方模板与 MediaInfo 版本完全一致

bash 复制代码
check() {
    echo "The test must be on an OpenHarmony device!"
}

说明:check() 是占位函数,因为交叉编译的产物无法在 x86 构建机上运行。真机测试需要在 鸿蒙PC设备上进行,所以此处无需修改。

archive() 函数(可选)

官方模板:无此函数。

说明:官方模板只负责编译和安装,不包含打包逻辑。lycium 框架会自动处理基础打包,但如果需要生成 HNP 格式(鸿蒙PC原生安装包)或自定义 tar.gz 命名规则,则需要自行实现 archive() 函数。

可选补充:如果项目需要 HNP 打包,可在 HPKBUILD 中根据自己需求增加:

bash 复制代码
# 归档打包函数:将编译完成的产物打包成压缩包,并生成HNP格式安装包
archive() {
    # 定义HNP打包工具路径,优先使用环境变量,否则使用SDK默认路径
    export HNP_TOOL="${HNP_TOOL:-${OHOS_SDK}/toolchains/hnpcli}"
    
    # 创建输出目录,用于存放最终的打包文件
    mkdir -p ${LYCIUM_ROOT}/output/$ARCH
    
    # 进入编译产物目录,静默输出
    pushd ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} > /dev/null 2>&1
    
    # 将编译产物打包为tar.gz压缩包,存放至输出目录
    tar -zcf ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz .
    
    # 返回原工作目录,静默输出
    popd > /dev/null 2>&1
    
    # 判断HNP工具是否存在,存在则执行HNP打包
    if [ -f "${HNP_TOOL}" ]; then
        # 复制HNP配置文件到产物目录
        cp ${LYCIUM_ROOT}/../thirdparty/${pkgname}/hnp.json ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/
        
        # 调用HNP工具生成OpenHarmony标准安装包
        ${HNP_TOOL} pack -i ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} -o ${LYCIUM_ROOT}/output/$ARCH/
    fi
}

变量声明区的增加项

增加变量 作用 必要性
srcpath 本地源码路径 使用本地源码时必需
builddir= p k g n a m e − {pkgname}- pkgname−{pkgver} 构建目录名 建议,头部定义更清晰,官方模板在 prepare() 中隐式处理
makedepends=("cmake") 声明编译依赖 必需,lycium 会检查 cmake 是否安装,未安装时报错提示

总结

通过对比可以得出结论:官方模板提供的是最小可行骨架,实际适配时必须根据三方库的具体情况进行扩展。

MediaInfo 的适配关键增加了四类内容:

  1. 本地源码处理:srcpath + cp + autounpack=false
  2. musl兼容性修复:mediainfo-zenlib-musl.patch + patch -p1
  3. 项目特有构建选项:-S./Project/CMake/CLI/ + 7 个 CMake 选项
  4. 产物打包输出:archive() 函数生成 tar.gz 和 HNP 安装包

没有写不出来的 HPKBUILD,只有不够深入的调研。祝大家在鸿蒙PC三方库适配的旅程中顺利!

相关推荐
wei_shuo2 小时前
[鸿蒙三方库适配实战] 高性能视频渲染库 libplacebo 的 鸿蒙PC 平台迁移实践
鸿蒙pc·三方库适配
wei_shuo3 天前
Windows 鸿蒙 PC 应用开发:DevEco Studio 集成与调用三方 Native 库实战指南
鸿蒙·鸿蒙pc·三方库适配
特立独行的猫a6 天前
鸿蒙 PC 命令行工具迁移实战直播课 · pngquant命令行移植实战
华为·ai·harmonyos·vcpkg·鸿蒙pc·lycim
特立独行的猫a7 天前
鸿蒙 PC 命令行工具迁移实战 · 直播PPT
android·华为·harmonyos·vcpkg·三方库移植·鸿蒙pc
特立独行的猫a7 天前
鸿蒙 PC 三方库移植实战 · 直播课件(详细教案)
华为·harmonyos·移植·鸿蒙pc·opendesk
特立独行的猫a9 天前
鸿蒙 PC 命令行工具迁移实战 · 内部课件(详细配套版)
华为·harmonyos·移植·鸿蒙pc
特立独行的猫a12 天前
HarmonyOS / OpenHarmony 鸿蒙PC平台三方库移植:AI自动化编译框架build_in_harmonyos介绍及使用
人工智能·自动化·harmonyos·三方库移植·鸿蒙pc·opendesk
特立独行的猫a21 天前
移植 vcpkg 到鸿蒙 PC:vcpkg-tool 交叉编译与实践手记
华为·harmonyos·vcpkg·鸿蒙pc·vcpkg-tool
特立独行的猫a1 个月前
使用 vcpkg 将 pngquant 命令行移植到鸿蒙 PC(OpenHarmony )
华为·harmonyos·命令行·vcpkg·pngquant·三方库·鸿蒙pc