3、交叉编译环境搭建:安装交叉编译工具链,配置环境变量,验证工具链
好,咱们继续。上一章我们把 Ubuntu 虚拟机跑起来了,现在该干正事了——搭建交叉编译环境。
说白了,交叉编译就是「在 PC 上编译,在 ARM 上运行」。你想想看,扫地机器人那个小芯片,跑个 Linux 都费劲,哪来的资源给你编译代码?所以我们在强大的 x86 主机上生成 ARM 能识别的二进制文件,再传过去跑。这就是交叉编译的核心思想。
3.1 什么是交叉编译工具链
工具链,英文叫 Toolchain,是一整套工具的集合。包括编译器(gcc)、汇编器(as)、链接器(ld)、调试器(gdb),还有 C 库(glibc 或 uclibc)等等。
我刚开始做嵌入式那会儿,对这些概念也是一头雾水。后来我师傅跟我说了一句话,我记到现在:「工具链就是你给目标板子配的翻译官」。你的代码是中文,ARM 处理器只懂 ARM 指令,工具链负责把中文翻译成 ARM 能听懂的方言。
对于扫地机器人这种资源受限的设备,我们通常用 arm-linux-gnueabihf- 前缀的工具链。这里的「hf」代表 hard-float,也就是硬件浮点运算。扫地机器人要算路径规划、避障算法,浮点运算少不了,所以选这个。
关键点:工具链的前缀决定了目标架构。比如:
arm-linux-gnueabihf-→ ARM 架构,硬件浮点aarch64-linux-gnu-→ 64 位 ARM 架构arm-none-eabi-→ 裸机程序,不带操作系统
我们做嵌入式 Linux,选第一个就够了。
3.2 获取交叉编译工具链
获取工具链有几种方式,我按推荐程度排个序:
| 方式 | 说明 | 推荐指数 |
|---|---|---|
| Linaro 官方预编译包 | ARM 公司官方维护,稳定可靠 | ⭐⭐⭐⭐⭐ |
| Buildroot 或 Yocto 生成 | 可定制,但耗时长 | ⭐⭐⭐⭐ |
| 芯片厂商 SDK 自带 | 如全志、瑞芯微提供的工具链 | ⭐⭐⭐ |
| 自己从源码编译 | crosstool-NG 等工具 | ⭐⭐(不推荐新手) |
我个人习惯用 Linaro 的预编译包。为什么呢?省事。你想想看,从源码编译一套完整的工具链,少则两三个小时,多则半天。而且中间任何一个依赖没装好,你就等着报错吧。我曾经在 crosstool-NG 上折腾了一整天,最后发现是 glibc 版本不匹配……嗯,从那以后我就学乖了。
下载命令如下:
# 下载 Linaro 7.5.0 版本的 ARM 工具链
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
# 解压到 /opt 目录
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 重命名一下,方便后续操作
sudo mv /opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf /opt/arm-linux-gnueabihf
小提示:为什么选 7.5.0 版本?因为太新的工具链可能对老内核支持不好,太旧的又缺少新特性。7.5.0 是个比较稳妥的选择,兼容性好,bug 也修得差不多了。我在好几个项目里都用这个版本,没出过问题。
3.3 配置环境变量
工具链下载好了,但系统还不知道它在哪。你得告诉系统:「嘿,我把工具链放在 /opt/arm-linux-gnueabihf/bin 下面了,你去找找。」
配置环境变量,说白了就是修改 PATH 变量。我建议你把它写到 ~/.bashrc 里,这样每次打开终端都能自动加载。
# 编辑 .bashrc 文件
vim ~/.bashrc
# 在文件末尾添加以下内容
export PATH=$PATH:/opt/arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
# 保存退出后,使配置生效
source ~/.bashrc
这里我多加了两个变量:CROSS_COMPILE 和 ARCH。为什么?因为后面编译内核、uboot 的时候,Makefile 会自动读取这两个变量。提前设好,后面省事。
注意:千万不要把 PATH 写错了。我曾经见过一个同事,把 export PATH=/opt/arm-linux-gnueabihf/bin 写成了 export PATH=/opt/arm-linux-gnueabihf/bin 但忘了加 $PATH: 前缀。结果呢?系统原来的命令全找不到了,ls、cd 全失效,终端直接废了。最后只能重启进恢复模式修……
3.4 验证工具链是否安装成功
环境配好了,怎么知道对不对?跑几个命令验证一下。
第一步:检查编译器版本
arm-linux-gnueabihf-gcc --version
如果看到类似下面的输出,说明工具链已经能用了:
arm-linux-gnueabihf-gcc (Linaro GCC 7.5-2019.12) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
第二步:编译一个测试程序
写一个最简单的 C 程序,用交叉编译器编译,看看能不能生成 ARM 格式的可执行文件。
# 创建一个测试文件
echo '#include <stdio.h>
int main() {
printf("Hello, 扫地机器人!\n");
return 0;
}' > test.c
# 用交叉编译器编译
arm-linux-gnueabihf-gcc test.c -o test_arm
# 查看生成的文件信息
file test_arm
如果输出是:
test_arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, not stripped
看到「ARM」字样了吗?这就对了。说明我们生成的是 ARM 架构的可执行文件,不是 x86 的。
第三步:反汇编验证指令集
如果你还不放心,可以用 objdump 反汇编看看:
arm-linux-gnueabihf-objdump -d test_arm | head -20
你会看到一堆 ARM 指令,比如 mov r0, #1、ldr r3, [pc, #...] 之类的。嗯,看到这些就稳了。
验证清单:
arm-linux-gnueabihf-gcc --version→ 显示版本号file test_arm→ 显示 ARM 架构arm-linux-gnueabihf-objdump -d test_arm→ 显示 ARM 指令
三条都过了,工具链就算搭好了。
3.5 避坑指南
做嵌入式这么多年,工具链这块我踩过的坑不少。分享几个常见的:
- 32 位 vs 64 位:Linaro 的工具链有 x86_64 和 i686 两个版本。现在的主机基本都是 64 位的,下载 x86_64 版本就行。如果你在 64 位系统上装了 32 位的工具链,运行时会报「No such file or directory」,但其实文件是存在的。这是因为缺少 32 位的运行时库。装一下
sudo apt install lib32z1 lib32ncurses5就能解决。 - 权限问题:工具链解压到 /opt 目录后,普通用户可能没有执行权限。记得
sudo chmod +x /opt/arm-linux-gnueabihf/bin/*给所有二进制文件加上执行权限。 - 多版本冲突:如果你同时装了多个工具链版本,注意 PATH 的顺序。系统会使用第一个找到的版本。我一般把最常用的版本放在 PATH 最前面。
好了,工具链搭好了,环境变量也配好了。下一章我们开始搞点真东西——编译一个能在扫地机器人上跑的最小 Linux 内核。到时候你就知道,今天搭的这个工具链有多重要了。