4、安装交叉编译工具链

好,咱们继续往下走。上一节我们把 NuttX 源码拉下来了,但光有源码还不行——你得有办法把代码变成能在目标板上跑的东西。这就引出了今天的主角:交叉编译工具链

什么是交叉编译?

先聊个基础概念。你平时在 Windows 上写个 C 程序,编译出来的 exe 只能在 Windows 上跑,这叫本地编译。但嵌入式开发不一样——你的开发电脑是 x86 架构,目标板可能是 ARM、RISC-V 或者 Xtensa。你想想看,x86 的机器怎么生成 ARM 的机器码?

答案就是交叉编译

说白了,交叉编译就是在一种架构的电脑上,编译出能在另一种架构上运行的程序。我刚开始接触嵌入式时,总觉得这玩意儿很玄乎。后来想通了——它就是个特殊的编译器,知道怎么生成目标 CPU 能识别的指令而已。

核心要点:交叉编译工具链 = 编译器 + 链接器 + 库文件 + 调试工具,专门为某个目标平台定制。

举个例子。我们这次用的是 ARM Cortex-M 系列芯片,所以需要 arm-none-eabi-gcc 这套工具链。其中:

  • arm:目标架构是 ARM
  • none:没有操作系统(bare-metal)
  • eabi:嵌入式应用二进制接口(Embedded ABI)

嗯,这里要注意:NuttX 虽然是 RTOS,但它编译时用的是 none-eabi 而不是 linux-gnu。为什么?因为 NuttX 的启动代码和链接脚本是自己管理的,不需要依赖 Linux 的 C 库。我在项目中遇到过有人误装了 arm-linux-gnueabihf,结果链接阶段各种报错,折腾了半天才发现是工具链选错了。

下载并安装 ARM GCC 工具链

好,概念讲完了,咱们动手。我个人习惯用 ARM 官方维护的 GCC ARM Embedded 工具链,稳定且更新及时。

方式一:从 ARM 官网下载(推荐)

访问 developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm,找到最新版本。我写这篇文章时,最新的是 10.3-2021.10 版本。你下载对应操作系统的压缩包就行。

  • Linux:gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
  • macOS:gcc-arm-none-eabi-10.3-2021.10-mac.tar.bz2
  • Windows:gcc-arm-none-eabi-10.3-2021.10-win32.zip

我的建议:别用 apt-get 或 brew 安装,那些源里的版本往往比较旧。我踩过坑——旧版本编译器对 Cortex-M33 的支持有 bug,导致浮点运算结果不对。从那以后,我只用官方原版。

方式二:命令行下载(Linux/macOS)

如果你喜欢用命令行,直接 wget 也行:

# 下载
wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2

# 解压到 /opt 目录
sudo tar -xjf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 -C /opt/

# 重命名(方便管理)
sudo mv /opt/gcc-arm-none-eabi-10.3-2021.10 /opt/gcc-arm-none-eabi

解压完后,你可以看看里面都有什么:

ls /opt/gcc-arm-none-eabi/bin/
# 你会看到 arm-none-eabi-gcc, arm-none-eabi-ld, arm-none-eabi-objcopy 等一堆工具

这些就是咱们的“武器库”了。

配置环境变量

工具链装好了,但系统还不知道它在哪。你需要把它的路径加到 PATH 环境变量里。

临时配置(当前终端有效)

export PATH="/opt/gcc-arm-none-eabi/bin:$PATH"

这条命令只对当前终端窗口有效。关掉终端再打开,又得重新设置。所以我们需要永久配置。

永久配置(推荐)

我个人习惯把配置写到 ~/.bashrc(如果你用 zsh,就写 ~/.zshrc):

echo 'export PATH="/opt/gcc-arm-none-eabi/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

注意:如果你用的是 macOS,默认 shell 是 zsh,记得改 ~/.zshrc。我曾经帮同事排查问题,发现他改了 bashrc 但用的是 zsh,折腾了半小时才找到原因。

验证工具链

配置完了,怎么知道好不好使?跑几个命令验证一下。

检查版本

arm-none-eabi-gcc --version

你应该能看到类似这样的输出:

arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release)
Copyright (C) 2020 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 文件测试一下:

// test.c
void main(void) {
    while(1);
}

然后编译:

arm-none-eabi-gcc -c -mcpu=cortex-m4 -mthumb test.c -o test.o

如果没有任何报错,并且生成了 test.o 文件,说明工具链工作正常。你可以用 file 命令看看它是不是 ARM 的机器码:

file test.o
# 输出: test.o: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped

看到 ARM, EABI5 这几个字,就稳了。

检查所有工具是否可用

我习惯再跑一条命令,确认关键工具都在:

arm-none-eabi-gcc --version && \
arm-none-eabi-ld --version && \
arm-none-eabi-objcopy --version && \
arm-none-eabi-gdb --version

如果四个命令都正常输出版本信息,那工具链就算彻底装好了。

本章知识体系

为了让你更直观地理解这一章的内容,我画了张图:

交叉编译工具链安装流程 什么是交叉编译 下载 ARM GCC 工具链 解压安装到 /opt 配置 PATH 环境变量 验证工具链(gcc --version) 避坑指南 • 别用 apt-get 安装 • 版本选 10.3+ • 注意 shell 类型 • 别装 linux-gnu 版 • 验证四个工具 • 检查 file 输出 • 确认 mcpu 参数

小技巧:如果你经常在多个项目间切换,可以考虑用 update-alternatives 管理多个版本的 GCC。不过对于 NuttX 开发,一套最新的工具链基本够用了。

好了,工具链装好了,环境变量配好了,也验证通过了。下一节我们会用这套工具链来编译 NuttX 内核,到时候你就知道它到底有多重要了。


公众号:蓝海资料掘金营,微信deep3321