4、宿主机与目标机:宿主机环境要求、目标机架构(ARM、MIPS、RISC-V)、ABI与EABI
好,咱们进入正题。交叉编译这事儿,说白了就是「我在我的电脑上,编译出能在你电脑上跑的程序」。那我的电脑叫宿主机,你的电脑叫目标机。这两者之间,隔着的不只是网线,还有架构、指令集、ABI 这些硬骨头。
我个人习惯,在开始任何 SDK 发布工作之前,先把宿主机环境理清楚。不然编译到一半报错,你都不知道是工具链的问题,还是系统库的问题。
4.1 宿主机环境要求
宿主机,就是你面前这台开发机。我建议用 Linux,最好是 Ubuntu 20.04 LTS 或 22.04 LTS。为什么?因为绝大多数嵌入式工具链和 SDK 都是基于 Linux 生态构建的。你用 Windows 当然也能搞,但坑会多不少——我当年在 Windows 上折腾 ARM GCC,光是环境变量就配了一下午。
宿主机的基本要求,我列个清单:
- 操作系统:Ubuntu 20.04/22.04 LTS,或者 CentOS 7/8。Debian 也行,但别太新,库版本可能不兼容。
- 磁盘空间:至少 50GB 空闲。一个完整的交叉编译工具链加上 SDK,轻松吃掉 10-20GB。我见过有人只留了 20GB,编译到一半磁盘满了,那叫一个尴尬。
- 内存:8GB 起步,16GB 更稳。编译大型项目(比如 Linux 内核)时,内存不够会直接 OOM。
- CPU:多核优先。交叉编译可以并行,make -j$(nproc) 能省不少时间。
- 必备软件:build-essential、git、wget、curl、python3、texinfo、bison、flex、libncurses-dev。这些是基础,缺一个都可能让编译卡住。
4.2 目标机架构:ARM、MIPS、RISC-V
目标机就是你的嵌入式设备。它的 CPU 架构决定了你用什么样的交叉编译工具链。目前主流的三驾马车:ARM、MIPS、RISC-V。
4.2.1 ARM 架构
ARM 是嵌入式领域的霸主。从手机到路由器,从单片机到服务器,到处都有它。ARM 是个精简指令集(RISC)架构,特点是功耗低、性能不错。
ARM 有两个主要系列:
- Cortex-A:应用处理器,跑 Linux、Android。比如树莓派的 BCM2835 就是 Cortex-A 系列。
- Cortex-M:微控制器,跑裸机或 RTOS。比如 STM32 系列。
- Cortex-R:实时处理器,用于汽车、工业控制。
我在项目中遇到过最头疼的事:ARM 的版本太多了。ARMv7、ARMv8、ARMv9,指令集不完全兼容。你编译时选错了 -march,程序跑起来就崩。
4.2.2 MIPS 架构
MIPS 曾经很火,尤其是在路由器、机顶盒领域。龙芯早期也用过 MIPS 指令集。MIPS 也是 RISC 架构,设计哲学比 ARM 更简洁。
MIPS 的特点:
- 指令长度固定(32位),不像 ARM 有 Thumb 模式。
- 延迟槽(Delay Slot)——这个坑了我好几次。MIPS 在分支指令后面会执行一条指令,哪怕分支已经跳转了。写汇编时得小心。
- 现在 MIPS 生态在萎缩,但存量市场依然很大。
4.2.3 RISC-V 架构
RISC-V 是后起之秀,开源、简洁、可扩展。我最近几年越来越看好它。为什么?因为它没有历史包袱,指令集设计干净,而且从 MCU 到超级计算机都能用。
RISC-V 的模块化设计:
- RV32I/RV64I:基础整数指令集,必选。
- M:乘除法扩展。
- F/D:单精度/双精度浮点。
- C:压缩指令,减小代码体积。
嗯,这里要注意:RISC-V 的工具链还在快速演进中。我建议用官方的 riscv-gnu-toolchain,或者 SiFive 提供的预编译包。自己从源码编译?那得准备好咖啡,编译一次要几个小时。
4.3 ABI 与 EABI
ABI(Application Binary Interface),说白了就是「二进制层面的约定」。它规定了函数怎么传参、寄存器怎么用、栈怎么布局、数据怎么对齐。两个模块如果 ABI 不一致,链接在一起就会出问题。
EABI(Embedded ABI)是嵌入式领域的 ABI 标准。它和桌面版的 ABI 有什么区别?
| 特性 | 桌面 ABI | EABI |
|---|---|---|
| 浮点传参 | 用栈传递 | 用寄存器传递(更高效) |
| 结构体对齐 | 自然对齐 | 可配置,节省空间 |
| 位置无关代码 | 支持 | 可选,常用于裸机 |
| 系统调用接口 | 依赖操作系统 | 可无操作系统 |
举个例子。ARM 的 EABI 有两种常见变体:
- arm-eabi:老版本,浮点用软浮点(soft float),效率低。
- arm-eabihf:新版本,硬浮点(hard float),直接用 FPU 寄存器传参,快很多。
我踩过的一个坑:编译了一个库用的是 arm-eabihf,但主程序用的是 arm-eabi。链接时一堆「undefined reference」,查了半天才发现是 ABI 不匹配。所以,整个项目的所有模块必须用同一个 ABI。
4.4 知识体系结构图
下面这张图,帮你理清宿主机、目标机、ABI 之间的关系:
这张图想表达的核心:宿主机上跑的是 x86_64 的 Linux,工具链把源码编译成目标机架构的机器码。而目标机那边,架构和 ABI 共同决定了这个二进制能不能跑起来。
好了,这一节的内容就到这儿。记住:宿主机环境要稳,目标机架构要准,ABI 要一致。这三样搞定了,交叉编译就成功了一半。