3、交叉编译环境搭建(下):下载WebRTC源码、配置GN构建系统、首次编译验证
上一节我们把交叉编译工具链和sysroot都准备好了。说实话,那只是开胃菜。真正的硬仗,是从拉取WebRTC源码开始的。
WebRTC的源码管理方式有点特别——它不用传统的Makefile或CMake,而是用Google自家的depot_tools + GN + Ninja这套组合。我第一次接触时也觉得别扭,但用顺手后会发现,这套工具链在大型C++项目上确实高效。
3.1 安装depot_tools
depot_tools是Google为Chromium/WebRTC项目定制的源码管理工具集。它封装了git、gclient、gn等命令。
核心思路:depot_tools本身是一个git仓库,我们把它clone下来,然后加到PATH里。
# 在用户目录下创建工具目录
mkdir -p ~/tools
cd ~/tools
# 克隆depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
# 添加到环境变量(建议写入~/.bashrc)
export PATH="$HOME/tools/depot_tools:$PATH"
我个人习惯把depot_tools的路径放在~/.bashrc里,这样每次打开终端自动生效。你想想看,如果每次都要手动export,多容易忘。
注意:depot_tools依赖Python 2.7或Python 3。如果你的系统默认Python版本是3.8+,可能需要安装python-is-python3包。我曾经在Ubuntu 22.04上踩过这个坑,gclient死活报错,最后发现是Python版本不兼容。
3.2 下载WebRTC源码
WebRTC源码体积巨大——完整仓库大约15-20GB。所以下载前,建议确认磁盘空间充足。
下载流程分两步:先fetch拉取,再gclient sync同步依赖。
# 创建工作目录
mkdir ~/webrtc_build
cd ~/webrtc_build
# 拉取WebRTC源码(这一步会创建src目录)
fetch --nohooks webrtc_android
# 进入源码目录
cd src
# 同步所有依赖(耗时较长,建议挂代理)
gclient sync
这里有个细节:fetch webrtc_android会拉取Android平台的WebRTC。但我们目标是ARM Linux,为什么选Android?
其实webrtc_android包含了完整的ARM架构支持。我们后续通过GN参数指定arm-linux-gnueabihf工具链即可。如果你直接fetch webrtc,默认是x86桌面版,反而要额外配置ARM交叉编译。
我的经验:第一次gclient sync时,网络不稳定很容易中断。建议用gclient sync --no-history跳过git历史,能省不少流量和时间。另外,如果中途断了,重新执行gclient sync会断点续传,不用从头开始。
3.3 配置GN构建系统
GN(Generate Ninja)是Google开发的元构建系统。它不直接编译代码,而是生成Ninja构建文件。说白了,GN负责“规划”,Ninja负责“执行”。
配置GN的关键是编写一个args.gn文件。我们针对ARM Linux平台,需要指定:
- 目标CPU架构(arm)
- 交叉编译工具链路径
- sysroot路径
- 是否启用某些特性(如H264、VP9)
# 在src目录下创建ARM构建目录
mkdir -p out/arm_release
cd out/arm_release
# 生成GN配置
gn gen . --args='
target_os="linux"
target_cpu="arm"
arm_arch="armv7-a"
arm_float_abi="hard"
arm_use_neon=true
# 交叉编译工具链
arm_linux_gnueabihf_gcc="/opt/arm-gcc/bin/arm-linux-gnueabihf-gcc"
arm_linux_gnueabihf_gxx="/opt/arm-gcc/bin/arm-linux-gnueabihf-g++"
arm_linux_gnueabihf_ar="/opt/arm-gcc/bin/arm-linux-gnueabihf-ar"
arm_linux_gnueabihf_readelf="/opt/arm-gcc/bin/arm-linux-gnueabihf-readelf"
# sysroot路径
arm_linux_gnueabihf_sysroot="/opt/arm-sysroot"
# 优化选项
is_debug=false
is_official_build=true
rtc_use_h264=true
rtc_use_vp9=true
rtc_include_tests=false
rtc_build_examples=false
'
关键参数说明:
arm_float_abi="hard":必须与工具链的浮点ABI一致。如果你的工具链是hard-float,这里写soft会导致链接错误。arm_use_neon=true:ARMv7-A及以上都支持NEON,开启后视频编解码性能提升明显。is_official_build=true:启用官方优化,包括LTO(链接时优化)。
配置完成后,可以用gn args out/arm_release --list查看所有生效的参数。我建议你跑一下这个命令,看看有没有参数被覆盖或遗漏。
3.4 首次编译验证
配置没问题的话,就可以开始编译了。WebRTC使用Ninja作为构建工具,编译命令很简单:
# 回到src目录
cd ~/webrtc_build/src
# 编译WebRTC静态库和头文件
ninja -C out/arm_release webrtc
# 如果只想编译特定模块(比如音频处理)
ninja -C out/arm_release audio_processing
首次编译时间较长——我的i7-10700机器上大约需要40分钟。你可以用-j参数指定并行任务数,比如ninja -j8 -C out/arm_release webrtc。
常见错误:
- 找不到头文件:通常是sysroot路径不对。检查
arm_linux_gnueabihf_sysroot是否指向正确的目录。 - 链接错误:检查工具链版本是否匹配。我曾经用gcc 9.3编译,但sysroot是gcc 8.4的,结果链接libstdc++时符号找不到。
- NEON指令集错误:如果目标CPU不支持NEON,编译会报非法指令。可以在
arm_arch里指定具体型号,比如"armv7-a"。
编译成功后,输出文件在out/arm_release/obj/目录下。核心产物包括:
| 文件 | 说明 |
|---|---|
libwebrtc.a |
WebRTC静态库(约200MB) |
libwebrtc_full.a |
包含所有依赖的完整静态库 |
webrtc.h |
主头文件(自动生成) |
pc/ |
PeerConnection相关头文件 |
api/ |
API接口头文件 |
验证编译产物是否正确的办法:用file命令检查目标文件格式。
file out/arm_release/obj/libwebrtc.a
# 输出应包含:ELF 32-bit LSB relocatable, ARM, version 1 (ARM)
如果显示的是x86-64,说明GN配置没生效,你编译的是本地版本。嗯,这时候别慌,回去检查target_cpu和工具链路径。
3.5 本章知识结构
下面这张图梳理了交叉编译环境搭建的完整流程:
这张图把整个流程串起来了。你会发现,最耗时的其实是gclient sync这一步——它要下载数百个依赖库。我建议你找个网络好的时间段,一次性跑完。
3.6 避坑总结
最后,我把这些年踩过的坑汇总一下:
我的血泪史:
- 第一次编译时,我忘了设置
arm_linux_gnueabihf_sysroot,结果编译了3个小时,最后链接阶段报了一堆undefined reference。嗯,从那以后我每次都会先检查GN参数。 - 还有一次,我用的工具链是gcc 8.3,但sysroot是从Ubuntu 18.04拷的,里面libstdc++版本不匹配。最后我重新用crosstool-NG编译了工具链,才解决问题。
- 如果你遇到莫名其妙的编译错误,先试试
gn clean out/arm_release清理缓存。有时候GN的缓存会出问题。