3. 嵌入式开发流程
好,咱们进入第三章。这一章要解决一个很实际的问题——怎么在你的电脑上,给ARM芯片编译程序。
你想想看,你的电脑是x86架构,ARM开发板是ARM架构。直接在电脑上编译出来的程序,ARM板子是跑不起来的。这时候就需要交叉编译工具链。说白了,就是一套能在x86上生成ARM可执行文件的编译器、链接器和库。
核心概念:交叉编译 = 在A架构上编译出能在B架构上运行的程序。我们这里就是x86编译,ARM运行。
3.1 什么是交叉编译工具链
工具链(Toolchain)不是单个工具,而是一整套工具的集合。我习惯把它拆成三部分来看:
- 编译器:最核心的是GCC,负责把C/C++代码编译成汇编。
- 汇编器与链接器:来自Binutils,负责汇编、链接、地址重定位。
- C库:通常是glibc或uClibc,提供标准C函数实现。
这三者必须版本匹配,否则编译出来的程序可能跑不起来。我在项目中遇到过好几次,因为glibc版本和编译器不匹配,程序在板子上段错误,查了半天才发现是工具链内部不兼容。
3.2 选择哪个ARM交叉编译器
市面上ARM交叉编译器有好几种,我列个表,你一看就明白:
| 编译器名称 | 适用场景 | 特点 |
|---|---|---|
| arm-linux-gnueabihf-gcc | ARM Cortex-A系列,带硬件浮点 | 最常用,性能好 |
| arm-linux-gnueabi-gcc | ARM Cortex-A系列,软件浮点 | 兼容老内核,性能稍差 |
| aarch64-linux-gnu-gcc | ARMv8 64位架构 | 用于树莓派3/4等64位板子 |
| arm-none-eabi-gcc | 裸机开发,无操作系统 | 用于STM32等MCU |
我个人建议,如果你做嵌入式Linux开发,直接选 arm-linux-gnueabihf-gcc。这个版本支持硬件浮点,性能比软浮点好不少。我早期做项目时用过软浮点版本,跑图像处理算法慢得让人抓狂,换成硬浮点后速度提升明显。
3.3 安装ARM交叉编译器
安装方式有两种:从包管理器安装,或者从Linaro官网下载预编译包。我推荐后者,版本更新、更可控。
方式一:apt安装(Ubuntu/Debian)
sudo apt update
sudo apt install gcc-arm-linux-gnueabihf
这种方式最简单,但版本可能比较老。我检查过,Ubuntu 20.04自带的版本是7.5.0,对于大多数项目够用,但如果你需要新特性,还是用方式二。
方式二:从Linaro下载(推荐)
# 下载ARM GCC 9.3.0版本
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 查看解压后的目录
ls /opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/
小提示:解压到 /opt/ 目录是Linux惯例,用于存放第三方软件。你也可以放到 /usr/local/ 或用户目录下,看个人习惯。
3.4 配置环境变量
安装完编译器后,系统还不知道它在哪里。你需要把编译器路径加到 PATH 环境变量里。
我习惯把配置写在 ~/.bashrc 里,这样每次打开终端都会自动加载。
# 编辑bash配置文件
vim ~/.bashrc
# 在文件末尾添加以下内容
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
# 保存退出后,使配置生效
source ~/.bashrc
为什么要用 source?因为修改 .bashrc 后,新开的终端才会自动加载。用 source 可以让当前终端立即生效,不用重启。
注意:如果你用的是Zsh(macOS默认),配置文件是 ~/.zshrc,不是 ~/.bashrc。别搞混了,我曾经帮同事排查过半小时,才发现他改错了文件。
3.5 验证工具链是否安装成功
环境变量配好了,怎么知道对不对?三步验证法,我一直在用:
- 检查编译器版本
arm-linux-gnueabihf-gcc --version
如果输出类似 arm-linux-gnueabihf-gcc (Linaro GCC 7.5.0-2019.12) 7.5.0,说明编译器找到了。
- 编译一个测试程序
# 写一个简单的C程序
echo '#include <stdio.h>
int main() {
printf("Hello, ARM!\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)。看到 ARM 字样就对了。
- 检查能否在开发板上运行
把 test_arm 拷贝到开发板上,执行:
./test_arm
如果输出 Hello, ARM!,恭喜你,工具链完全没问题。
关键点:用 file 命令检查可执行文件类型,是验证交叉编译是否成功的最直接方法。如果显示的是 x86-64,说明你用了本机编译器,不是交叉编译器。
3.6 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作一个快速参考:
3.7 常见问题与避坑指南
安装过程中,有几个坑我踩过,分享给你:
- PATH路径写错:检查一下路径末尾有没有
/bin。我见过有人只写到工具链根目录,没加/bin,结果编译器找不到。 - 32位库缺失:有些64位系统缺少32位兼容库,运行交叉编译器时会报
No such file or directory。安装lib32z1和lib32ncurses5就能解决。 - 权限问题:解压到
/opt/后,普通用户可能没有执行权限。用chmod +x给编译器加上执行权限。
曾经我踩过的坑:有一次我编译出来的程序在板子上运行就段错误,查了两天。最后发现是工具链的glibc版本和板子上内核的glibc版本不匹配。从那以后,我每次都会用 ldd 检查可执行文件依赖的库版本。
嗯,这一章的内容就这些。工具链装好了,环境变量配好了,验证也通过了,接下来就可以放心地写代码、编译、下载到板子上跑了。记住,工具链是整个BSP开发的基础,基础打牢了,后面才不容易出问题。