1. 项目概述
最近在T113平台上进行libmpv的交叉编译工作,遇到了不少坑,也积累了一些经验。libmpv作为一款轻量级、高性能的多媒体播放库,在嵌入式设备上有着广泛的应用场景。本文将详细记录整个编译过程,包括环境配置、依赖库编译顺序、关键问题解决等,希望能为有类似需求的开发者提供参考。
2. 环境准备
2.1 目录结构规划
合理的目录结构是项目成功的基础。我采用了以下目录布局:
code复制~/t113-mpv/
├── build/ # 各库的编译目录
├── install/ # 最终安装目录
├── logs/ # 编译日志
├── pkgconfig-merged/ # 合并后的pkgconfig目录
├── src/ # 源码下载目录
├── env.sh # 环境变量配置
├── pkg-config-t113 # pkg-config包装脚本
└── t113-arm-musl.cross # Meson交叉编译配置文件
这种结构清晰地区分了源码、构建和安装目录,便于管理和维护。
2.2 交叉编译环境配置
env.sh文件是整个编译过程的核心,它定义了所有必要的环境变量:
bash复制export TINA_SDK=~/t113/Tina-Linux
export SYSROOT=$TINA_SDK/out/t113-mq_r/staging_dir/target
export PREFIX=~/t113-mpv/install
export TOOLCHAIN=$TINA_SDK/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain
export CROSS_BIN=$TOOLCHAIN/bin
export TARGET=arm-openwrt-linux
export PATH=$CROSS_BIN:$HOME/.local/bin:$PATH
export CC=$CROSS_BIN/${TARGET}-gcc
export CXX=$CROSS_BIN/${TARGET}-g++
export AR=$CROSS_BIN/${TARGET}-ar
export AS=$CROSS_BIN/${TARGET}-as
export LD=$CROSS_BIN/${TARGET}-ld
export RANLIB=$CROSS_BIN/${TARGET}-ranlib
export STRIP=$CROSS_BIN/${TARGET}-strip
export NM=$CROSS_BIN/${TARGET}-nm
export CFLAGS="--sysroot=$SYSROOT -Os -fPIC"
export CXXFLAGS="--sysroot=$SYSROOT -Os -fPIC"
export CPPFLAGS="--sysroot=$SYSROOT"
export LDFLAGS="--sysroot=$SYSROOT -L$PREFIX/lib -Wl,-rpath-link,$PREFIX/lib -Wl,-rpath-link,$SYSROOT/usr/lib -Wl,-rpath-link,$SYSROOT/lib"
关键点说明:
SYSROOT指向目标系统的根目录,包含目标系统的头文件和库PREFIX指定自定义库的安装位置CFLAGS和LDFLAGS中的-fPIC和-Wl,-rpath-link选项对嵌入式开发尤为重要
2.3 Meson交叉编译配置文件
对于使用Meson构建系统的项目,需要专门的交叉编译配置文件t113-arm-musl.cross:
ini复制[binaries]
c = '~/t113/Tina-Linux/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-gcc'
cpp = '~/t113/Tina-Linux/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-g++'
ar = '~/t113/Tina-Linux/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-ar'
strip = '~/t113/Tina-Linux/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-strip'
pkgconfig = '~/t113-mpv/pkg-config-t113'
[properties]
needs_exe_wrapper = true
c_args = ['--sysroot=~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target', '-Os', '-fPIC']
cpp_args = ['--sysroot=~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target', '-Os', '-fPIC']
c_link_args = ['--sysroot=~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target', '-L~/t113-mpv/install/lib', '-Wl,-rpath-link,~/t113-mpv/install/lib', '-Wl,-rpath-link,~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target/usr/lib', '-Wl,-rpath-link,~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target/lib']
cpp_link_args = ['--sysroot=~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target', '-L~/t113-mpv/install/lib', '-Wl,-rpath-link,~/t113-mpv/install/lib', '-Wl,-rpath-link,~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target/usr/lib', '-Wl,-rpath-link,~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target/lib']
[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'
特别注意pkgconfig项的配置,这是后续解决依赖问题的关键。
3. 基础库编译
3.1 编译顺序规划
libmpv依赖众多基础库,编译顺序至关重要。经过多次尝试,确定了以下顺序:
- zlib
- freetype(第一轮,不链接harfbuzz)
- fribidi
- harfbuzz
- freetype(第二轮,链接harfbuzz)
- libass
这种分阶段编译freetype的方法避免了循环依赖问题。
3.2 各库编译详解
3.2.1 zlib编译
bash复制cd $SRC_DIR
wget https://zlib.net/fossils/zlib-1.3.1.tar.gz
tar xf zlib-1.3.1.tar.gz
cd zlib-1.3.1
CHOST=$TARGET ./configure --prefix=$PREFIX
make -j$(nproc)
make install
验证编译结果:
bash复制file $PREFIX/lib/libz.so*
应输出类似:
code复制libz.so.1.3.1: ELF 32-bit LSB shared object, ARM, EABI5
3.2.2 freetype第一轮编译
bash复制cd $SRC_DIR
wget https://download.savannah.gnu.org/releases/freetype/freetype-2.13.3.tar.xz
tar xf freetype-2.13.3.tar.xz
rm -rf $BUILD_DIR/freetype
mkdir -p $BUILD_DIR/freetype
cd $BUILD_DIR/freetype
$SRC_DIR/freetype-2.13.3/configure \
--host=arm-openwrt-linux \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--with-zlib=yes \
--with-png=no \
--with-harfbuzz=no \
--with-bzip2=no \
--with-brotli=no \
CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS"
make -j$(nproc)
make install
3.2.3 fribidi编译
bash复制cd $SRC_DIR
wget https://github.com/fribidi/fribidi/releases/download/v1.0.16/fribidi-1.0.16.tar.xz
tar xf fribidi-1.0.16.tar.xz
rm -rf $BUILD_DIR/fribidi
mkdir -p $BUILD_DIR/fribidi
cd $BUILD_DIR/fribidi
$SRC_DIR/fribidi-1.0.16/configure \
--host=arm-openwrt-linux \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-docs \
CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS"
make -j$(nproc)
make install
3.2.4 harfbuzz编译
关键步骤:需要临时取消PKG_CONFIG_SYSROOT_DIR设置
bash复制unset PKG_CONFIG_SYSROOT_DIR
export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
cd $SRC_DIR
wget https://github.com/harfbuzz/harfbuzz/releases/download/10.2.0/harfbuzz-10.2.0.tar.xz
tar xf harfbuzz-10.2.0.tar.xz
rm -rf $BUILD_DIR/harfbuzz
mkdir -p $BUILD_DIR/harfbuzz
cd $BUILD_DIR/harfbuzz
meson setup . $SRC_DIR/harfbuzz-10.2.0 \
--cross-file ~/t113-mpv/t113-arm-musl.cross \
--prefix=$PREFIX \
--libdir=lib \
--default-library=shared \
-Dglib=disabled \
-Dgobject=disabled \
-Dicu=disabled \
-Dtests=disabled \
-Ddocs=disabled \
-Dfreetype=enabled \
-Dbenchmark=disabled \
-Dintrospection=disabled
meson compile -C .
meson install -C .
3.2.5 freetype第二轮编译
bash复制unset PKG_CONFIG_SYSROOT_DIR
export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
rm -rf $BUILD_DIR/freetype
mkdir -p $BUILD_DIR/freetype
cd $BUILD_DIR/freetype
$SRC_DIR/freetype-2.13.3/configure \
--host=arm-openwrt-linux \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--with-zlib=yes \
--with-png=no \
--with-harfbuzz=yes \
--with-bzip2=no \
--with-brotli=no \
CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS"
make -j$(nproc)
make install
3.2.6 libass编译
bash复制unset PKG_CONFIG_SYSROOT_DIR
export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
cd $SRC_DIR
wget https://github.com/libass/libass/releases/download/0.17.3/libass-0.17.3.tar.xz
tar xf libass-0.17.3.tar.xz
rm -rf $BUILD_DIR/libass
mkdir -p $BUILD_DIR/libass
cd $BUILD_DIR/libass
$SRC_DIR/libass-0.17.3/configure \
--host=arm-openwrt-linux \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-require-system-font-provider \
CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" \
PKG_CONFIG=/usr/bin/pkg-config
make -j$(nproc)
make install
验证:
bash复制pkg-config --modversion libass
pkg-config --cflags libass
pkg-config --libs libass
4. FFmpeg编译
4.1 pkg-config合并方案
mpv和FFmpeg需要同时看到两类.pc文件:
- install/lib/pkgconfig下的自编产物
- SYSROOT/usr/lib/pkgconfig下的alsa.pc
解决方案是创建合并目录:
bash复制rm -f ~/t113-mpv/pkgconfig-merged/*
cp -a ~/t113-mpv/install/lib/pkgconfig/*.pc \
~/t113-mpv/pkgconfig-merged/
cp -a ~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target/usr/lib/pkgconfig/alsa.pc \
~/t113-mpv/pkgconfig-merged/
sed -i 's#^prefix=.*#prefix=~/t113/Tina-Linux/out/t113-mq_r/staging_dir/target/usr#' \
~/t113-mpv/pkgconfig-merged/alsa.pc
sed -i 's#^exec_prefix=.*#exec_prefix=${prefix}#' \
~/t113-mpv/pkgconfig-merged/alsa.pc
sed -i 's#^libdir=.*#libdir=${exec_prefix}/lib#' \
~/t113-mpv/pkgconfig-merged/alsa.pc
sed -i 's#^includedir=.*#includedir=${prefix}/include#' \
~/t113-mpv/pkgconfig-merged/alsa.pc
创建pkg-config包装脚本:
bash复制cat > ~/t113-mpv/pkg-config-t113 <<'EOF'
#!/bin/sh
MERGED=~/t113-mpv/pkgconfig-merged
export PKG_CONFIG_DIR=
unset PKG_CONFIG_SYSROOT_DIR
export PKG_CONFIG_LIBDIR="$MERGED"
export PKG_CONFIG_PATH="$MERGED"
exec /usr/bin/pkg-config "$@"
EOF
chmod +x ~/t113-mpv/pkg-config-t113
4.2 FFmpeg编译命令
bash复制export PKG_CONFIG=~/t113-mpv/pkg-config-t113
export EXTRA_CFLAGS="$CFLAGS -D_GNU_SOURCE"
export EXTRA_CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE"
cd $SRC_DIR
wget https://ffmpeg.org/releases/ffmpeg-4.4.4.tar.xz
tar xf ffmpeg-4.4.4.tar.xz
rm -rf $BUILD_DIR/ffmpeg
mkdir -p $BUILD_DIR/ffmpeg
cd $BUILD_DIR/ffmpeg
$SRC_DIR/ffmpeg-4.4.4/configure \
--prefix=$PREFIX \
--cross-prefix=arm-openwrt-linux- \
--arch=arm \
--target-os=linux \
--enable-cross-compile \
--sysroot=$SYSROOT \
--pkg-config=$PKG_CONFIG \
--pkg-config-flags="--static" \
--enable-pic \
--enable-shared \
--disable-static \
--disable-debug \
--disable-doc \
--enable-gpl \
--enable-version3 \
--enable-avcodec \
--enable-avformat \
--enable-avutil \
--enable-swresample \
--enable-swscale \
--enable-postproc \
--enable-avfilter \
--enable-avdevice \
--disable-programs \
--enable-ffmpeg \
--enable-ffprobe \
--disable-ffplay \
--enable-libass \
--enable-zlib \
--enable-alsa \
--extra-cflags="$EXTRA_CFLAGS" \
--extra-cxxflags="$EXTRA_CXXFLAGS" \
--extra-ldflags="$LDFLAGS" \
--extra-libs="-lpthread -lm -ldl -lrt -lass -lfribidi -lharfbuzz -lfreetype -lz -lasound"
make -j$(nproc)
make install
验证:
bash复制grep -E 'CONFIG_AVDEVICE|CONFIG_LIBASS|CONFIG_ALSA' config.h
file $PREFIX/lib/libavdevice.so*
file $PREFIX/bin/ffprobe
5. libmpv编译
5.1 源码准备
bash复制export PKG_CONFIG=~/t113-mpv/pkg-config-t113
cd $SRC_DIR
wget https://github.com/mpv-player/mpv/archive/refs/tags/v0.36.0.tar.gz -O mpv-0.36.0.tar.gz
tar xf mpv-0.36.0.tar.gz
5.2 Meson配置
bash复制rm -rf $BUILD_DIR/mpv
mkdir -p $BUILD_DIR/mpv
cd $BUILD_DIR/mpv
meson setup . $SRC_DIR/mpv-0.36.0 \
--cross-file ~/t113-mpv/t113-arm-musl.cross \
--prefix=$PREFIX \
--libdir=lib \
--default-library=shared \
-Dcplayer=false \
-Dlibmpv=true \
-Dalsa=enabled \
-Dpulse=disabled \
-Dpipewire=disabled \
-Djack=disabled \
-Dopenal=disabled \
-Doss-audio=disabled \
-Dsndio=disabled \
-Dlua=disabled \
-Djavascript=disabled \
-Duchardet=disabled \
-Drubberband=disabled \
-Ddvdnav=disabled \
-Dlibarchive=disabled \
-Dlibbluray=disabled \
-Dvapoursynth=disabled \
-Dzimg=disabled \
-Djpeg=disabled \
-Dlcms2=disabled \
-Ddrm=disabled \
-Degl=disabled \
-Dgl=disabled \
-Dvulkan=disabled \
-Dwayland=disabled \
-Dx11=disabled \
-Dxv=disabled \
-Dsdl2-video=disabled \
-Dsdl2-audio=disabled \
-Dmanpage-build=disabled \
-Dhtml-build=disabled \
-Dpdf-build=disabled \
-Dtests=false \
-Dbuild-date=false
5.3 编译安装
bash复制meson compile -C .
meson install -C .
验证:
bash复制ls $PREFIX/lib/libmpv.so*
file $PREFIX/lib/libmpv.so.2.1.0
ls $PREFIX/include/mpv
ls $PREFIX/lib/pkgconfig/mpv.pc
6. 常见问题与解决方案
6.1 ft2build.h not found
问题现象:编译harfbuzz时出现freetype头文件找不到的错误
原因分析:PKG_CONFIG_SYSROOT_DIR污染了PREFIX下的freetype2.pc文件
解决方案:
bash复制unset PKG_CONFIG_SYSROOT_DIR
export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig
6.2 Dependency "libavcodec" not found
问题现象:mpv配置阶段报告找不到FFmpeg库
原因分析:Meson实际使用的是cross file里的pkgconfig条目,不是shell环境里的PKG_CONFIG
解决方案:修改t113-arm-musl.cross文件:
ini复制pkgconfig = '~/t113-mpv/pkg-config-t113'
6.3 ERROR: alsa requested but not found
问题现象:FFmpeg配置阶段ALSA检测失败
原因分析:FFmpeg的ALSA探测源码在Tina sysroot下会因为u_int8_t等类型定义不可见而编译失败
解决方案:给FFmpeg增加-D_GNU_SOURCE定义:
bash复制export EXTRA_CFLAGS="$CFLAGS -D_GNU_SOURCE"
export EXTRA_CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE"
6.4 链接问题
问题现象:链接时报告各种符号未定义
解决方案:需要显式指定所有依赖库:
bash复制-lpthread -lm -ldl -lrt -lass -lfribidi -lharfbuzz -lfreetype -lz -lasound
并确保-Wl,-rpath-link正确设置。
7. 总结与建议
经过这次交叉编译实践,我总结了以下几点经验:
- 环境隔离:严格区分host和target环境,特别是pkg-config的设置
- 编译顺序:对于有复杂依赖关系的库,分阶段编译是必要的
- 问题排查:遇到问题时,首先检查config.log和编译日志
- 验证步骤:每个库编译后都应进行基本验证,避免问题累积
在实际应用中,还需要注意:
- 目标设备的存储空间限制
- 运行时库的部署路径
- 性能优化选项的调整
希望这篇详细的记录能帮助其他开发者顺利完成类似项目的交叉编译工作。如果在实践中遇到新问题,建议参考各库的官方文档和社区讨论。
