开源鸿蒙PC三方库:从空白文件开始,写出第一份 HPKBUILD

以 MediaInfo 为例,还原我从一份空模板开始,一点点把它填成可用配方的真实过程。

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

开源仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mediainfo_hpkbuild

本篇思路源自社区作者 wei_shuohttps://weishuo.blog.csdn.net/article/details/161294044,我按自己的理解重新组织了讲法。致谢原作者的开源贡献。

为什么很多人卡在「空白的 HPKBUILD」

我自己刚上手时也一样:知道要写 HPKBUILD,但盯着空文件不知道第一行敲什么。后来想明白了——HPKBUILD 没那么玄,它就是一个遵循框架约定的 bash 脚本,你只要实现框架点名要的几个函数,它会按固定顺序帮你调。

lycium(lycium_plusplus)帮我屏蔽了交叉编译里最难的四类差异:

  • CPU 架构:x86_64 ↔ ARM64
  • 操作系统:Linux ↔ 鸿蒙
  • C 标准库:glibc ↔ musl
  • 编译器:gcc ↔ clang

我不需要懂这些底层细节,只要写好配方,框架按下面这条生命周期跑:

prepare() → build() → check() → package() → archive()

在这里插入图片描述

第一步:搭骨架(先抄官方模板)

不要从零手敲,直接拿官方模板改。模板顶部是一堆元信息变量,中间是几个空函数。我先把元信息填了:

pkgname=mediainfo
pkgver=25.03
pkgrel=0
pkgdesc="A unified display of technical and tag data for video/audio files (CLI)"
url="https://github.com/MediaArea/MediaInfo"
archs=("armeabi-v7a" "arm64-v8a")
license=("BSD-2-Clause")
depends=()                # 运行时依赖,这里没有
makedepends=("cmake")     # 编译期工具

这一步纯粹是「填表」,没什么难度,但 licensepkgdesc 这些是合规和检索要用的,别偷懒留空。

第二步:决定源码从哪来

官方模板默认是「远程下载 + 自动解压」。但我这次源码是本地准备好的(放在 Projects/MediaInfo),所以要关掉自动下载:

autounpack=false
downloadpackage=false
srcpath="${LYCIUM_ROOT}/../Projects/MediaInfo"
builddir=${pkgname}-${pkgver}

这个选择会直接影响 prepare() 的写法——既然不自动下载,那源码的「就位」就得我自己在 prepare 里手动做。

第三步:一个函数一个函数地填

我把「官方模板 → MediaInfo 实际版本」每个函数多了什么、为什么多,整理成了对照笔记。这比单纯贴最终代码有用得多。

prepare():从 2 行膨胀到十几行

模板里它几乎是空的。我的版本要做四件事:

  1. 建构建目录、把本地源码 cp 进去(替代自动下载解压);
  2. .bak 备份文件;
  3. 删 Windows 残留的 :Zone.Identifier 文件;
  4. 打 musl 补丁。
prepare() {
    if [ -d "$srcpath" ]; then
        mkdir -p "$builddir"
        cp -rf "$srcpath"/* "$builddir/"
        find "$builddir" -name "*.bak" -delete 2>/dev/null || true
        find "$builddir" -name "*:Zone.Identifier" -delete 2>/dev/null || true
        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
}

我特意保留了最后的 else exit 1——源码不在就尽早报错,比让后面编译抛一堆莫名其妙的错强。

build():关键是 -S 和那几个开关

模板里的 build() 假设 CMakeLists.txt 在源码根目录。但 MediaInfo 的在 Project/CMake/CLI/ 子目录,必须用 -S 指过去。另外要把依赖库的构建开关打开:

build() {
    cd "$builddir"
    cmake "$@" \
        -B"$ARCH-build" \
        -S./Project/CMake/CLI/ \
        -D CMAKE_BUILD_TYPE=Release \
        -D CMAKE_INSTALL_PREFIX="/usr" \
        -D BUILD_ZENLIB=ON \
        -D BUILD_MEDIAINFOLIB=ON \
        -D BUILD_ZLIB=ON \
        -D ZLIB_BUILD_SHARED=OFF \
        -D MediaInfoLib_BUILD_STATIC=ON
    make -j4 -C "$ARCH-build"
    ret=$?
    cd "$OLDPWD"
    return $ret
}

我的理解:BUILD_ZENLIB=ON 这类是让 CMake 顺手把依赖一起编了,省去单独适配每个依赖的麻烦;*_BUILD_STATIC=ON 则是把依赖编成静态库打进主程序,产物更独立、运行时不缺 .so。

package():别忘了 DESTDIR

模板的 make install 会装到系统目录,那不是我们要的。加 DESTDIR 把产物收到框架约定的位置:

package() {
    cd "$builddir"
    make -C "$ARCH-build" install DESTDIR="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}"
    cd "$OLDPWD"
}

check() 和 archive()

check() 我没改——交叉编译出来的 arm64 产物没法在 x86 构建机上跑,所以这里就是个占位,提示「请到鸿蒙设备上测」。

archive() 模板里没有,是我按需补的,作用是生成 tar.gz 和调用 hnpcli.hnp 包。

我的总结:模板是骨架,调研是肌肉

把模板和实际版本一对比,结论很清楚:官方模板只是最小骨架,真正决定成败的是你对目标库的调研。MediaInfo 这次的「增量」其实就四类:

  1. 本地源码处理(srcpath + cp + 关闭自动下载);
  2. musl 兼容补丁;
  3. 项目特有的 CMake 选项(-S 子目录 + 依赖开关);
  4. 产物打包(archive 生成 tar.gz / hnp)。

我自己的体会是:写不出 HPKBUILD,几乎总是因为「还没搞清楚这个库怎么编、依赖啥」。前期花时间读它的 CMakeLists.txt、跑通它在 Linux 上的原生编译,HPKBUILD 自然就水到渠成了。

小结

这一篇把系列里反复出现的 HPKBUILD「揭开盖子」讲了一遍。掌握了「填元信息 → 定源码来源 → 逐函数填充 → 对照模板查缺」这套方法,再去写别的库的配方就有章可循了。

下一篇回到 libplacebo 本体,聊聊它作为 Meson 构建系统的库,交叉编译时和 CMake 类项目有什么不一样。感谢 wei_shuo 的开源分享。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐