4、源码编译工具链(crosstool-NG):安装、配置与实战
说实话,手动编译交叉工具链这件事,我当年刚入行时也头大过。那时候网上资料少,自己对着 Makefile 硬啃,一个配置不对就得重来一整天。后来遇到了 crosstool-NG,才算是找到了正路。这玩意儿说白了就是个自动化工具,帮你把 gcc、binutils、glibc 这些组件串起来,省去大量重复劳动。
我个人习惯是,只要不是特别冷门的架构,首选 crosstool-NG。它比手动编译快得多,也比 Linaro 那些预编译包更灵活。你想想看,同样是 ARM 平台,你是要硬浮点还是软浮点?要 uclibc 还是 glibc?这些 crosstool-NG 都能让你自己选。
4.1 安装 crosstool-NG
先说说安装。crosstool-NG 的安装其实不复杂,但有几个前置依赖容易踩坑。我曾经在 Ubuntu 18.04 上装过一次,缺了 flex 和 bison,编译到一半报错,气得我差点砸键盘。
依赖包清单如下:
sudo apt-get install -y autoconf automake libtool \
gcc g++ make flex bison texinfo \
libncurses-dev libssl-dev gperf
然后从官网拉源码:
git clone https://github.com/crosstool-ng/crosstool-ng.git
cd crosstool-ng
./bootstrap
./configure --prefix=/opt/ct-ng
make
sudo make install
这里我建议把 --prefix 设到一个独立目录,别跟系统路径混在一起。后面升级也好管理。
libncurses-dev 换成 ncurses-devel。包名不一样,但功能一样。
4.2 选择目标架构
安装完以后,运行 ct-ng menuconfig 就能进入配置界面。嗯,这里要注意,第一次进去可能会被密密麻麻的选项吓到。别慌,咱们一步步来。
首先选目标架构。crosstool-NG 支持几十种架构,从常见的 ARM、x86、MIPS,到冷门的 MicroBlaze、Nios II 都有。我个人最常用的是 ARM 和 RISC-V。
配置路径:
Target options --->
Target Architecture (arm) --->
(cortex-a9) Target CPU
(armv7-a) Target Architecture Variant
(armv7-a) Target Endianness: Little endian
这里我踩过一个坑:选 CPU 型号时,如果你不确定,就选最通用的。比如 ARM 平台,选 cortex-a9 基本能覆盖大部分场景。别一上来就选 cortex-a76,万一你的目标板子不支持,编译出来的程序跑都跑不起来。
| 架构 | 常用 CPU 型号 | 适用场景 |
|---|---|---|
| ARM | cortex-a9, cortex-a53 | 嵌入式 Linux、工业控制 |
| RISC-V | rv64gc | 开源处理器、AI 加速 |
| MIPS | mips32r2 | 路由器、网络设备 |
4.3 配置内核头文件与 C 库
架构选好了,接下来是内核头文件和 C 库。这两个东西决定了你的工具链能支持哪些系统调用和标准库函数。
配置路径:
Operating System --->
Target OS (linux) --->
Linux kernel version (5.10.100)
C-library --->
C library (glibc) --->
glibc version (2.35)
内核头文件版本怎么选?我有个经验法则:选你目标板子内核版本相近的,或者稍微低一点。比如你的板子跑的是 5.10 内核,那就选 5.10.x 的头文件。别选太新的,否则编译出来的程序可能调用了一些老内核没有的系统调用。
C 库的选择上,glibc 功能最全,但体积大。uclibc 和 musl 更轻量,适合资源受限的设备。我做过一个项目,板子只有 32MB Flash,用 glibc 编译出来的 busybox 都塞不下,换成 uclibc 才搞定。
4.4 编译与测试
配置完成后,保存退出,然后执行:
ct-ng build
这个过程比较漫长,我第一次编译 ARM 工具链时,用了将近两个小时。中间会下载源码包、打补丁、编译各个组件。你可以去泡杯咖啡,或者看看文档。
编译完成后,工具链默认安装在 ~/x-tools/ 目录下。结构大概是这样的:
~/x-tools/arm-cortex_a9-linux-gnueabihf/
├── arm-cortex_a9-linux-gnueabihf/
│ ├── bin/
│ ├── lib/
│ └── sysroot/
└── bin/
├── arm-cortex_a9-linux-gnueabihf-gcc
├── arm-cortex_a9-linux-gnueabihf-g++
└── arm-cortex_a9-linux-gnueabihf-ld
测试一下能不能用:
export PATH=$PATH:~/x-tools/arm-cortex_a9-linux-gnueabihf/bin
arm-cortex_a9-linux-gnueabihf-gcc --version
如果能看到版本信息,恭喜你,工具链已经可以用了。写个简单的 Hello World 试试:
#include <stdio.h>
int main() {
printf("Hello from crosstool-NG!\n");
return 0;
}
arm-cortex_a9-linux-gnueabihf-gcc -o hello hello.c
file hello
# 输出: ELF 32-bit LSB executable, ARM, version 1 (SYSV)
4.5 避坑指南
最后分享几个我踩过的坑:
- 网络问题: crosstool-NG 编译时会从网上拉源码包。如果你在公司内网,记得配好代理。我曾经因为没配代理,卡在下载 gcc 源码那一步整整半天。
- 磁盘空间: 编译过程中会生成大量临时文件,建议预留至少 10GB 空间。我有个同事用虚拟机编译,结果磁盘满了,编译到 99% 报错退出,那叫一个惨。
- 版本匹配: gcc、binutils、glibc 的版本不是随便选的。crosstool-NG 默认的版本组合是经过测试的,别手痒去改。我试过一次把 gcc 版本从 12 改成 13,结果编译 glibc 时各种报错。
好了,这一章的内容就到这里。crosstool-NG 用熟了以后,你会发现它比手动编译省心太多了。下一章咱们聊聊如何用这个工具链去编译一个完整的嵌入式 Linux 系统。