4、获取交叉编译工具链:三种方式对比
拿到交叉编译工具链,是搭建环境的第一步。说白了,你得有一套能在 x86 电脑上生成 ARM 代码的编译器。怎么搞到手?我这些年用过三种主流方式:从 Linaro 官网下载预编译包、用 apt-get 直接安装、自己从源码编译。每种都有各自的脾气,今天咱们就掰开揉碎了聊聊。
核心结论先放这:新手推荐 apt-get,项目定型后用 Linaro 预编译包,只有特殊定制需求才走源码编译。别一上来就想着自己编译,我见过太多人在这上面浪费一整天。
4.1 方式一:从 Linaro 官网下载预编译包
Linaro 是 ARM 生态里最活跃的组织之一。他们维护的 GCC 工具链,基本覆盖了主流 ARM 架构。我个人习惯用这个方式,因为版本明确,出了问题也好查。
操作步骤:
- 打开 Linaro 官方 Releases 页面(
releases.linaro.org) - 找到
components/toolchain/gcc-linaro-7.5.0-2019.12这类目录 - 根据你的宿主机架构选文件:x86_64 就选
gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz - 解压到
/opt/toolchains/目录 - 配置环境变量
PATH
# 下载(以 ARM 32位 hard-float 为例)
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/toolchains/
# 配置环境变量(写入 ~/.bashrc)
export PATH=/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
# 验证
arm-linux-gnueabihf-gcc --version
我的小技巧:解压后先跑一下 arm-linux-gnueabihf-gcc -v,看看有没有报缺少动态库的错误。曾经我在 Ubuntu 18.04 上遇到过缺少 lib32stdc++6 的情况,装一下 sudo apt install lib32stdc++6 就解决了。
4.2 方式二:使用 apt-get 安装
这是最省事的方式。Ubuntu/Debian 的官方源里就带了交叉编译工具链。你想想看,一行命令搞定,多方便。
# 安装 ARM 32位工具链
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf
# 安装 ARM 64位工具链
sudo apt-get install gcc-aarch64-linux-gnu
# 验证
arm-linux-gnueabihf-gcc --version
aarch64-linux-gnu-gcc --version
优点很明显:
- 依赖自动解决,不会缺库
- 和系统集成好,头文件路径不用手动配
- 卸载也干净,
apt remove就行
缺点也得说:
- 版本通常比较旧。Ubuntu 20.04 自带的 GCC 还是 9.x,而 Linaro 已经出到 13.x 了
- 不支持选择特定补丁版本。如果你需要某个修复了特定 bug 的版本,apt-get 给不了
- 不同 Ubuntu 版本的工具链行为可能有细微差异
我曾经踩过的坑:有次项目用 apt-get 装的 GCC 9.3 编译出来的内核,在某个老款 i.MX6 上跑起来网络驱动死活不通。折腾了两天,换成 Linaro 的 GCC 7.5 就正常了。所以,生产环境建议和芯片厂商推荐的 GCC 版本保持一致。
4.3 方式三:从源码编译
这是最硬核的方式,也是我早期经常干的事。为什么?因为要定制。比如你想开启 Graphite 循环优化,或者想用 LTO(链接时优化),预编译包不一定支持。
编译一个完整的交叉工具链,通常需要这几个组件:
- binutils:汇编器、链接器、目标文件工具
- GCC:编译器本身
- glibc:C 运行库(或者用 uclibc、musl)
- Linux Kernel Headers:系统调用接口头文件
- GMP、MPFR、MPC:GCC 依赖的数学库
编译顺序有讲究:先编 binutils → 安装内核头文件 → 编 GCC 第一阶段(仅支持编译 glibc)→ 编 glibc → 编 GCC 第二阶段(完整版)。
# 以 crosstool-NG 为例(强烈推荐用这个工具,别手搓)
# 安装 crosstool-NG
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
./bootstrap
./configure --enable-local
make
make install
# 配置目标架构
ct-ng arm-cortex_a9-linux-gnueabihf
# 进入菜单配置(可以调整 GCC 版本、glibc 版本、优化选项等)
ct-ng menuconfig
# 开始编译(耗时约 30-60 分钟,取决于机器性能)
ct-ng build
什么时候必须走源码编译?我总结三种场景:
- 需要启用特定 GCC 优化选项(如
--with-float=hard配合特定 FPU) - 目标板子的 glibc 版本和宿主机不兼容
- 需要把工具链放到特定路径,或者打包给团队统一使用
4.4 三种方式对比总结
| 对比维度 | Linaro 预编译 | apt-get 安装 | 源码编译 |
|---|---|---|---|
| 上手难度 | 低 | 极低 | 高 |
| 版本灵活性 | 高(可选多个版本) | 低(仅系统源版本) | 极高(可定制任何版本) |
| 依赖管理 | 手动解决 | 自动解决 | 手动解决 |
| 编译时间 | 0(直接下载) | 0(直接安装) | 30-90 分钟 |
| 定制能力 | 无 | 无 | 完全定制 |
| 推荐场景 | 项目开发、生产环境 | 学习、快速验证 | 特殊优化、芯片适配 |
4.5 知识体系:工具链获取方式决策图
下面这张图帮你快速决策:你的项目该用哪种方式?
4.6 我的最终建议
如果你问我个人怎么选?我分场景说:
- 自己学习、做实验:apt-get 一把梭。省下的时间多写几行代码不香吗?
- 公司项目、产品开发:去 Linaro 下载和芯片厂商推荐版本一致的预编译包。我习惯在
/opt/toolchains/下按gcc-版本-架构命名,方便多版本切换。 - 遇到奇怪的问题:比如浮点性能不对、某个 intrinsic 函数没生效,这时候才考虑源码编译。用 crosstool-NG,别手搓,别问我怎么知道的。
一个小技巧:不管你用哪种方式装好了工具链,第一时间编译一个 hello world 并放到目标板上跑一下。我每次搭建新环境都这么做——确认编译器能工作、链接器能找到库、运行时不出错。这一步能筛掉 80% 的环境问题。