LV005-交叉编译简介
一、什么是交叉编译?
1. 本地编译
在当前的 PC 下,x86 的 CPU 下,直接编译出来程序,可以运行的程序(或者库文件),其可以直接在当前的环境,即 x86 的 CPU 下,当前电脑中,运行。
此时的编译,可以叫做:本地编译,即在当前目标平台下,编译出来的程序,也只是放到当前平台下,就可以运行的。
2. 交叉编译
交叉编译是一种在一个平台上生成另一个体系结构不同的平台可执行代码的编译方式。
通常情况下,我们在一台计算机上编写和编译程序,编译后的可执行文件只能在与编译环境相同的硬件架构和操作系统上运行。但在一些特殊场景中,比如开发嵌入式系统、为不同架构的移动设备开发应用,或者针对特定的专用硬件平台进行软件开发时,就需要用到交叉编译技术。它允许开发者在自己常用的开发环境(如 x86 架构的 PC 上),编译出能够在其他不同架构(如 ARM 架构的嵌入式设备)上运行的代码。

3. 为什么要交叉编译?
主要原因是:嵌入式系统中的资源太少。
在进行嵌入式开发时,目标平台,即嵌入式开发板,比如是最大主频 200MHz 的 ARM 的 CPU,加上 32M 的 RAM,加上 1G 的 Nand Flash 等等。在如此相对比较紧张的硬件资源的前提下,还要运行了嵌入式 Linux 系统,是基本没法直接在嵌入式 Linux 下,去本地编译可以供开发板使用的程序。因为编译,开发,都需要相对比较多的 CPU,内存,硬盘等资源,而嵌入式开发上的那点资源,只够嵌入式(Linux)系统运行的,没太多剩余的资源,供本地编译使用,当然其实也不是不可以,对于一些处理性能很强的平台,可以编译一些比较小的程序,稍微大一点,编译速度就会很慢。
所以我们还是离不开 X86 电脑强大高效的桌面环境进行软件开发。但是这样有一个问题,X86、Arm、MIPS、RISC-V 这些芯片,它们的指令集是由不同的组织或者公司设计的,彼此并不兼容——Arm 和 MIPS 的 CPU 无法运行以 X86 的指令集编码的程序,反之亦然。所以我们要在 X86 的电脑上编译出能够在 Arm 上运行的程序,我们必须明确告诉编译器,编译生成的可执行文件需要以 Arm 指令集的标准编码。为了让这个流程变得简单,开发者们为不同的芯片开发了不同的编译器,比如针对 Arm 平台的 arm-linux-gcc,针对 mips 平台的 mips-linux-gnu-gcc,这些编译器都是基于 GCC 针对具体的架构指令集进行对应配置,所以它们在运行的时候就就会生成和该目标平台对应的可执行文件。
那么交叉编译有哪些优势?
- 方便开发:开发者可以在自己熟悉的开发环境中进行代码编写和调试,无需频繁切换到目标设备的环境,提高了开发效率。
- 支持多种平台:能够轻松地为不同架构和操作系统的设备开发软件,扩大了软件的适用范围。比如,一个软件可以通过交叉编译同时支持 Windows、Linux、Android 等多种平台。
- 提前测试:在开发主机上完成交叉编译后,可以在目标设备或模拟器上进行测试,及时发现和解决兼容性问题,减少在目标设备上直接开发和调试的时间成本。
二、交叉工具链
1. 工具和链
所谓的工具链,包含两部分:工具和链。
1.1 工具
工具:即 tool,目标是为了生成(可以运行的)程序或库文件。而为了达成此目标,内部的执行过程和逻辑主要包含了 编译、链接。
- 编译
编译所需要的工具就是编译器,在交叉编译中,称之为交叉编译器。例如 Ubuntu 中安装使用的 GCC 编译器是针对 X86 架构的。而我们现在要编译的是 ARM 架构的代码,所以我们需要一个在 X86 架构的 PC 上运行,可以编译 ARM 架构代码的 GCC 编译器,这个编译器就叫做 交叉编译器。
在这里,我使用的是开发板配套教程中 Linaro 出品的交叉编译器,而作为初学者的我,还是先跟教程走吧,哈哈。所以我使用的就是 4.9 版本的编译器啦。相关网址如下:
| linaro 官网 | https://www.linaro.org/ |
| 4.9 版本交叉编译器 | gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz |
- 链接
链接的输入(对象)是(程序运行时所依赖的,或者某个库所依赖的另外一个)库(文件)。链接的输出(目标)是:程序的可执行文件,或者是可以被别人调用的完整的库文件。链接所需要的工具是:链接器,即 ld
- 还有一些其他工具
实际上,上面所说的 ld,只是处理操作目标文件,二进制文件的最主要的一个工具。而和操作目标等文件相关的,还有其他很多工具的:as,objcopy,strip,ar 等等工具的。
所以,对此,GNU 官网,有一个 binutils,即 binary utils,二进制工具(包),集成了这些,和操作二进制相关的工具集合,叫做 binutils。所以,之后我们所见到的,常见的工具,就是刚才说的的著名的 GNU Binutils 了。
1.2 链
链,即链条,chain。之所以能称为链,说明不止一个东西,然后,按照对应的逻辑,串在一起,链在一起。而对应的,描述中涉及到的:
不止一个东西:指的是就是前面所说的那个工具,即和程序编译链接等相关的 gcc,binutils 等工具。
按照对应的逻辑:指的就是,按照程序本身编译链接的先后顺序,即先编译,后链接,再进行后期其他的处理等等,比如用 objcopy 去操作相应的目标文件等等。
如此的,将和程序编译链接等相关的 gcc,binutils 等工具按照先编译后链接等相关的编译程序的内在逻辑串起来,就成了我们所说的 工具链。
2. 工具链种类
GCC 的命名规则为:
arch [-vendor] [-os] [-(gnu)eabi]-gcc比如 arm-linux-gnueabi-gcc ,arm-none-eabi-gcc, aarch64-linux-gnu-gcc,其中:
- 带
[]的是可选部分。 - arch: 芯片架构,比如 32 位的 Arm 架构对应的 arch 为 arm,64 位的 Arm 架构对应的 arch 为 aarch64。
- vendor :工具链提供商,大部分工具链名字里面都没有包含这部分。
- os :编译出来的可执行文件(目标文件)针对的操作系统,比如 Linux。
3. 交叉工具链
用于交叉编译的工具链,就叫做交叉工具链。即那些工具,即编译的 gcc,链接的 ld,以及相关的工具,用于交叉编译的,工具链,叫做交叉工具链。
交叉工具链,很明显,是用来,交叉编译,跨平台的程序所用的。交叉工具链,和(本地)工具链类似,也是包含了很多的,对应的工具,交叉编译版本的 gcc,ld,as 等等。但是,由于其中最最主要的是用于编译的 gcc,所以,我们也常把:交叉工具链,简称为交叉编译器。
严格意义上来说,交叉编译器,只是指的是交叉编译版本的 gcc。但是实际上为了叫法上的方便,我们常说的交叉编译器,都是指的是交叉工具链。常说的交叉编译版本的 gcc,比如 arm-linux-gcc,实际上指代了,包含一系列交叉编译版本的交叉工具链(arm-linux-gcc,arm-linux-ld,arm-linux-as 等等)而此文中,后面,所说的,如无特殊指明,均用交叉编译器指代交叉工具链。
4. 小结
其实我们可以看一个交叉编译工具链的内容都有哪些,比如这个gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz 我们下载后解压,这里就不展示了。解压后会发现,除了一些工具,还有大量的库和头文件。
其实交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发环境,交叉编译工具链主要由 binutils、gcc 和 glibc 三个部分组成。有时出于减小 libc 库大小的考虑,也可以用别的 c 库来代替 glibc,例如:uClibc、dietlibc 和 newlib。
参考资料: