3、交叉编译工具链配置:arm-linux-gnueabihf安装、sysroot制作、环境变量设置
交叉编译工具链,说白了就是一套能在你的 x86 笔记本上生成 ARM 可执行文件的工具集。你想想看,WebRTC 这种体量的项目,直接在 ARM 板子上编译?那得等到天荒地老。所以我们得在 PC 上搞定它。
我个人习惯把工具链配置分成三步走:装工具链 → 做 sysroot → 设环境变量。每一步都有坑,我踩过不少,下面一个一个说。
3.1 安装 arm-linux-gnueabihf 交叉编译器
Ubuntu 下最省事的办法就是 apt 直接装:
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
装完验证一下:
arm-linux-gnueabihf-gcc --version
能看到版本号就说明装好了。不过这里有个细节——apt 源里的版本可能比较老。我在项目中遇到过,Ubuntu 18.04 默认装的是 GCC 7.x,但 WebRTC 官方推荐用 clang 或者更新的 GCC。如果你遇到编译错误,可以考虑从 Linaro 或 ARM 官网下载预编译包。
3.2 制作 sysroot——这一步最容易被忽略
什么是 sysroot?简单说,就是目标 ARM 板子的根文件系统的一个副本。里面包含了板子上的 /lib、/usr/lib、/usr/include 等目录。交叉编译时,编译器会去 sysroot 里找头文件和库,而不是去 PC 本机的 /usr/include。
为什么要自己做?因为 WebRTC 依赖很多系统库(libpthread、libdl、librt 等),这些库的版本必须和板子上的一致。我曾经偷懒用了一个通用 sysroot,结果编译出来的 WebRTC 在板子上运行时,报 GLIBC_2.29 not found——板子上的 glibc 版本太旧了。
制作 sysroot 的步骤:
- 从板子上拷贝:用 scp 或 NFS 把板子的
/lib、/usr/lib、/usr/include拷出来。 - 整理目录结构:放到一个文件夹里,比如
$HOME/sysroot,保持lib/、usr/lib/、usr/include/的层级。 - 处理符号链接:板子上的库很多是相对链接,拷贝后可能断链。用
readlink -f检查,手动修复。
我一般用 rsync 来同步,保留软链接属性:
rsync -avz --copy-links root@<板子IP>:/lib/ $HOME/sysroot/lib/
rsync -avz --copy-links root@<板子IP>:/usr/lib/ $HOME/sysroot/usr/lib/
rsync -avz --copy-links root@<板子IP>:/usr/include/ $HOME/sysroot/usr/include/
tar 打包再传,速度更快。我曾经在树莓派上这么干过,省了不少时间。
3.3 环境变量设置——CC/CXX/AR 的学问
环境变量是告诉构建系统「用哪个编译器」的关键。WebRTC 用的是 GN + Ninja 构建系统,它通过 gn args 来配置工具链。但如果你要手动编译某个依赖库,就得设好这些变量。
核心变量就三个:
| 变量名 | 含义 | 示例值 |
|---|---|---|
CC |
C 编译器 | arm-linux-gnueabihf-gcc |
CXX |
C++ 编译器 | arm-linux-gnueabihf-g++ |
AR |
静态库打包器 | arm-linux-gnueabihf-ar |
我习惯写一个 setenv.sh 脚本,每次编译前 source 一下:
#!/bin/bash
export CC=arm-linux-gnueabihf-gcc
export CXX=arm-linux-gnueabihf-g++
export AR=arm-linux-gnueabihf-ar
export SYSROOT=$HOME/sysroot
export CFLAGS="--sysroot=$SYSROOT -march=armv7-a -mfpu=neon"
export CXXFLAGS="$CFLAGS"
export LDFLAGS="--sysroot=$SYSROOT"
这里有几个关键点:
--sysroot:告诉编译器去哪里找头文件和库。不设的话,编译器会去 PC 本机的/usr/include,那编译出来的东西肯定跑不了。-march=armv7-a:指定 ARM 架构。WebRTC 一般需要 ARMv7 以上。-mfpu=neon:启用 NEON 指令集。WebRTC 的编解码、降噪、回声消除都重度依赖 NEON,不开的话性能直接腰斩。
AR 变量,结果它用了 x86 的 ar 来打包静态库。编译没报错,但链接 WebRTC 时疯狂报 undefined reference。查了两天才发现是库文件格式不对。所以 AR 一定要设对。
3.4 验证工具链是否正常工作
写一个简单的测试程序:
// test.c
#include <stdio.h>
#include <arm_neon.h>
int main() {
printf("Hello from ARM WebRTC!\n");
// 简单 NEON 指令测试
int32x4_t a = vdupq_n_s32(1);
int32x4_t b = vdupq_n_s32(2);
int32x4_t c = vaddq_s32(a, b);
printf("NEON works: %d\n", vgetq_lane_s32(c, 0));
return 0;
}
编译:
arm-linux-gnueabihf-gcc --sysroot=$HOME/sysroot -march=armv7-a -mfpu=neon test.c -o test_arm
然后用 file 命令检查:
file test_arm
# 输出应该类似:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
如果看到 ARM 字样,说明编译成功了。把文件传到板子上运行一下,确认能正常输出。
3.5 本章知识结构图
下面这张图梳理了工具链配置的完整流程和关键节点: