3、依赖库准备(上):下载并编译zlib、libffi、glib的ARM版本
好,咱们继续往下走。上一章我们把交叉编译工具链和sysroot都准备好了,现在手里有家伙了,该干活了。
这一章,我们要搞定三个最基础的依赖库:zlib、libffi 和 glib。为什么先搞它们?因为GStreamer的底层离不开glib,而glib又依赖zlib和libffi。说白了,这就是个套娃结构,得从最里面那个娃开始拆。
我个人习惯,编译这种基础库,一定要先搞清楚它们的依赖关系。不然你编译到一半,突然报个错说找不到某个头文件,那才叫一个头大。
3.1 准备工作:环境变量与目录结构
在开始之前,先把环境变量确认一下。我假设你跟我一样,把交叉编译工具链装在了 /opt/arm-gcc 目录下,sysroot在 /opt/arm-sysroot。
每次打开新终端,我建议你先跑一遍这个:
export CC=arm-linux-gnueabihf-gcc
export CXX=arm-linux-gnueabihf-g++
export AR=arm-linux-gnueabihf-ar
export RANLIB=arm-linux-gnueabihf-ranlib
export SYSROOT=/opt/arm-sysroot
export PREFIX=$SYSROOT/usr
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=$SYSROOT
export CFLAGS="--sysroot=$SYSROOT -I$PREFIX/include"
export LDFLAGS="--sysroot=$SYSROOT -L$PREFIX/lib"
嗯,这里要注意:PREFIX 一定要指向sysroot下的 usr 目录。为什么?因为后面编译出来的 .pc 文件(pkg-config用的)里会记录这个路径,如果你随便放个地方,后面找库的时候会乱套。我在项目中就吃过这个亏,编译完glib后怎么都找不到,最后发现是路径写死了。
3.2 编译zlib:最基础的压缩库
zlib是个轻量级的压缩库,GStreamer里很多插件都用它来处理数据流。编译它相对简单,但有几个坑要注意。
先下载源码:
wget https://zlib.net/zlib-1.2.13.tar.gz
tar -xzf zlib-1.2.13.tar.gz
cd zlib-1.2.13
zlib的构建系统比较老,用的是自己写的configure脚本,不是autotools。所以配置方式有点不一样:
CHOST=arm-linux-gnueabihf \
./configure --prefix=$PREFIX --static
这里我加了 --static 参数。为什么?因为嵌入式平台上,静态链接能减少运行时依赖,避免目标板上缺库的尴尬。你想想看,你的程序在开发板上跑起来,结果报错说 libz.so.1 not found,那多闹心。
配置完直接编译安装:
make -j4
make install
验证一下:
arm-linux-gnueabihf-objdump -p $PREFIX/lib/libz.a | grep -i "architecture"
如果输出显示 ARM,那就对了。
--static 即可。但记得把生成的 libz.so.1 拷贝到目标板的 /lib 或 /usr/lib 下。
3.3 编译libffi:外部函数接口库
libffi这个库,说白了就是让程序能在运行时动态调用C函数。glib的GObject类型系统底层依赖它。我记得第一次接触libffi时,觉得这东西很神秘,后来发现其实就是个跳板。
下载源码:
wget https://github.com/libffi/libffi/releases/download/v3.4.4/libffi-3.4.4.tar.gz
tar -xzf libffi-3.4.4.tar.gz
cd libffi-3.4.4
libffi用的是autotools构建系统,配置命令如下:
./configure \
--host=arm-linux-gnueabihf \
--prefix=$PREFIX \
--with-sysroot=$SYSROOT \
--enable-static \
--disable-shared
这里有个关键参数 --with-sysroot,它告诉configure脚本去哪里找依赖的头文件和库。如果不加这个,它可能会去宿主机的 /usr/include 里找,那编译出来的东西就串味了。
编译安装:
make -j4
make install
undefined reference to `ffi_prep_closure' 的错误。这是因为某些架构需要开启 --enable-closures 选项。如果你遇到类似问题,可以加上 --enable-closures 重新配置。
安装完后,检查一下生成的 .pc 文件:
cat $PREFIX/lib/pkgconfig/libffi.pc
确保 prefix 和 exec_prefix 指向的是你的sysroot路径,而不是宿主机的路径。
3.4 编译glib:GStreamer的基石
glib是GStreamer最核心的依赖,没有之一。它提供了事件循环、线程管理、内存分配、类型系统等基础设施。GStreamer的pipeline、buffer、element这些概念,底层都是基于glib实现的。
下载源码:
wget https://download.gnome.org/sources/glib/2.78/glib-2.78.0.tar.xz
tar -xf glib-2.78.0.tar.xz
cd glib-2.78.0
glib从2.60版本开始,构建系统从autotools切换到了meson。所以配置方式变了:
meson setup build \
--cross-file /path/to/arm-cross-file.txt \
--prefix $PREFIX \
--libdir lib \
--default-library static \
-Dtests=false \
-Dselinux=disabled \
-Dlibmount=disabled
这里需要准备一个交叉编译配置文件 arm-cross-file.txt,内容如下:
[binaries]
c = 'arm-linux-gnueabihf-gcc'
cpp = 'arm-linux-gnueabihf-g++'
ar = 'arm-linux-gnueabihf-ar'
strip = 'arm-linux-gnueabihf-strip'
pkgconfig = 'arm-linux-gnueabihf-pkg-config'
[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'armv7l'
endian = 'little'
[properties]
sys_root = '/opt/arm-sysroot'
pkg_config_libdir = '/opt/arm-sysroot/usr/lib/pkgconfig'
这个文件告诉meson:你的目标机器是ARM架构,编译器用哪个,sysroot在哪。我个人习惯把这个文件放在源码目录下,方便以后复用。
配置完成后,编译安装:
meson compile -C build
meson install -C build
libffi 或 zlib。这是因为meson没有自动找到我们之前编译好的库。解决办法是设置 PKG_CONFIG_PATH 环境变量,指向我们安装库的 pkgconfig 目录。如果你按照我前面的步骤做了,这一步应该不会出问题。
验证glib是否编译成功:
arm-linux-gnueabihf-gcc --sysroot=$SYSROOT -o test_glib test_glib.c \
$(pkg-config --cflags --libs glib-2.0)
其中 test_glib.c 可以写一个简单的glib程序:
#include <glib.h>
int main() {
g_print("Hello from GLib %d.%d.%d\n",
GLIB_MAJOR_VERSION,
GLIB_MINOR_VERSION,
GLIB_MICRO_VERSION);
return 0;
}
如果能编译通过,说明glib已经成功安装到sysroot里了。
3.5 常见问题与避坑指南
编译这三个库时,我遇到过不少坑,这里列几个典型的:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| configure: error: C compiler cannot create executables | 交叉编译器路径不对或sysroot配置错误 | 检查 CC 和 CFLAGS 环境变量,确保 --sysroot 指向正确的目录 |
| undefined reference to `ffi_type_uint32' | libffi未正确安装或链接顺序不对 | 重新编译libffi,确保 make install 成功,并在链接时加上 -lffi |
| glib: ERROR: Problem encountered: glib requires libffi >= 3.0.0 | pkg-config找不到libffi的.pc文件 | 设置 PKG_CONFIG_PATH 指向libffi的pkgconfig目录 |
| meson: ERROR: Unknown compiler(s): [['cc'], ['gcc']] | meson没有找到交叉编译器 | 检查 arm-cross-file.txt 中的编译器路径是否正确 |
嗯,这里我要特别说一下。我曾经在编译glib时,卡在 libffi 的依赖上整整半天。后来发现是 PKG_CONFIG_PATH 没设置对,meson一直去宿主机的目录找libffi,结果找到的是x86版本的,链接时当然报错。所以,环境变量一定要检查三遍。
3.6 本章小结
这一章我们完成了三个基础库的交叉编译:
- zlib:最基础的压缩库,编译最简单,注意用
CHOST指定目标架构 - libffi:外部函数接口,glib的底层依赖,注意
--with-sysroot参数 - glib:GStreamer的基石,用meson构建,需要准备交叉编译配置文件
这三个库都安装到了sysroot的 /usr 目录下。下一章,我们会继续编译GStreamer的其他依赖库,比如 libxml2、orc 等。到时候你会发现,有了这一章的基础,后面的编译会顺畅很多。
好,今天就到这里。如果你在编译过程中遇到任何问题,欢迎随时交流。记住,交叉编译就是个细心活,耐心点,总能搞定。