常见的交叉编译工具链
常见的交叉编译工具链
我们日常开发使用最多的就是gcc编译器,gcc来源于GNU C Compiler,起初支持一个C语言的编译器,而后发展成了为了GNU Compiler Collection,工具链中包括了编译器、链接器、binutils、glibc、头文件等。同时也支持了多种语言(C、C++、Java、Go等)与多种硬件平台(X86、ARM、MIPS、RISV-V等)。
而arm-none-eabi-gcc就是gcc的针对ARM平台的一个分支,全称是GNU C Compiler for ARM Architecture。
免费版目前有三大主流工具商:GNU、Codesourcery(已被西门子收购)、Linora。接下来我们列举一下你可能在开发中见到过的ARM交叉编译工具链。
arm-none-linux-gnueabi-gcc
:是Codesourcery公司基于GCC推出的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。arm-linux-gnueabihf-gcc
:是由Linaro公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kerrnel、filesystem和App应用程序。与上一个的主要区别在于hf,表示对于浮点数编译使用的规则不同,后面详细说明。aarch64-none-linux-gnu-gcc
:是由Linaro公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARMV8 64位CPU的裸机程序、u-boot、Linux kernel、filesystem和App应用用程序。arm-none-eabi-gcc
:是GNU推出的ARM交叉编译工具。可用于交叉编译ARMMCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。不支持操作系统,所以如果程序中有依赖系统调用等API接口则无法成功编译。
02
编译命名规则
arm编译工具链的命名规则如下:
<arch>-<vendor>-<os>-<abi>
arch(架构):描述目标处理器架构,如arm、aarch64。
vendor(供应商):一般填写none或者不填,表示没有特定供应商,常用于开源工具链。也可能是特定的公司名称(如apple或者特定平台的名字)。
os(操作系统):描述目标操作系统或者平台环境。
linux:表示目标系统是 Linux。
none:表示不依赖任何操作系统,常用于裸机编程。
elf:通常用于不依赖特定操作系统,但需要支持 ELF 格式。
abi(应用二进制接口):描述生成代码时使用的 ABI。
eabi:嵌入式应用二进制接口,适用于无操作系统环境。
eabihf: 嵌入式应用二进制接口,启用硬件浮点运算。
03
abi/eabi/eabihf
要完全搞懂几种编译工具链,还要再了解一下什么是工具链中经常出现的eabi?
什么是ABI?
ABI(Application Binary Interface),ABI 是对应用程序在运行时如何与操作系统或其他程序模块交互的详细定义。这包括函数调用约定、系统调用接口、二进制格式、库的链接方法、内存布局和寄存器使用等。
ABI是系统与应用之间的协议。一个BINARY(EXEC, LIB)必须符合ABI才能在相应的系统上运行。比如我在PC上用不管什么样的COMPILER, 只要产生符合LINUX的ELF文件, 用相应的指令集(比如INTEL, PPC, SPARC). 就可以在一个LINUX机器上运行,调用系统或别人的LIB。
简单来说ABI就是机器代码的一层封装接口,有点类似于系统调用的API接口,只不过ABI比API更接近硬件的一层接口,规定的是二进制代码之间的调用规则。
2. 什么是EABI?
EABI(Embedded Application Binary Interface),EABI 是专门为嵌入式系统设计的 ABI,在资源受限的环境中(如微控制器和嵌入式处理器)使用。它是常规 ABI 的一个子集,优化为嵌入式系统的需求。与通用计算机的ABI的主要区别是应用程序中允许使用特权指令,不需要动态链接和更紧凑的堆栈,广泛应用在ARM和Power PC中。
3. 什么是EABIHF?
HF代表hard float,它是在 EABI 基础上,进一步为支持硬件浮点运算进行优化的版本。与eabi
的最大区别在于eabihf
使用硬件浮点寄存器和浮点协处理器来进行浮点运算。这能显著提高涉及浮点运算的程序性能。
在早期嵌入式CPU(ARM7以前)中不包含FPU(浮点运算单元),会使用软件模拟实现,通过逻辑运算单元来处理浮点数。后来在CPU(Cortex-A系列)中逐渐支持了FPU,这时候编译器分为两种:软浮点(softfp)与硬浮点(hf)。
两种编译器都会使用FPU来计算浮点数,但是softfp使用普通寄存器来传参,而hf寄存器也是用FPU专用寄存器。所以sotffp一般用来兼容没有FPU的CPU,使用的较多。
然而最重要的来了,到了arm64时代,也就是ARMv8之后,ARM64引入了统一的ABI接口,不再区分ABI与EABI。并且所有的ARM V8架构都支持硬浮点运算,所以也不再区分hf。因此arm64的工具链就命名相对统一使用aarch64-none-linux-gnu-gcc
。
04
总结
最后做一个总结,我在这里给大家花了一个简单的示意图作为选择编译工具链的选择方法。
对于arm64架构统一使用aarch64-none-linux-gnu-gcc
即可,即使是裸机程序或者ATF等,也是可以用这个工具进行编译的,区别可能就是最后编译出来的产物稍大一些,对于空间没有那么敏感的时候可以不必作区分。
对于arm32架构,如果是裸机程序可以使用arm-none-eabi-gcc
,而对于uboot,linux使用arm-none-linux-eabi-gcc
。