[鸿蒙PC三方库适配实战] mpv 多层依赖树完整解析与适配实践
摘要:本文以媒体播放器 mpv 为例,详细介绍了在鸿蒙PC平台上适配多层依赖C/C++项目的系统化方法。文章首先解析了mpv的四层依赖树结构(基础库→中间库→核心库→目标库),强调自底向上的构建顺序原则。随后以zlib和libpng为例,展示了底层库的HPKBUILD配置要点,包括交叉编译环境设置、依赖声明和补丁应用。本文属于"软件鸿蒙化迁移实践"系列,提供完整的代码示例和构建指南,旨在帮助开发者
摘要:本文以 mpv 媒体播放器为例,深入讲解如何在 鸿蒙PC 平台上适配具有复杂多层依赖树的 C/C++ 项目。文章将按照依赖层次,从底层基础库到顶层应用,逐一解析每个依赖库的 HPKBUILD 配置、pkg-config 路径管理、头文件路径处理等关键技术点,所有代码均取自 thirdparty 目录下的真实项目。
本文是软件鸿蒙化迁移实践系列文章之一,专注于多层依赖树的系统化适配方法。
欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mpv_deps
项目信息说明
| 项目 | 说明 |
|---|---|
| 目标库 | mpv (libmpv) |
| 开源协议 | LGPL-2.1-or-later |
| 源码版本 | 0.41.0 |
| 目标平台 | 鸿蒙 PC |
| 构建系统 | Meson + Ninja |
| 操作系统平台 | WSL Ubuntu 24.04 |
一、多层依赖树结构解析
1.0 为什么需要理解依赖树
在 C/C++ 项目中,多层依赖树是最常见的架构模式。理解依赖树的重要性在于:
- 构建顺序决定成败:必须自底向上构建,否则依赖库找不到
- pkg-config 路径传递:每个库的 pkgconfig 路径必须正确传递给上层
- 头文件路径差异:不同库的安装路径规范不一致,需要特殊处理
- 链接路径配置:库文件位置不同,需要显式指定链接路径
1.1 mpv 的完整依赖树
mpv 的依赖展现了典型的金字塔形依赖结构,共分为 4 层:
第 4 层:mpv (目标库 - 媒体播放器)
├── 依赖: FFmpeg, libplacebo, libass
│
第 3 层:核心依赖库
├── FFmpeg (音视频编解码)
├── libplacebo (GPU 渲染)
│ └── 依赖: vulkan-headers, spirv-headers, fast_float
└── libass (字幕渲染)
└── 依赖: fontconfig, harfbuzz, fribidi, freetype2
│
第 2 层:中间依赖库
├── fontconfig (字体配置)
│ └── 依赖: freetype2, libexpat
├── harfbuzz (文本整形)
│ └── 依赖: freetype2, glib
└── freetype2 (字体渲染)
└── 依赖: zlib, libpng, brotli
│
第 1 层:基础依赖库
├── zlib (压缩库)
├── libpng (PNG 图像)
├── brotli (压缩算法)
├── libexpat (XML 解析)
├── fribidi (双向文本)
└── glib (基础工具库)
└── 依赖: libffi, pcre2
1.2 构建顺序原则
核心原则:自底向上,逐层构建
第 1 步:zlib, libpng, brotli, libexpat, fribidi, libffi, pcre2
↓
第 2 步:glib (依赖 libffi, pcre2)
↓
第 3 步:freetype2 (依赖 zlib, libpng, brotli)
↓
第 4 步:fontconfig (依赖 freetype2, libexpat)
harfbuzz (依赖 freetype2, glib)
↓
第 5 步:libass (依赖 fontconfig, harfbuzz, fribidi, freetype2)
↓
第 6 步:FFmpeg, libplacebo (并行构建)
↓
第 7 步:mpv (依赖 FFmpeg, libplacebo, libass)
二、第 1 层:基础依赖库适配
2.1 zlib - 压缩库
依赖关系:无依赖(最底层)
HPKBUILD 完整配置:
# Contributor: Jeff Han <hanjinfei@foxmail.com>
# Maintainer: Jeff Han <hanjinfei@foxmail.com>
pkgname=zlib
pkgver=v1.2.13
pkgrel=0
pkgdesc=""
url=""
archs=("armeabi-v7a" "arm64-v8a" "x86_64")
license=("zlib License")
depends=()
makedepends=()
# 官方下载地址source="https://github.com/madler/$pkgname/archive/refs/tags/$pkgver.tar.gz"受网络影响可能存在下载失败的情况,现使用gitee镜像可以与官方仓库保持同步
source="https://gitee.com/mirrors/$pkgname/repository/archive/$pkgver.zip"
autounpack=true
downloadpackage=true
buildtools="configure"
builddir=$pkgname-${pkgver}
packagename=$builddir.zip
patch_flag=true
source envset.sh
prepare() {
mkdir -p $builddir/$ARCH-build
if [ "$patch_flag" == true ]
then
cd $builddir
patch -p1 < ../zlib_ohos_pkg.patch
cd $OLDPWD
patch_flag=false
fi
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
fi
if [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
fi
}
build() {
cd $builddir/$ARCH-build
PKG_CONFIG_LIBDIR="${pkgconfigpath}" \
../configure "$@" > $buildlog 2>&1
$MAKE VERBOSE=1 >> $buildlog 2>&1
ret=$?
cd $OLDPWD
return $ret
}
package() {
cd $builddir/$ARCH-build
$MAKE install >> $buildlog 2>&1
cd $OLDPWD
if [ $ARCH == "armeabi-v7a" ]
then
unsetarm32ENV
fi
if [ $ARCH == "arm64-v8a" ]
then
unsetarm64ENV
fi
}
check() {
echo "The test must be on an OpenHarmony device!"
# real test CMD
# make check
}
# 清理环境
cleanbuild(){
rm -rf ${PWD}/$builddir #${PWD}/$packagename
}

关键技术点:
- depends=() 空数组表示无依赖
- source envset.sh 导入 lycium 框架的环境变量设置函数
- setarm64ENV 设置 arm64-v8a 交叉编译环境变量
- patch -p1 < …/zlib_ohos_pkg.patch 应用鸿蒙适配补丁
- 标准 configure + make 构建流程
构建命令:
cd lycium_plusplus/lycium
./build.sh zlib
2.2 libpng - PNG 图像处理库
依赖关系:依赖 zlib
HPKBUILD 完整配置:
# Contributor: Jeff Han <hanjinfei@foxmail.com>
# Maintainer: Jeff Han <hanjinfei@foxmail.com>
pkgname=libpng
pkgver=v1.6.39
pkgrel=0
pkgdesc=""
url=""
archs=("arm64-v8a")
license=("PNG Reference Library License version 2")
depends=()
makedepends=()
install=
# 官方下载地址source="https://sourceforge.net/projects/$pkgname/files/libpng16/$pkgver/$pkgname-$pkgver.tar.xz"受网络影响可能存在下载失败的情况,现使用gitee镜像可以与官方仓库保持同步
source="https://gitee.com/mirrors/$pkgname/repository/archive/$pkgver.zip"
autounpack=true
downloadpackage=true
buildtools="configure"
builddir=$pkgname-${pkgver}
packagename=$builddir.zip
source envset.sh
host=
prepare() {
mkdir -p $builddir/$ARCH-build
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
host=arm-linux
fi
if [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
host=aarch64-linux
fi
}
build() {
cd $builddir/$ARCH-build
# 显式设置 C 预处理器,避免 configure 自动检测使用 C++ 编译器
export CPP="${CC:-${LYCIUM_ROOT}/../toolchain/${host}-ohos-clang} -E"
PKG_CONFIG_LIBDIR="${pkgconfigpath}" ../configure "$@" \
--host=$host --enable-shared --enable-static > $buildlog 2>&1
# 修改导致测试失败的字符串
find . -name Makefile -exec sed -i 's#mawk#awk#' {} +
find . -name Makefile -exec sed -i 's#/bin/bash#bash#' {} +
find . -name Makefile -exec sed -i 's#/usr/bin/sed#/bin/sed#' {} +
find . -name Makefile -exec sed -i 's#/usr/bin/mkdir#mkdir#' {} +
ret=-1
if [ $LYCIUM_BUILD_OS == "CYGWI" ]
then
$MAKE libpng16.la >> $buildlog 2>&1
ret=$?
else
$MAKE >> $buildlog 2>&1
ret=$?
fi
cd $OLDPWD
return $ret
}
package() {
cd $builddir/$ARCH-build
ret=-1
if [ $LYCIUM_BUILD_OS == "CYGWI" ]
then
$MAKE install-libLTLIBRARIES >> $buildlog 2>&1
$MAKE install-library-links >> $buildlog 2>&1
$MAKE install-pkgincludeHEADERS >> $buildlog 2>&1
$MAKE install-header-links >> $buildlog 2>&1
$MAKE install-pkgconfigDATA >> $buildlog 2>&1
ret=$?
else
$MAKE install >> $buildlog 2>&1
ret=$?
fi
cd $OLDPWD
return $ret
}
check() {
cd $builddir/$ARCH-build
$MAKE pngtest pngunknown pngstest pngvalid pngimage pngcp timepng >> $buildlog 2>&1
sed -i 's#/bin/bash#/bin/env bash#' pngtest pngunknown pngstest pngvalid pngimage pngcp timepng
sed -i '/.*check-TESTS: $(check_PROGRAMS)/c\check-TESTS: #$(check_PROGRAMS)' Makefile
cd $OLDPWD
if [ $ARCH == "armeabi-v7a" ]
then
unsetarm32ENV
fi
if [ $ARCH == "arm64-v8a" ]
then
unsetarm64ENV
fi
unset host
echo "The test must be on an OpenHarmony device!"
# test CMD
# make check-TESTS
}
# 清理环境
cleanbuild(){
rm -rf ${PWD}/$builddir #${PWD}/$packagename
}
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键技术点:
- source envset.sh 导入 lycium 环境变量
- setarm64ENV 设置交叉编译环境,host=aarch64-linux
- export CPP=“… -E” 显式设置 C 预处理器,避免使用 C++ 编译器
- find … sed 替换 Makefile 中的路径,适配鸿蒙环境
- Cygwin 特殊处理(LYCIUM_BUILD_OS == “CYGWI”)
构建命令:
# 必须先构建 zlib
./build.sh zlib
./build.sh libpng
2.3 fribidi - 双向文本处理
依赖关系:无依赖
HPKBUILD 完整配置:
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Contributor: 小肉头君 <chenbaodi@huawei.com>
# Maintainer: 小肉头君 <chenbaodi@huawei.com>
pkgname=fribidi
pkgver=v1.0.12
pkgrel=0
pkgdesc="The Free Implementation of the Unicode Bidirectional Algorithm."
url="https://github.com/fribidi/fribidi"
archs=("arm64-v8a")
license=("LGPL-2.1-only")
depends=()
makedepends=("unzip" "yacc" "flex")
# 原仓地址: https://github.com/$pkgname/$pkgname/archive/refs/tags/$pkgver.tar.gz, 因网络原因使用镜像
source="https://gitee.com/mirrors/$pkgname/repository/archive/$pkgver.zip"
autounpack=true
downloadpackage=true
buildtools="meson"
builddir=$pkgname-$pkgver
packagename=$builddir.zip
source envset.sh
autogenflag=true
buildhostc2man=true
host=
originalPath=
prepare() {
mkdir -p $builddir/$ARCH-build
# 编译c2man
if $buildhostc2man
then
# 原仓地址: https://github.com/fribidi/c2man/archive/refs/heads/master.zip,因网络原因使用镜像
curl -f -L https://gitee.com/lycium_pkg_mirror/c2man/repository/archive/master.zip -o c2man.zip
if [ $? != 0 ]
then
return -1
fi
unzip c2man.zip > $buildlog 2>&1
cd c2man-master
PKG_CONFIG_LIBDIR="${pkgconfigpath}" ./Configure -d -e > $buildlog 2>&1
$MAKE VERBOSE=1 >> $buildlog 2>&1
cd $OLDPWD
buildhostc2man=false
fi
# 把c2man的路径配置到PATH中
originalPath=$PATH
export PATH=$PATH:$LYCIUM_ROOT/../thirdparty/$pkgname/c2man-master
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
host=arm-linux
fi
if [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
host=aarch64-linux
fi
if $autogenflag
then
cd $builddir
./autogen.sh > $buildlog 2>&1
autogenflag=false
cd $OLDPWD
fi
}
build() {
# Meson 交叉编译配置
local abs_builddir="${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}"
local cross_file="${abs_builddir}/ohos-cross.ini"
local build_path="${abs_builddir}/ohos-build"
cat > "$cross_file" << EOF
[binaries]
c = '${CC}'
cpp = '${CXX}'
ar = '${AR}'
strip = '${STRIP}'
pkgconfig = 'pkg-config'
[built-in options]
prefix = '/usr'
[host_machine]
system = 'linux'
cpu_family = '${ARCH/arm64-v8a/aarch64}'
cpu = '${ARCH/arm64-v8a/aarch64}'
endian = 'little'
EOF
meson setup "$build_path" "$abs_builddir" \
--cross-file "$cross_file" \
--prefix="/usr" \
-Ddefault_library=both \
-Dc_args=$(echo $CFLAGS | sed 's/ /","/g; s/^/"/; s/$/"/') \
-Dcpp_args=$(echo $CXXFLAGS | sed 's/ /","/g; s/^/"/; s/$/"/') > "$buildlog" 2>&1
ninja -C "$build_path" >> "$buildlog" 2>&1
ret=$?
return $ret
}
package() {
local abs_builddir="${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}"
cd "$abs_builddir"
# 使用 lycium 标准的 destdir 变量,确保使用当前 ARCH
local destdir="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}"
# meson install 使用 destdir
DESTDIR="${destdir}" ninja -C "ohos-build" install >> "$buildlog" 2>&1
}
check() {
echo "The test must be on an OpenHarmony device!"
}
# 清理环境
cleanbuild() {
rm -rf ${PWD}/$builddir ${PWD}/c2man.zip ${PWD}/c2man-master #${PWD}/$packagename
}
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键注意:
- c2man 工具编译:fribidi 需要先编译 c2man 文档生成工具
curl -f -L https://gitee.com/lycium_pkg_mirror/c2man/repository/archive/master.zip -o c2man.zip
unzip c2man.zip
cd c2man-master
./Configure -d -e
$MAKE
- **PATH **环境变量:将 c2man 加入 PATH
export PATH=$PATH:$LYCIUM_ROOT/../thirdparty/$pkgname/c2man-master
- autogen.sh:执行 autogen 生成 configure 脚本
- prefix=/usr:导致安装路径特殊
- 头文件安装在 usr/include 而非 include
- pkgconfig 文件在 usr/lib/pkgconfig 而非 lib/pkgconfig
构建命令:
./build.sh fribidi
三、第 2 层:中间依赖库适配
3.1 glib - 基础工具库
依赖关系:依赖 libffi、pcre2
HPKBUILD 完整配置:
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Contributor: 城meto <myxuan475@126.com>
# Maintainer: 城meto <myxuan475@126.com>
pkgname=glib
pkgver=2.77.1
pkgrel=0
pkgdesc="GLib is a general-purpose, portable utility library, which provides many useful data types, macros, type conversions, string utilities, file utilities, a mainloop abstraction, and so on."
url="https://docs.gtk.org/glib/"
archs=("armeabi-v7a" "arm64-v8a")
license=("LGPL-2.1-or-later")
depends=("libffi" "pcre2")
makedepends=("meson" "ninja")
# 原仓位置: https://github.com/GNOME/${pkgname}/archive/refs/tags/$pkgver.tar.gz, 因网络原因使用镜像
source="https://gitee.com/mirrors/$pkgname/repository/archive/$pkgver.zip"
downloadpackage=true
autounpack=true
buildtools="meson"
builddir=$pkgname-$pkgver
packagename=$pkgname-$pkgver.zip
pkgconfigpath=
clonesubmodule=true
prepare() {
# 下载子模块
if $clonesubmodule
then
# 下载gvdb,因网络原因使用镜像, 原仓地址: https://github.com/GNOME/gvdb.git
git clone https://gitee.com/lycium_pkg_mirror/gvdb.git $builddir/subprojects/gvdb
if [ $? -ne 0 ];then
return -1
fi
cd $builddir/subprojects/gvdb
git checkout --detach 0854af0fdb6d527a8d1999835ac2c5059976c210
cd $OLDPWD
# 下载 libintl, meson 下载会失败, 原仓地址: https://github.com/frida/proxy-libintl.git
git clone --depth 1 --branch 0.4 https://gitee.com/lycium_pkg_mirror/proxy-libintl.git $builddir/subprojects/proxy-libintl
if [ $? -ne 0 ];then
return -2
fi
clonesubmodule=false
fi
# 依赖库加入 pkg_config_path 路径
for depend in ${depends[@]}
do
dependpath=$LYCIUM_ROOT/usr/$depend/$ARCH/lib/pkgconfig
if [ ! -d ${dependpath} ]
then
continue
fi
pkgconfigpath=$pkgconfigpath"${dependpath}:"
done
pkgconfigpath=${pkgconfigpath%:*}
cp $ARCH-cross-file.txt $builddir
mkdir -p $builddir/$ARCH-build
}
build() {
cd $builddir
ohos_sdk_path=${OHOS_SDK//\//\\\/}
sed -i 's/ohos_sdk/'"$ohos_sdk_path"'/g' $ARCH-cross-file.txt
# 需要设置pkg路径
meson setup $ARCH-build --cross-file $ARCH-cross-file.txt \
--pkg-config-path=$pkgconfigpath \
--prefix=$LYCIUM_ROOT/usr/$pkgname/$ARCH > $ARCH-build/build.log 2>&1
ninja -C $ARCH-build -v >> $ARCH-build/build.log 2>&1
ret=$?
cd $OLDPWD
return $ret
}
package() {
cd $builddir
ninja -v -C $ARCH-build install >> build.log 2>&1
# 还原
unset pkgconfigpath
cd $OLDPWD
}
check() {
echo "The test must be on an OpenHarmony device!"
# TODO
}
# 清理环境
cleanbuild() {
rm -rf ${PWD}/$builddir
}
# 打包产物
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键技术点:
- 子模块下载:glib 需要 gvdb 和 proxy-libintl 两个子模块
git clone https://gitee.com/lycium_pkg_mirror/gvdb.git $builddir/subprojects/gvdb
git clone --depth 1 --branch 0.4 https://gitee.com/lycium_pkg_mirror/proxy-libintl.git $builddir/subprojects/proxy-libintl
- pkgconfigpath 循环收集:遍历 depends 数组,拼接所有依赖的 pkgconfig 路径
- 交叉编译文件替换:使用 sed 替换 ohos_sdk 占位符为实际路径
ohos_sdk_path=${OHOS_SDK//\/\\\/}
sed -i 's/ohos_sdk/'"$ohos_sdk_path"'/g' $ARCH-cross-file.txt
- –pkg-config-path 参数:Meson 特有的依赖查找参数
构建命令:
# 必须先构建依赖
./build.sh libffi
./build.sh pcre2
./build.sh glib
3.2 freetype2 - 字体渲染引擎
依赖关系:依赖 zlib、libpng、bzip2、brotli
HPKBUILD 完整配置:
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Contributor: tyBrave <tianyong13@huawei.com>
# Maintainer: tyBrave <tianyong13@huawei.com>
pkgname=freetype2
pkgver=VER-2-13-0
pkgrel=0
pkgdesc="FreeType is a freely available software library to render fonts."
url="https://freetype.org"
archs=("arm64-v8a")
license=("GPL FTL")
depends=("zlib" "bzip2" "brotli" "libpng")
makedepends=()
# 官方下载地址https://sourceforge.net/projects/freetype/files/$pkgname/$pkgver/freetype-$pkgver.tar.xz受网络影响可能存在下载失败的情况,现使用gitee镜像可以与官方仓库保持同步
source="https://gitee.com/lycium_pkg_mirror/${pkgname:0:8}/repository/archive/$pkgver.zip"
autounpack=true
downloadpackage=true
builddir=${pkgname:0:8}-${pkgver}
packagename=$builddir.zip
testdir=
prepare() {
testdir=`pwd`/$builddir/$ARCH-build/freetype-cmake-testbuild
rm -rf $testdir
mkdir -p $testdir
}
build() {
cd $builddir
${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" -DOHOS_ARCH=$ARCH -DFT_DISABLE_BROTLI=OFF -DFT_DISABLE_BZIP2=OFF -DFT_DISABLE_HARFBUZZ=ON -DFT_DISABLE_PNG=OFF -DFT_DISABLE_ZLIB=OFF -DFT_ENABLE_ERROR_STRINGS=ON -B$testdir/ftb -S./ -L > `pwd`/$ARCH-build/build.log 2>&1
make -j4 -C $testdir/ftb >> `pwd`/$ARCH-build/build.log 2>&1
ret=$?
cd $OLDPWD
return $ret
}
package() {
cd "$builddir"
make -C $testdir/ftb install >> `pwd`/$ARCH-build/build.log 2>&1
cd $OLDPWD
}
check() {
echo -e " \n
cmake_minimum_required(VERSION 3.16.5) \n
project(freetype-cmake-testbuild)\n
set(FREETYPE_LIBRARY $LYCIUM_ROOT/usr/$pkgname/$ARCH/lib) \n
set(FREETYPE_INCLUDE_DIRS $LYCIUM_ROOT/usr/$pkgname/$ARCH/include/freetype2) \n
include_directories($LYCIUM_ROOT/usr/$pkgname/$ARCH/include/freetype2) \n
add_executable(freetype-cmake-test main.c)\n
target_link_libraries(freetype-cmake-test PUBLIC $LYCIUM_ROOT/usr/$pkgname/$ARCH/lib/libfreetype.a)\n
target_link_libraries(freetype-cmake-test PUBLIC $LYCIUM_ROOT/usr/brotli/$ARCH/lib/libbrotlidec.so)\n
target_link_libraries(freetype-cmake-test PUBLIC $LYCIUM_ROOT/usr/bzip2/$ARCH/lib/libbz2.a)\n
target_link_libraries(freetype-cmake-test PUBLIC $LYCIUM_ROOT/usr/libpng/$ARCH/lib/libpng.a)\n
target_link_libraries(freetype-cmake-test PUBLIC $LYCIUM_ROOT/usr/zlib/$ARCH/lib/libz.a)\n
enable_testing()\n
add_test(freetype-cmake-test freetype-cmake-test)" > $testdir/CMakeLists.txt
echo -e " \n
#include <stdio.h> \n
#include <stdlib.h> \n
#include <ft2build.h> \n
#include <freetype/freetype.h> \n
FT_Library library; \n
int main(int argc,char*argv[]) \n
{ \n
FT_Error error; \n
FT_Int major = 0; \n
FT_Int minor = 0; \n
FT_Int patch = 0; \n
error = FT_Init_FreeType(&library); \n
if (error) return EXIT_FAILURE; \n
FT_Library_Version(library, &major, &minor, &patch); \n
if (major != FREETYPE_MAJOR|| minor != FREETYPE_MINOR|| patch != FREETYPE_PATCH) return EXIT_FAILURE; \n
printf(\"FT_Library_Version:%d.%d.%d\", major, minor, patch);\n
error = FT_Done_FreeType(library); \n
if (error) return EXIT_FAILURE; \n
return EXIT_SUCCESS;
}" > $testdir/main.c
mkdir -p $testdir/tb
cd $testdir/tb
${OHOS_SDK}/native/build-tools/cmake/bin/cmake $testdir -DCMAKE_TOOLCHAIN_FILE=$OHOS_SDK/native/build/cmake/ohos.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DOHOS_ARCH=$ARCH >> $testdir/../build.log 2>&1
${OHOS_SDK}/native/build-tools/cmake/bin/cmake --build . --config Release >> $testdir/../build.log 2>&1
ret=$?
cd $OLDPWD
echo "The test must be on an OpenHarmony device!"
return $ret
# cd freetype-cmake-testbuild/tb
# ctest -V -C Release
}
# 清理环境
cleanbuild(){
rm -rf ${PWD}/$builddir #${PWD}/$packagename
}
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键技术点:
- CMake 构建:使用 CMake 而非 Meson
- 特性开关:通过 -DFT_DISABLE_* 控制启用/禁用哪些依赖
-DFT_DISABLE_BROTLI=OFF # 启用 brotli
-DFT_DISABLE_BZIP2=OFF # 启用 bzip2
-DFT_DISABLE_PNG=OFF # 启用 libpng
-DFT_DISABLE_ZLIB=OFF # 启用 zlib
-DFT_DISABLE_HARFBUZZ=ON # 禁用 harfbuzz
- ${pkgname:0:8} 字符串截取:freetype2 源码目录名是 freetype 而非 freetype2
- CMake 自动查找依赖:CMake 工具链会自动处理依赖库路径
构建命令:
# 按顺序构建所有依赖
./build.sh zlib
./build.sh libpng
./build.sh brotli
./build.sh bzip2
./build.sh freetype2
3.3 fontconfig - 字体配置库
依赖关系:依赖 freetype2、libpng、zlib、bzip2、brotli、libexpat
HPKBUILD 完整配置:
# Contributor: 小肉头君 <chenbaodi@huawei.com>
# Maintainer: 小肉头君 <chenbaodi@huawei.com>
pkgname=fontconfig
pkgver=2.14.2
pkgrel=0
pkgdesc="Font configuration and customization library."
url="https://gitlab.freedesktop.org/fontconfig/fontconfig"
archs=("arm64-v8a")
license=("HPND" "Public Domain" "MIT-Modern-Variant" "MIT")
depends=("freetype2" "libpng" "zlib" "bzip2" "brotli" "libexpat")
makedepends=()
source="https://www.freedesktop.org/software/${pkgname}/release/${pkgname}-${pkgver}.tar.gz"
autounpack=true
downloadpackage=true
buildtools="configure"
builddir=$pkgname-$pkgver
packagename=$builddir.tar.gz
autogenflag=true
testpatch=true
source envset.sh
host=
prepare() {
mkdir -p $builddir/$ARCH-build
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
host=arm-linux
fi
if [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
host=aarch64-linux
fi
if $autogenflag
then
cd $builddir
./autogen.sh > `pwd`/build.log 2>&1
cd $OLDPWD
autogenflag=false
fi
}
build() {
cd $builddir/$ARCH-build
# 显式设置 C 预处理器,避免 configure 自动检测使用 C++ 编译器
export CPP="${CC:-${LYCIUM_ROOT}/../toolchain/${host}-ohos-clang} -E"
FREETYPE_CFLAGS="-I${LYCIUM_ROOT}/usr/freetype2/$ARCH/include/freetype2 ${LYCIUM_ROOT}/usr/bzip2/$ARCH/lib/libbz2.a \
${LYCIUM_ROOT}/usr/libpng/$ARCH/lib/libpng.a ${LYCIUM_ROOT}/usr/brotli/$ARCH/lib/libbrotlicommon.so \
${LYCIUM_ROOT}/usr/brotli/$ARCH/lib/libbrotlienc.so ${LYCIUM_ROOT}/usr/brotli/$ARCH/lib/libbrotlidec.so -lz" \
FREETYPE_LIBS="${LYCIUM_ROOT}/usr/freetype2/$ARCH/lib/libfreetype.a" CFLAGS="$FREETYPE_CFLAGS $FREETYPE_LIBS" \
PKG_CONFIG_PATH="${pkgconfigpath}" ../configure "$@" --host=$host --disable-libxml2 --enable-static \
--enable-shared --disable-silent-rules > `pwd`/build.log 2>&1 # --sysconfdir="/etc" --localstatedir="/var" --datarootdir="/share"
make -j4 >> `pwd`/build.log 2>&1
# 对最关键一步的退出码进行判断
ret=$?
cd $OLDPWD
return $ret
}
package() {
cd $builddir/$ARCH-build
make install >> `pwd`/build.log 2>&1
cd $OLDPWD
}
check() {
# 下载字库
# 测试过程需要curl下载字体,为避免测试机下载失败,采用提前下载好
cd $builddir/$ARCH-build/test
mkdir noto
curl -s -o noto/noto.zip https://noto-website-2.storage.googleapis.com/pkgs/NotoSans-hinted.zip
cd $OLDPWD
cd $builddir/$ARCH-build/test/noto
unzip noto.zip > `pwd`/build.log 2>&1
tar -zcf noto.tar.gz *.ttf README LICENSE_OFL.txt
cp noto.tar.gz ../
cd $OLDPWD
# 编译测试用例
cd $builddir/$ARCH-build/test
make test-pthread test-crbug1004254 test-bz89617 test-bz131804 test-migration \
test-bz96676 test-name-parse test-bz106618 test-bz106632 test-issue107 test-bz1744377 \
test-issue180 test-family-matching >> `pwd`/build.log 2>&1
if $testpatch
then
sed -i '435d' ../../test/run-test.sh
sed -i '434a cp $MyPWD/noto.tar.gz "$FONTDIR"/noto.tar.gz' ../../test/run-test.sh
sed -i '/.*(cd "$FONTDIR"; unzip noto.zip)/c\ (cd "$FONTDIR"; tar -zxf noto.tar.gz)' ../../test/run-test.sh
testpatch=false
fi
sed -i '/.*check-TESTS: $(check_PROGRAMS) $(check_SCRIPTS)/c\check-TESTS: $(check_SCRIPTS) #$(check_PROGRAMS)' Makefile
sed -i '/.*test-bz89617.log: test-bz89617$(EXEEXT)/c\test-bz89617.log: #test-bz89617$(EXEEXT)' Makefile
sed -i '/.*test-bz131804.log: test-bz131804$(EXEEXT)/c\test-bz131804.log: #test-bz131804$(EXEEXT)' Makefile
sed -i '/.*test-bz96676.log: test-bz96676$(EXEEXT)/c\test-bz96676.log: #test-bz96676$(EXEEXT)' Makefile
sed -i '/.*test-name-parse.log: test-name-parse$(EXEEXT)/c\test-name-parse.log: #test-name-parse$(EXEEXT)' Makefile
sed -i '/.*test-bz106632.log: test-bz106632$(EXEEXT)/c\test-bz106632.log: #test-bz106632$(EXEEXT)' Makefile
sed -i '/.*test-issue107.log: test-issue107$(EXEEXT)/c\test-issue107.log: #test-issue107$(EXEEXT)' Makefile
sed -i '/.*test-issue110.log: test-issue110$(EXEEXT)/c\test-issue110.log: #test-issue110$(EXEEXT)' Makefile
sed -i '/.*test-d1f48f11.log: test-d1f48f11$(EXEEXT)/c\test-d1f48f11.log: #test-d1f48f11$(EXEEXT)' Makefile
sed -i '/.*test-bz1744377.log: test-bz1744377$(EXEEXT)/c\test-bz1744377.log: #test-bz1744377$(EXEEXT)' Makefile
sed -i '/.*test-issue180.log: test-issue180$(EXEEXT)/c\test-issue180.log: #test-issue180$(EXEEXT)' Makefile
sed -i '/.*test-family-matching.log: test-family-matching$(EXEEXT)/c\test-family-matching.log: #test-family-matching$(EXEEXT)' Makefile
cd $OLDPWD
if [ $ARCH == "armeabi-v7a" ]
then
unsetarm32ENV
fi
if [ $ARCH == "arm64-v8a" ]
then
unsetarm64ENV
fi
unset host
echo "The test must be on an OpenHarmony device!"
# real test
# copy 依赖库
# make -C test check-TESTS
}
cleanbuild(){
rm -rf ${PWD}/$builddir #${PWD}/$packagename
}
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键技术点:
- autogen.sh:需要先生成 configure 脚本
- **显式****设置 FREETYPE_CFLAGS/**LIBS:fontconfig 需要直接指定 freetype2 及其所有依赖的库路径
FREETYPE_CFLAGS="-I.../include/freetype2 .../libbz2.a .../libpng.a .../libbrotlicommon.so -lz"
FREETYPE_LIBS=".../libfreetype.a"
CFLAGS="$FREETYPE_CFLAGS $FREETYPE_LIBS"
- configure 选项:
- –disable-libxml2:禁用 libxml2 依赖
- –enable-static --enable-shared:同时构建静态库和动态库
构建命令:
# 按顺序构建所有依赖
./build.sh freetype2
./build.sh libexpat
./build.sh fontconfig
3.4 harfbuzz - 文本整形引擎
依赖关系:依赖 freetype2、zlib、libpng、brotli、bzip2
HPKBUILD 完整配置:
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Contributor: 小肉头君 <chenbaodi@huawei.com>, 城meto <myxuan475@126.com>
# Maintainer: 小肉头君 <chenbaodi@huawei.com>
pkgname=harfbuzz
pkgver=7.1.0
pkgrel=0
pkgdesc="HarfBuzz text shaping engine."
url="https://github.com/harfbuzz/harfbuzz"
archs=("arm64-v8a")
license=("Old MIT" "OFL-1.1" "MIT" "Apache-2.0")
depends=("freetype2" "zlib" "libpng" "brotli" "bzip2")
makedepends=()
# 原仓地址: https://github.com/$pkgname/$pkgname/archive/refs/tags/$pkgver.tar.gz, 因网络原因使用镜像
source="https://gitee.com/lycium_pkg_mirror/$pkgname/repository/archive/$pkgver.zip"
autounpack=true
downloadpackage=true
buildtools="configure"
builddir=$pkgname-$pkgver
packagename=$builddir.zip
source envset.sh
autogenflag=true
host=
firstflag=true
prepare() {
if [ $firstflag == true ]
then
firstflag=false
#这里屏蔽使用python脚本来检测参数,oh上面不支持python
sed -i 's/^TESTS += \$(dist_check_SCRIPTS/#TESTS += \$(dist_check_SCRIPTS/g' $builddir/src/Makefile.am
fi
mkdir -p $builddir/$ARCH-build
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
host=arm-linux
fi
if [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
host=aarch64-linux
fi
if $autogenflag
then
cd $builddir
./autogen.sh > `pwd`/build.log 2>&1
cd $OLDPWD
autogenflag=false
fi
}
build() {
cd $builddir/$ARCH-build
# 显式设置 C 预处理器,避免 configure 自动检测使用 C++ 编译器
export CPP="${CC:-${LYCIUM_ROOT}/../toolchain/${host}-ohos-clang} -E"
# 添加 bzip2 库路径到 LDFLAGS
export LDFLAGS="-L${LYCIUM_ROOT}/usr/bzip2/$ARCH/lib"
PKG_CONFIG_LIBDIR=${pkgconfigpath} ../configure "$@" --host=$host --with-freetype=yes --with-icu=no --with-glib=no -with-cairo=no --enable-static > `pwd`/build.log 2>&1
make -j4 VERBOSE=1 >> `pwd`/build.log 2>&1
ret=$?
cd $OLDPWD
return $ret
}
# 安装打包
package() {
cd $builddir
make -C $ARCH-build install >> `pwd`/$ARCH-build/build.log 2>&1
cd $OLDPWD
}
# 测试,需要在 ohos 设备上进行
check() {
cd $builddir/$ARCH-build/src
make test-algs test-array test-bimap test-iter test-machinery test-map test-multimap test-number test-ot-tag test-priority-queue test-set test-serialize test-unicode-ranges test-vector test-repacker test-classdef-graph >> `pwd`/../build.log 2>&1
if [ $ARCH == "armeabi-v7a" ]
then
unsetarm32ENV
fi
if [ $ARCH == "arm64-v8a" ]
then
unsetarm64ENV
fi
sed -i 's/^check-TESTS: \$(check_PROGRAMS/check-TESTS: #\$(check_PROGRAMS/g' Makefile
sed -i 's/^test-algs.log: test-algs/test-algs.log:# test-algs/g' Makefile
sed -i 's/^test-array.log: test-array/test-array.log:# test-array/g' Makefile
sed -i 's/^test-bimap.log: test-bimap/test-bimap.log:# test-bimap/g' Makefile
sed -i 's/^test-iter.log: test-iter/test-iter.log:# test-iter/g' Makefile
sed -i 's/^test-machinery.log: test-machinery/test-machinery.log:# test-machinery/g' Makefile
sed -i 's/^test-map.log: test-map/test-map.log:# test-map/g' Makefile
sed -i 's/^test-multimap.log: test-multimap/test-multimap.log:# test-multimap/g' Makefile
sed -i 's/^test-number.log: test-number/test-number.log:# test-number/g' Makefile
sed -i 's/^test-ot-tag.log: test-ot-tag/test-ot-tag.log:# test-ot-tag/g' Makefile
sed -i 's/^test-priority-queue.log: test-priority-queue/test-priority-queue.log:# test-priority-queue/g' Makefile
sed -i 's/^test-set.log: test-set/test-set.log:# test-set/g' Makefile
sed -i 's/^test-serialize.log: test-serialize/test-serialize.log:# test-serialize/g' Makefile
sed -i 's/^test-unicode-ranges.log: test-unicode-ranges/test-unicode-ranges.log:# test-unicode-ranges/g' Makefile
sed -i 's/^test-vector.log: test-vector/test-vector.log:# test-vector/g' Makefile
sed -i 's/^test-repacker.log: test-repacker/test-repacker.log:# test-repacker/g' Makefile
sed -i 's/^test-classdef-graph.log: test-classdef-graph/test-classdef-graph.log:# test-classdef-graph/g' Makefile
cd $OLDPWD
unset host
echo "The test must be on an OpenHarmony device!"
# real test CMD
# make -C src check-TESTS
}
# 清理环境
cleanbuild(){
rm -rf ${PWD}/$builddir #${PWD}/$packagename
}
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键技术点:
- Makefile.am 修改:屏蔽 Python 脚本检测(鸿蒙不支持 Python)
sed -i 's/^TESTS += \$(dist_check_SCRIPTS/#TESTS += \$(dist_check_SCRIPTS/g' $builddir/src/Makefile.am
- LDFLAGS 设置:显式添加 bzip2 库路径
export LDFLAGS="-L${LYCIUM_ROOT}/usr/bzip2/$ARCH/lib"
- configure 选项:
- –with-freetype=yes:启用 freetype2 支持
- –with-icu=no:禁用 ICU(国际化组件)
- –with-glib=no:禁用 glib 依赖
- –with-cairo=no:禁用 Cairo 图形库
构建命令:
# 按顺序构建所有依赖
./build.sh freetype2
./build.sh zlib
./build.sh libpng
./build.sh brotli
./build.sh bzip2
./build.sh harfbuzz
四、第 3 层:核心依赖库适配
4.1 libass - 字幕渲染库
依赖关系:依赖 freetype2、fribidi、harfbuzz、libpng、zlib、fontconfig
HPKBUILD 完整配置:
# Contributor: 小肉头君 <chenbaodi@huawei.com>
# Maintainer: 小肉头君 <chenbaodi@huawei.com>
pkgname=libass
pkgver=0.17.1
pkgrel=0
pkgdesc="libass is a portable subtitle renderer for the ASS/SSA (Advanced Substation Alpha/Substation Alpha) subtitle format."
url="https://github.com/libass/libass"
archs=("arm64-v8a")
license=("ISC License")
depends=("freetype2" "fribidi" "harfbuzz" "libpng" "zlib" "fontconfig") # fontconfig是测试需要的三方库
makedepends=()
source="https://github.com/$pkgname/$pkgname/archive/refs/tags/$pkgver.tar.gz"
autounpack=true
downloadpackage=true
buildtools="configure"
builddir=$pkgname-$pkgver
packagename=$builddir.tar.gz
source envset.sh
autogenflag=true
host=
prepare() {
mkdir -p $builddir/$ARCH-build
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
host=arm-linux
fi
if [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
host=aarch64-linux
fi
if $autogenflag
then
cd $builddir
./autogen.sh > $buildlog 2>&1
cd $OLDPWD
autogenflag=false
fi
}
build() {
cd $builddir/$ARCH-build
# 显式设置 C 预处理器,避免 configure 自动检测使用 C++ 编译器
export CPP="${CC:-${LYCIUM_ROOT}/../toolchain/${host}-ohos-clang} -E"
# 设置 PKG_CONFIG_PATH 包含所有依赖库的 pkgconfig
export PKG_CONFIG_PATH="${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/fribidi/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/fontconfig/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/libexpat/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/libpng/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/zlib/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/bzip2/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/brotli/$ARCH/lib/pkgconfig"
FRIBIDI_CFLAGS="-I${LYCIUM_ROOT}/usr/fribidi/$ARCH/usr/include/fribidi -I${LYCIUM_ROOT}/usr/fribidi/$ARCH/usr/include" FRIBIDI_LIBS="-L${LYCIUM_ROOT}/usr/fribidi/$ARCH/usr/lib -lfribidi" FREETYPE_CFLAGS="-I${LYCIUM_ROOT}/usr/freetype2/$ARCH/include/freetype2" FREETYPE_LIBS="-L${LYCIUM_ROOT}/usr/freetype2/$ARCH/lib -L${LYCIUM_ROOT}/usr/brotli/$ARCH/lib -L${LYCIUM_ROOT}/usr/bzip2/$ARCH/lib -lfreetype -lbz2 -lbrotlicommon -lbrotlienc -lbrotlidec -lz" FONTCONFIG_CFLAGS="-I${LYCIUM_ROOT}/usr/fontconfig/$ARCH/include" FONTCONFIG_LIBS="-L${LYCIUM_ROOT}/usr/fontconfig/$ARCH/lib -L${LYCIUM_ROOT}/usr/libexpat/$ARCH/lib -lfontconfig -lexpat" HARFBUZZ_CFLAGS="-I${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/include/harfbuzz" HARFBUZZ_LIBS="-L${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/lib -lharfbuzz" ../configure "$@" --enable-test --enable-static --host=$host >> $buildlog 2>&1
make -j4 >> `pwd`/build.log 2>&1
# 对最关键一步的退出码进行判断
ret=$?
cd $OLDPWD
return $ret
}
package() {
cd $builddir/$ARCH-build
make install >> $buildlog 2>&1
cd $OLDPWD
if [ $ARCH == "armeabi-v7a" ]
then
unsetarm32ENV
fi
if [ $ARCH == "arm64-v8a" ]
then
unsetarm64ENV
fi
unset host
}
check() {
echo "The test must be on an OpenHarmony device!"
# real test
# 测试时需要把Unbutu中的usr/share/fonts打包推送到ohos设备中,放在ohos设备同一路径中
# ./test/test testass.png ../compare/test/sub1.ass 0.03
}
cleanbuild(){
rm -rf ${PWD}/$builddir #${PWD}/$packagename
}
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}

关键技术点:
- 硬编码 PKG_CONFIG_PATH:libass 不使用循环收集,而是直接硬编码所有依赖路径
export PKG_CONFIG_PATH="${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/$ARCH/lib/pkgconfig:..."
- **显式****设置 CFLAGS/**LIBS:每个依赖库都需要单独指定头文件和库路径
FRIBIDI_CFLAGS="-I.../usr/include/fribidi -I.../usr/include"
FRIBIDI_LIBS="-L.../usr/lib -lfribidi"
FREETYPE_CFLAGS="-I.../include/freetype2"
FREETYPE_LIBS="-L.../lib -L.../brotli/lib -L.../bzip2/lib -lfreetype -lbz2 -lbrotlicommon ..."
FONTCONFIG_CFLAGS="-I.../include"
FONTCONFIG_LIBS="-L.../lib -L.../libexpat/lib -lfontconfig -lexpat"
HARFBUZZ_CFLAGS="-I.../include/harfbuzz"
HARFBUZZ_LIBS="-L.../lib -lharfbuzz"
- fribidi 路径特殊:头文件在 usr/include/fribidi 而非 include
- configure 选项:
- –enable-test:启用测试(需要字体文件)
- –enable-static:构建静态库
构建命令:
# 必须先构建所有依赖
./build.sh freetype2
./build.sh fontconfig
./build.sh harfbuzz
./build.sh fribidi
./build.sh libass
4.2 libplacebo - GPU 渲染库
依赖关系:无运行时依赖(构建时依赖 meson、ninja)
HPKBUILD 完整配置:
#!/bin/bash
# HPKBUILD for libplacebo
# =============================================================================
# libplacebo OpenHarmony 适配脚本
# -----------------------------------------------------------------------------
# - 使用 Meson 构建系统
# - 高性能视频渲染库,支持多种 GPU 后端
# - 依赖:Vulkan-Headers(已包含在 3rdparty)
# - 注意:鸿蒙可能无完整 Vulkan 支持,尝试编译核心库
# =============================================================================
# Contributor: OpenHarmony adaptation
# Maintainer: OpenHarmony adaptation
# --- 包元数据(lycium 索引与下载用)---
pkgname=libplacebo
pkgver=7.362
pkgrel=0
pkgdesc="Reusable library for GPU-accelerated video/image rendering primitives"
url="https://code.videolan.org/videolan/libplacebo"
# 交叉目标 ABI;鸿蒙 arm64-v8a
archs=("arm64-v8a")
license=("LGPL-2.1-or-later")
# 运行时依赖:无
depends=()
# 构建依赖:meson, ninja
makedepends=("meson" "ninja")
# 使用本地源码
autounpack=false
downloadpackage=false
buildtools="meson"
# 本地源码路径
srcpath="${LYCIUM_ROOT}/../Projects/${pkgname}"
# 源码目录名
builddir="${pkgname}-${pkgver}"
# -----------------------------------------------------------------------------
# prepare():准备源码目录
# -----------------------------------------------------------------------------
prepare() {
if [ -d "$srcpath" ]; then
echo "Using local source from: $srcpath"
mkdir -p "$builddir"
# 复制整个 libplacebo 源码
cp -rf "$srcpath"/* "$builddir/"
cp -rf "$srcpath"/.git* "$builddir/" 2>/dev/null || true
# 初始化子模块(3rdparty 依赖)
if [ -f "$builddir/.gitmodules" ]; then
cd "$builddir"
git submodule update --init --recursive 2>/dev/null || true
cd ..
fi
# 清理不必要的文件
find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
echo "Prepare completed in: $builddir"
else
echo "ERROR: Source not found at $srcpath"
exit 1
fi
}
# -----------------------------------------------------------------------------
# build():使用 Meson 构建 libplacebo
# -----------------------------------------------------------------------------
build() {
cd "$builddir"
# 设置交叉编译环境变量
export CC="${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang"
export CXX="${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang++"
export AR="${OHOS_SDK}/native/llvm/bin/llvm-ar"
export RANLIB="${OHOS_SDK}/native/llvm/bin/llvm-ranlib"
export STRIP="${OHOS_SDK}/native/llvm/bin/llvm-strip"
export CFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC"
export CXXFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC"
export LDFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot"
# 创建 Meson 交叉编译配置文件
cat > ohos-cross.ini << EOF
[binaries]
c = '${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang'
cpp = '${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang++'
ar = '${OHOS_SDK}/native/llvm/bin/llvm-ar'
strip = '${OHOS_SDK}/native/llvm/bin/llvm-strip'
pkgconfig = 'pkg-config'
[built-in options]
c_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC']
cpp_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC']
c_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot']
cpp_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot']
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
EOF
# Meson 配置:禁用 Vulkan 等可能不支持的特性
meson setup ohos-build \
--cross-file ohos-cross.ini \
--prefix=/usr \
--buildtype=release \
-D vulkan=disabled \
-D opengl=disabled \
-D d3d11=disabled \
-D glslang=disabled \
-D shaderc=disabled \
-D lcms=disabled \
-D dovi=disabled \
-D libdovi=disabled \
-D demos=false \
-D tests=false \
-D bench=false \
> "$buildlog" 2>&1
ret=$?
if [ $ret -ne 0 ]; then
echo "Meson configuration failed!"
cat "$buildlog" >&2
cd "$OLDPWD"
return $ret
fi
# 编译
ninja -C ohos-build >> "$buildlog" 2>&1
ret=$?
if [ $ret -ne 0 ]; then
echo "Build failed!"
cat "$buildlog" >&2
cd "$OLDPWD"
return $ret
fi
echo "Build completed successfully!"
cd "$OLDPWD"
}
# -----------------------------------------------------------------------------
# package():打包产物
# -----------------------------------------------------------------------------
package() {
cd "$builddir"
# 使用 lycium 标准的 destdir 变量
: ${destdir:=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}}
# 手动复制编译产物
mkdir -p "${destdir}/usr/lib"
mkdir -p "${destdir}/usr/include"
mkdir -p "${destdir}/usr/lib/pkgconfig"
# 复制库文件
cp -f ohos-build/src/libplacebo.so* "${destdir}/usr/lib/" 2>/dev/null || true
# 复制头文件
cp -rf src/include/libplacebo "${destdir}/usr/include/" 2>/dev/null || true
# 复制构建生成的 config.h
if [ -f ohos-build/src/include/libplacebo/config.h ]; then
cp -f ohos-build/src/include/libplacebo/config.h "${destdir}/usr/include/libplacebo/"
echo " ✅ Installed config.h"
fi
# 复制 pkg-config 文件
if [ -f ohos-build/meson-private/libplacebo.pc ]; then
cp -f ohos-build/meson-private/libplacebo.pc "${destdir}/usr/lib/pkgconfig/"
fi
echo "Package completed!"
cd "$OLDPWD"
}
# -----------------------------------------------------------------------------
# check():验证构建产物
# -----------------------------------------------------------------------------
check() {
: ${destdir:=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}}
# 检查关键文件是否存在
if [ ! -f "${destdir}/usr/lib/libplacebo.so" ] && [ ! -f "${destdir}/usr/lib/libplacebo.a" ]; then
echo "ERROR: libplacebo library not found!"
exit 1
fi
if [ ! -d "${destdir}/usr/include/libplacebo" ]; then
echo "ERROR: libplacebo header not found!"
exit 1
fi
echo "Check passed!"
}
# -----------------------------------------------------------------------------
# archive():打包成 tar.gz 和 HNP
# -----------------------------------------------------------------------------
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}
# -----------------------------------------------------------------------------
# cleanbuild():清理构建产物
# -----------------------------------------------------------------------------
cleanbuild() {
echo "Cleaning build artifacts for ${pkgname}..."
# 清理构建目录
rm -rf "${LYCIUM_ROOT}/../thirdparty/${pkgname}/${pkgname}-${pkgver}"
# 清理 output
rm -rf "${LYCIUM_ROOT}/output/${pkgname}"*
# 清理 usr 产物
rm -rf "${LYCIUM_ROOT}/usr/${pkgname}"
echo "Clean completed"
}

关键技术点:
- 本地****源码:使用 autounpack=false 和 srcpath 从 Projects 目录复制源码
- 子模块初始化:git submodule update --init --recursive 初始化 3rdparty 依赖
- 禁用 GPU 特性:鸿蒙 PC 可能无完整 Vulkan 支持,需要禁用
-D vulkan=disabled
-D opengl=disabled
-D d3d11=disabled
-D glslang=disabled
-D shaderc=disabled
- config.h 必须复制:这是 Meson 构建时生成的配置文件,未包含在源码中
- pkg-config 文件:需要手动复制 libplacebo.pc 到 pkgconfig 目录
构建命令:
# libplacebo 无运行时依赖,直接构建
./build.sh libplacebo
4.3 FFmpeg - 音视频编解码库
依赖关系:依赖 zlib、libiconv 等
HPKBUILD 关键配置:
# Contributor: Jeff Han <hanjinfei@foxmail.com>
# Maintainer: Jeff Han <hanjinfei@foxmail.com>
pkgname=FFmpeg
pkgver=8.0
pkgrel=0
pkgdesc="FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata."
url="https://github.com/FFmpeg/FFmpeg/"
archs=("armeabi-v7a" "arm64-v8a")
license=("GPL2" "GPL3" "LGPL3" "MIT" "X11" "BSD-styl")
depends=("openssl_1_1_1w")
makedepends=()
source="https://github.com/FFmpeg/$pkgname/archive/refs/tags/$pkgver.tar.gz"
autounpack=false
downloadpackage=false
buildtools="configure"
builddir=$pkgname-${pkgver}
packagename=$builddir.tar.gz
srcpath="${LYCIUM_ROOT}/../Projects/FFmpeg"
source envset.sh
buildhost=true
arch=
ldflags=
prepare() {
if [ -d "$srcpath" ]; then
echo "Using local source from: $srcpath"
mkdir -p "$builddir"
cp -rf "$srcpath"/* "$builddir/"
find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
find "$builddir" -name "*Zone.Identifier" -type f -delete 2>/dev/null || true
# 添加执行权限
chmod +x "$builddir/configure" 2>/dev/null || true
find "$builddir" -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true
echo "Prepare completed in: $builddir"
else
echo "ERROR: Source not found at $srcpath"
exit 1
fi
mkdir -p $pkgname-$ARCH-build
cp -rf $builddir $pkgname-$ARCH-build/
# 构建主机工具(bin2c 等)
if [ $buildhost == true ]; then
echo "Building host tools..."
cd $pkgname-$ARCH-build/$builddir
./configure --enable-static --disable-shared --disable-doc \
--target-os=linux --disable-optimizations > $publicbuildlog 2>&1
$MAKE tools/bin2c >> $publicbuildlog 2>&1 || $MAKE ffbuild/bin2c >> $publicbuildlog 2>&1
buildhost=false
cd $OLDPWD
fi
cd $pkgname-$ARCH-build/$builddir
if [ -f ../../FFmpeg_oh_test.patch ]; then
patch -p1 < ../../FFmpeg_oh_test.patch
fi
cd $OLDPWD
if [ $ARCH == "armeabi-v7a" ]
then
setarm32ENV
arch=arm
ldflags="-L${OHOS_SDK}/native/sysroot/usr/lib/arm-linux-ohos"
elif [ $ARCH == "arm64-v8a" ]
then
setarm64ENV
arch=aarch64
ldflags="-L${OHOS_SDK}/native/sysroot/usr/lib/aarch64-linux-ohos"
else
echo "${ARCH} not support"
return -1
fi
return $ret
}
build() {
cd $pkgname-$ARCH-build/$builddir
PKG_CONFIG_LIBDIR="${pkgconfigpath}" ./configure "$@" --enable-neon --enable-asm --enable-network \
--disable-vulkan --enable-cross-compile --disable-librtmp --disable-x86asm --enable-openssl --enable-protocols \
--enable-static --enable-shared --disable-doc --disable-htmlpages --target-os=linux --arch=$arch \
--cc=${CC} --ld=${CC} --strip=${STRIP} --host-cc="gcc" --host-ld="gcc" --host-os=linux \
--host-ldflags=${ldflags} --sysroot=${OHOS_SDK}/native/sysroot > $buildlog 2>&1
$MAKE >> $buildlog 2>&1
ret=$?
cd $OLDPWD
return $ret
}
package() {
cd $pkgname-$ARCH-build/$builddir
$MAKE install >> $buildlog 2>&1
cd $OLDPWD
}
archive() {
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
# 打包 HNP
if [ -f "${HNP_TOOL}" ]; then
cp ${LYCIUM_ROOT}/../thirdparty/ffmpeg/hnp.json ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/
${HNP_TOOL} pack \
-i ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} \
-o ${LYCIUM_ROOT}/output/$ARCH/
echo "HNP pack completed: ${LYCIUM_ROOT}/output/$ARCH/${pkgname}.hnp"
else
echo "WARNING: hnpcli not found, skip HNP packaging"
fi
}
checktestfiles() {
cd $pkgname-$ARCH-build/$builddir/tests/ref
tmpdir=("fate" "acodec" "lavf" "lavf-fate" "pixfmt" "seek" "vsynth")
for dir in ${tmpdir[*]}
do
for file in `ls $dir`
do
if [ ! -f $dir/$file ]; then
continue
fi
str=`cat $dir/$file | grep "\*tests"`
if [ ! -z "$str" ]
then
sed -i.bak 's/\*tests/tests/g' $dir/$file
fi
done
done
cd $OLDPWD
}
copyhostbin() {
file=$1
if [[ -f tests/$file ]] && [[ ! -f tests/$file.${ARCH} ]]
then
mv tests/$file tests/$file.${ARCH}
cp ../../$builddir/tests/$file tests/$file
fi
}
check() {
# 跳过测试(需要 x86_64 测试工具,交叉编译环境不支持)
return 0
cd $pkgname-$ARCH-build/$builddir
# disable running cmd
sed -i.bak 's/ $(Q)$(SRC_PATH)\/tests\/fate-run.sh/# $(Q)$(SRC_PATH)\/tests\/fate-run.sh/g' tests/Makefile
# disable check git sources
sed -i.bak 's/include $(SRC_PATH)\/tests\/fate\/source.mak/#include $(SRC_PATH)\/tests\/fate\/source.mak/g' tests/Makefile
# disable check ffprobe,this use xmllint command, which ohos is not support
sed -i.bak 's/include $(SRC_PATH)\/tests\/fate\/ffprobe.mak/#include $(SRC_PATH)\/tests\/fate\/ffprobe.mak/g' tests/Makefile
# change x86 cmd for generate test target
mv ffmpeg ffmpeg.${ARCH} 2>/dev/null || true
# 如果主机工具已构建,直接使用当前目录的 ffmpeg
if [ ! -f ffmpeg ]; then
cp ../../$builddir/ffmpeg ./ 2>/dev/null || true
fi
retrytimes=0
ret=0
while true
do
$MAKE check >> $buildlog 2>&1
if [ $? -eq 0 ]
then
break;
fi
copyhostbin base64
copyhostbin audiomatch
copyhostbin audiogen
copyhostbin videogen
copyhostbin tiny_psnr
copyhostbin tiny_ssim
copyhostbin rotozoom
let retrytimes=$retrytimes+1
if [ $retrytimes -gt 4 ]
then
ret=1
break
fi
done
mv ffmpeg.${ARCH} ffmpeg
for file in `ls tests/*.${ARCH}`
do
tmpfile=${file%.*}
mv $file $tmpfile
done
# reduction running cmd for real test
sed -i.bak 's/# $(Q)$(SRC_PATH)\/tests\/fate-run.sh/ $(Q)$(SRC_PATH)\/tests\/fate-run.sh/g' tests/Makefile
cd $OLDPWD
checktestfiles
echo "The test must be on an OpenHarmony device!"
# skip running test on host
# real test CMD
# make check
return $ret
}
recoverpkgbuildenv() {
unset arch
unset ldflags
if [ $ARCH == "armeabi-v7a" ]
then
unsetarm32ENV
elif [ $ARCH == "arm64-v8a" ]
then
unsetarm64ENV
else
echo "${ARCH} not support"
return -1
fi
}
# 清理环境
cleanbuild() {
rm -rf ${PWD}/${builddir} ${PWD}/$pkgname-arm64-v8a-build ${PWD}/$pkgname-armeabi-v7a-build #${PWD}/$packagename
}

关键技术点:
- FFmpeg 使用自有的 configure 系统
- –enable-cross-compile 启用交叉编译
- –enable-shared 构建动态库
- –extra-cflags 和 --extra-ldflags 传递交叉编译参数
构建命令:
./build.sh zlib
./build.sh FFmpeg
五、第 4 层:目标库 mpv 适配
5.1 mpv - 媒体播放器
依赖关系:依赖 FFmpeg、libplacebo、libass(传递依赖包含 11 个库)
完整的依赖链:
mpv 直接依赖:
├── FFmpeg
├── libplacebo
└── libass
mpv 传递依赖(通过 libass):
├── fontconfig
│ ├── freetype2
│ │ ├── zlib
│ │ ├── libpng
│ │ └── brotli
│ └── libexpat
├── harfbuzz
│ ├── freetype2 (已包含)
│ └── glib
│ ├── libffi
│ └── pcre2
└── fribidi
mpv 传递依赖(通过 libplacebo):
├── vulkan-headers
└── spirv-headers
总计:14 个依赖库
HPKBUILD 完整配置:
#!/bin/bash
# -----------------------------------------------------------------------------
# mpv HPKBUILD - OpenHarmony 鸿蒙适配
# -----------------------------------------------------------------------------
pkgname=mpv
pkgver=0.41.0
pkgrel=0
pkgdesc="A free, open source, and cross-platform media player"
url="https://mpv.io"
archs=("arm64-v8a")
license=("LGPL-2.1-or-later")
depends=("FFmpeg" "libplacebo")
makedepends=("meson" "ninja")
autounpack=false
downloadpackage=false
buildtools="meson"
srcpath="${LYCIUM_ROOT}/../Projects/${pkgname}"
builddir="${pkgname}-${pkgver}"
# -----------------------------------------------------------------------------
# prepare():准备源码
# -----------------------------------------------------------------------------
prepare() {
if [ -d "$srcpath" ]; then
echo "Using local source from: $srcpath"
mkdir -p "$builddir"
cp -rf "$srcpath"/* "$builddir/"
find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
echo "Prepare completed in: $builddir"
else
echo "ERROR: Source not found at $srcpath"
exit 1
fi
}
# -----------------------------------------------------------------------------
# build():编译构建
# -----------------------------------------------------------------------------
build() {
cd "$builddir"
# 设置交叉编译环境变量
export CC="${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang"
export CXX="${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang++"
export AR="${OHOS_SDK}/native/llvm/bin/llvm-ar"
export RANLIB="${OHOS_SDK}/native/llvm/bin/llvm-ranlib"
export STRIP="${OHOS_SDK}/native/llvm/bin/llvm-strip"
export CFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
export CXXFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot -O2 -fPIC -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
export LDFLAGS="--target=aarch64-linux-ohos --sysroot=${OHOS_SDK}/native/sysroot"
# 创建 Meson 交叉编译配置文件
cat > ohos-cross.ini << EOF
[binaries]
c = '${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang'
cpp = '${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang++'
ar = '${OHOS_SDK}/native/llvm/bin/llvm-ar'
strip = '${OHOS_SDK}/native/llvm/bin/llvm-strip'
pkgconfig = 'pkg-config'
[properties]
pkg_config_path = ['${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libexpat/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig', '${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig', '${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig']
[built-in options]
c_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC', '-I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include']
cpp_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-O2', '-fPIC', '-I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include']
c_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
cpp_link_args = ['--target=aarch64-linux-ohos', '--sysroot=${OHOS_SDK}/native/sysroot', '-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
EOF
# 设置 FFmpeg、libplacebo 和 libass 及其所有依赖的 pkg-config 路径
export PKG_CONFIG_PATH="${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libexpat/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig:${PKG_CONFIG_PATH}"
export PKG_CONFIG_LIBDIR="${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fontconfig/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libexpat/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/harfbuzz/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/zlib/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/libpng/${ARCH}/lib/pkgconfig:${LYCIUM_ROOT}/usr/brotli/${ARCH}/lib/pkgconfig"
echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
pkg-config --list-all | grep -E 'libav|libplacebo|libass' || true
# 设置 LDFLAGS 包含 libplacebo 的库路径
export LDFLAGS="-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib ${LDFLAGS}"
# Meson 配置:禁用图形界面和不支持的特性
meson setup ohos-build \
--cross-file ohos-cross.ini \
--prefix=/usr \
--buildtype=release \
-Dgpl=false \
-Dcplayer=false \
-Dlibmpv=true \
-Dbuild-date=false \
-Dtests=false \
-Dfuzzers=false \
-Dmanpage-build=disabled \
-Dcdda=disabled \
-Ddvbin=disabled \
-Ddvdnav=disabled \
-Djavascript=disabled \
-Djpeg=disabled \
-Dlcms2=disabled \
-Dlibarchive=disabled \
-Dlibavdevice=disabled \
-Dlibbluray=disabled \
-Dlua=disabled \
-Drubberband=disabled \
-Dsdl2-gamepad=disabled \
-Dsdl2-audio=disabled \
-Dsdl2-video=disabled \
-Dsubrandr=disabled \
-Duchardet=disabled \
-Dvapoursynth=disabled \
-Dzimg=disabled \
-Dalsa=disabled \
-Daudiounit=disabled \
-Dcoreaudio=disabled \
-Djack=disabled \
-Dopenal=disabled \
-Dopensles=disabled \
-Doss-audio=disabled \
-Dpipewire=disabled \
-Dpulse=disabled \
-Dsndio=disabled \
-Dgl=disabled \
-Degl-android=disabled \
-Degl-x11=disabled \
-Degl-wayland=disabled \
-Ddrm=disabled \
-Dgbm=disabled \
-Dx11=disabled \
-Dwayland=disabled \
-Dcocoa=disabled \
-Dmacos-media-player=disabled \
-Dios-gl=disabled \
-Dandroid-media-ndk=disabled \
-Dcaca=disabled \
-Dplain-gl=disabled \
-Dzlib=enabled \
> "$buildlog" 2>&1
ret=$?
if [ $ret -ne 0 ]; then
echo "Meson configuration failed!"
cat "$buildlog" >&2
cd "$OLDPWD"
return $ret
fi
# 编译
ninja -C ohos-build >> "$buildlog" 2>&1
ret=$?
cd "$OLDPWD"
return $ret
}
# -----------------------------------------------------------------------------
# check():验证构建产物
# -----------------------------------------------------------------------------
check() {
echo "The test must be on an OpenHarmony device!"
}
# -----------------------------------------------------------------------------
# package():打包产物
# -----------------------------------------------------------------------------
package() {
: ${destdir:=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}}
# 进入源码目录
cd ${builddir}
# 手动复制编译产物
mkdir -p "${destdir}/usr/bin"
mkdir -p "${destdir}/usr/lib"
mkdir -p "${destdir}/usr/include/mpv"
# 复制 mpv 可执行文件
if [ -f ohos-build/mpv ]; then
cp -f ohos-build/mpv "${destdir}/usr/bin/mpv"
chmod +x "${destdir}/usr/bin/mpv"
echo " ✅ Installed mpv binary"
fi
# 复制 libmpv 库文件
if ls ohos-build/libmpv.so* 1> /dev/null 2>&1; then
find ohos-build -maxdepth 1 -name 'libmpv.so*' -type f -exec cp -f {} "${destdir}/usr/lib/" \;
echo " ✅ Installed libmpv library"
fi
# 复制头文件
if [ -d include/mpv ]; then
cp -rf include/mpv/* "${destdir}/usr/include/mpv/"
echo " ✅ Installed mpv headers"
fi
find "${destdir}" -name "*.bak" -type f -delete 2>/dev/null || true
find "${destdir}" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
echo "Package completed!"
return 0
}
# -----------------------------------------------------------------------------
# archive():打包成 tar.gz 和 HNP
# -----------------------------------------------------------------------------
archive() {
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
# 打包 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
echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
fi
}
# -----------------------------------------------------------------------------
# cleanbuild():清理构建产物
# -----------------------------------------------------------------------------
cleanbuild() {
echo "Cleaning build artifacts for ${pkgname}..."
# 清理构建目录
rm -rf "${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}"
# 清理 output
rm -rf "${LYCIUM_ROOT}/output/${pkgname}"*
# 清理 usr 产物
rm -rf "${LYCIUM_ROOT}/usr/${pkgname}"
echo "Clean completed"
}

关键技术点:
- pkg_config_path 包含 11 个路径:
- 直接依赖:FFmpeg、libplacebo、libass
- 传递依赖:fontconfig、harfbuzz、fribidi、freetype2、zlib、libpng、brotli、libexpat
- fribidi 路径特殊:
'${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/lib/pkgconfig'
# 注意是 usr/lib/pkgconfig 而非 lib/pkgconfig
- libplacebo 路径特殊:
'${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig'
# 注意是 usr/lib/pkgconfig 而非 lib/pkgconfig
- 头文件路径显式添加:
export CFLAGS="... -I${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/include"
- 链接路径显式添加:
c_link_args = ['...','-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
构建命令:
# 完整构建流程(按依赖顺序)
cd lycium_plusplus/lycium
# 第 1 层:基础依赖
./build.sh zlib
./build.sh libpng
./build.sh brotli
./build.sh libexpat
./build.sh fribidi
./build.sh libffi
./build.sh pcre2
# 第 2 层:中间依赖
./build.sh glib
./build.sh freetype2
./build.sh harfbuzz
./build.sh fontconfig
# 第 3 层:核心依赖
./build.sh libass
./build.sh vulkan-headers
./build.sh spirv-headers
./build.sh libplacebo
./build.sh FFmpeg
# 第 4 层:目标库
./build.sh mpv
5.2 鸿蒙PC 上验证结果

解压 mpv 编译产物,进入库目录后查看文件,验证该 arm64 架构 ELF 共享库的有效性,再为其添加执行权限,最后执行鸿蒙系统签名操作
# 解压mpv编译产物
tar -zxf mpv_0.41.0.tar.gz
# 进入库目录
cd usr/lib
# 查看文件是否存在
ls
# 验证是否为鸿蒙 arm64 有效库(核心验证)
file libmpv.so.2.5.0
# 查看ELF魔数,确认架构合法
od -N 4 libmpv.so.2.5.0
通过 strings 命令提取 libmpv.so.2.5.0 共享库中的字符串信息,并结合 grep 过滤出版本号相关内容,成功匹配到 mpv v0.41.0-UNKNOWN 标识,验证了该动态库的版本正确性与编译完整性
strings libmpv.so.2.5.0 | grep "0.41.0"

六、多层依赖管理核心技巧
6.1 依赖状态检查
lycium 使用 usr/hpk_build.csv 跟踪构建状态:
# 查看某个库的构建状态
cat usr/hpk_build.csv | grep freetype2
# 查看所有已构建的库
cat usr/hpk_build.csv | awk -F',' '{print $1}' | sort -u
6.2 依赖构建失败处理
# 清理特定库的构建状态
cat usr/hpk_build.csv | grep -v freetype2 > /tmp/hpk_temp.csv
mv /tmp/hpk_temp.csv usr/hpk_build.csv
# 清理产物
rm -rf usr/freetype2
rm -rf ../thirdparty/freetype2/freetype2-*/
# 重新构建
./build.sh freetype2
6.3 pkg-config 路径调试
# 在 build() 函数中添加调试输出
echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
pkg-config --list-all | grep -E 'libav|libplacebo|libass|fontconfig|harfbuzz|freetype2' || true
6.4 头文件路径验证
# 验证各库头文件是否存在
ls /home/weishuo/lycium_plusplus/lycium/usr/libplacebo/arm64-v8a/usr/include/libplacebo/
ls /home/weishuo/lycium_plusplus/lycium/usr/fribidi/arm64-v8a/usr/include/
ls /home/weishuo/lycium_plusplus/lycium/usr/fontconfig/arm64-v8a/include/
七、常见问题与解决方案(FAQ)
Q1:构建 mpv 时报错 “dependency libass not found”?
A:libass 未构建或 pkg-config 路径不完整。
# 检查 libass 状态
cat usr/hpk_build.csv | grep libass
# 构建 libass 及其依赖
./build.sh fontconfig
./build.sh harfbuzz
./build.sh fribidi
./build.sh libass
# 验证 pkg-config
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:${LYCIUM_ROOT}/usr/libass/${ARCH}/lib/pkgconfig"
pkg-config --list-all | grep libass
Q2:编译时报错 “fatal error: fribidi.h: No such file or directory”?
A:fribidi 头文件在 usr/include 而非 include。
# 在 mpv 的 build() 中添加
export CFLAGS="${CFLAGS} -I${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/include"
# 或者在 Meson 交叉编译配置中
c_args = ['...', '-I${LYCIUM_ROOT}/usr/fribidi/${ARCH}/usr/include']
Q3:链接时报错 “unable to find library -lplacebo”?
A:libplacebo 库文件在 usr/lib 而非 lib。
# 在 Meson 交叉编译配置中
c_link_args = ['...','-L${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib']
Q4:lycium 直接跳过 mpv 构建?
A:构建缓存导致,需要清理。
# 清理 hpk_build.csv 中的 mpv 记录
cat usr/hpk_build.csv | grep -v mpv > /tmp/hpk_temp.csv
mv /tmp/hpk_temp.csv usr/hpk_build.csv
# 清理产物
rm -rf usr/mpv
rm -rf ../thirdparty/mpv/mpv-*/
# 重新构建
./build.sh mpv
Q5:glib 构建时报错 “subproject gvdb not found”?
A:glib 需要下载子模块 gvdb 和 proxy-libintl。
# 检查 prepare() 函数中的子模块下载逻辑
git clone https://gitee.com/lycium_pkg_mirror/gvdb.git $builddir/subprojects/gvdb
git clone --depth 1 --branch 0.4 https://gitee.com/lycium_pkg_mirror/proxy-libintl.git $builddir/subprojects/proxy-libintl
# 如果网络失败,可以手动下载后放到对应目录
Q6:fribidi 构建时报错 “c2man not found”?
A:fribidi 需要先编译 c2man 文档生成工具。
# 检查 prepare() 函数中的 c2man 编译逻辑
curl -f -L https://gitee.com/lycium_pkg_mirror/c2man/repository/archive/master.zip -o c2man.zip
unzip c2man.zip
cd c2man-master
./Configure -d -e
$MAKE
# 将 c2man 加入 PATH
export PATH=$PATH:$LYCIUM_ROOT/../thirdparty/fribidi/c2man-master
Q7:fontconfig 构建时报错 “freetype-config not found”?
A:fontconfig 需要显式设置 FREETYPE_CFLAGS 和 FREETYPE_LIBS。
# 在 fontconfig 的 build() 函数中
export FREETYPE_CFLAGS="-I${LYCIUM_ROOT}/usr/freetype2/$ARCH/include/freetype2"
export FREETYPE_LIBS="${LYCIUM_ROOT}/usr/freetype2/$ARCH/lib/libfreetype.a"
# 同时需要设置所有 freetype2 依赖的库路径
export FREETYPE_CFLAGS="$FREETYPE_CFLAGS ${LYCIUM_ROOT}/usr/bzip2/$ARCH/lib/libbz2.a ..."
export FREETYPE_LIBS="$FREETYPE_LIBS ${LYCIUM_ROOT}/usr/brotli/$ARCH/lib/libbrotlicommon.so ..."
Q8:harfbuzz 构建时报错 “Python detection failed”?
A:鸿蒙不支持 Python,需要屏蔽 Makefile.am 中的 Python 检测。
# 在 harfbuzz 的 prepare() 函数中
sed -i 's/^TESTS += \$(dist_check_SCRIPTS/#TESTS += \$(dist_check_SCRIPTS/g' $builddir/src/Makefile.am
Q9:libass 构建时报错 “harfbuzz not found”?
A:libass 不使用循环收集 pkgconfig,而是硬编码所有路径。
# 在 libass 的 build() 函数中,确保 PKG_CONFIG_PATH 包含 harfbuzz
export PKG_CONFIG_PATH="${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/lib/pkgconfig:${LYCIUM_ROOT}/usr/freetype2/$ARCH/lib/pkgconfig:..."
# 同时需要设置 HARFBUZZ_CFLAGS 和 HARFBUZZ_LIBS
export HARFBUZZ_CFLAGS="-I${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/include/harfbuzz"
export HARFBUZZ_LIBS="-L${LYCIUM_ROOT}/usr/harfbuzz/$ARCH/lib -lharfbuzz"
Q10:libplacebo 构建时报错 “vulkan not found”?
A:鸿蒙 PC 可能无完整 Vulkan 支持,需要禁用相关特性。
# 在 libplacebo 的 meson setup 中
meson setup ohos-build \
--cross-file ohos-cross.ini \
-D vulkan=disabled \
-D opengl=disabled \
-D d3d11=disabled \
-D glslang=disabled \
-D shaderc=disabled
Q11:mpv构建时报错 “meson配置失败,找不到 FFmpeg”?
A:pkg_config_path 未包含 FFmpeg 或路径错误。
# 在 mpv 的 ohos-cross.ini 中,确保包含 FFmpeg 路径
pkg_config_path = [
'${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig',
'${LYCIUM_ROOT}/usr/libplacebo/${ARCH}/usr/lib/pkgconfig',
...
]
# 验证 FFmpeg pkgconfig 文件是否存在
ls ${LYCIUM_ROOT}/usr/FFmpeg/${ARCH}/lib/pkgconfig/
# 应该看到 libavcodec.pc libavformat.pc libavutil.pc 等文件
Q12:构建产物中没有 .so 动态库,只有 .a 静态库?
A:检查构建配置是否启用了动态库构建。
# CMake 项目(如 freetype2)
-DBUILD_SHARED_LIBS=ON
# configure 项目(如 libpng)
--enable-shared --enable-static
# Meson 项目(如 glib)
-Ddefault_library=both
Q13:多个库都依赖 zlib,是否需要多次构建?
A:不需要。lycium 会自动检查 hpk_build.csv,已构建的库会跳过。
# 查看 zlib 构建状态
cat usr/hpk_build.csv | grep zlib
# 如果显示已构建,后续库会自动使用
# 如果需要强制重新构建 zlib
cat usr/hpk_build.csv | grep -v zlib > /tmp/hpk_temp.csv
mv /tmp/hpk_temp.csv usr/hpk_build.csv
rm -rf usr/zlib
./build.sh zlib
Q14:如何调试 pkg-config 路径是否正确?
A:在 build() 函数中添加调试输出。
# 在 build() 函数开头添加
echo "=== PKG_CONFIG_PATH ==="
echo $PKG_CONFIG_PATH
echo "=== pkg-config list ==="
pkg-config --list-all | grep -E 'libav|libplacebo|libass|fontconfig|harfbuzz|freetype2|fribidi'
echo "=== check specific package ==="
pkg-config --cflags libass
pkg-config --libs libass
Q15:构建顺序错误导致依赖找不到怎么办?
A:严格按照自底向上的顺序构建。
# 错误示例:先构建 libass 再构建 freetype2
./build.sh libass # ❌ 失败,freetype2 未构建
./build.sh freetype2
# 正确示例:先构建底层依赖
./build.sh zlib
./build.sh libpng
./build.sh freetype2
./build.sh fontconfig
./build.sh harfbuzz
./build.sh fribidi
./build.sh libass # ✅ 成功
八、技术总结
8.1 多层依赖适配核心原则
- 自底向上构建:严格按依赖层次顺序,从第 1 层到第 4 层
- 依赖声明准确:depends 数组声明所有直接依赖
- pkg-config 完整:收集所有传递依赖的 pkgconfig 路径
- 路径差异处理:fribidi、libplacebo 等库路径特殊,需显式配置
8.2 关键技术点
| 技术点 | 解决方案 | 示例 |
|---|---|---|
| 依赖声明 | depends=(“lib1” “lib2”) | libass 依赖 6 个库 |
| pkg-config 收集 | 遍历 depends 数组 | prepare() 函数 |
| 特殊路径处理 | 判断路径是否存在 | fribidi usr/lib/pkgconfig |
| 头文件路径 | CFLAGS 显式添加 | libplacebo usr/include |
| 链接路径 | c_link_args 配置 | libplacebo usr/lib |
| 构建缓存 | 清理 hpk_build.csv | grep -v 命令 |
8.3 通用适配能力
此套多层依赖树适配方案可直接迁移至:
- VLC媒体播放器 - 类似的音视频依赖链
- GStreamer多媒体框架 - 更复杂的多层依赖
- 任何具有多层依赖的 C/C++ 项目
更多推荐




所有评论(0)