1 为什么要交叉编译
在嵌入式开发过程中有宿主机和目标机的角色之分:宿主机是执行编译、链接嵌入式软件的计算机;目标机是运行嵌入式软件的硬件平台。
目标平台不具备编译环境:有时候,目标平台(例如嵌入式设备或移动设备)可能没有足够的计算资源或存储空间来支持源代码的本地编译。在这种情况下,使用一台性能更强大的主机进行交叉编译可以更高效地生成目标平台上可执行的代码。
平台兼容性:不同的体系结构和操作系统具有不同的指令集和库,因此无法直接在一个平台上运行另一个平台的代码。通过交叉编译,可以将源代码编译为适用于目标平台的二进制文件,以确保代码在目标平台上正确运行。
开发效率:在软件开发过程中,通常会使用高性能的开发主机来编写、调试和测试代码。然而,最终的目标可能是在低功耗设备或嵌入式系统上运行代码。通过交叉编译,可以在开发主机上进行快速的开发、调试和测试,然后将生成的可执行文件部署到目标平台上,提高开发效率。
跨平台开发:对于跨平台应用程序或库的开发,交叉编译是一种常见的方法。它允许在一台主机上编译和构建适用于多个目标平台的代码,从而简化了跨平台开发的复杂性。
2 交叉编译工具链命名规则
在使用交叉编译链时,常常会看到下面这样的名字:
arm-linux-gnueabihf-
arm-none-linux-gnueabi-
arm-cortex_a8-linux-gnueabi-
mips-malta-linux-gnu-
这些交叉编译链的命名通常会遵循一定的规则:arch-vender-os-abi
,各字段说明如下:
- arch:目标cpu架构,比如mips、arm、x86、riscv等,该字段通常不会省略
- vendor:提供此编译工具链的厂商名称或是厂商特定信息,该字段只是标识信息,没有实际意义,可以为none、cross、unknow或是直接省略
- os:目标设备上运行的操作系统,常见的有linux、none(裸机)等
- abi:应用程序二进制接口(Application Binary Interface),交叉编译链所选择的库函数和目标映像的规范,该字段常见的值有abi 、eabi(embedded abi)、gun(glibc+oabi)、gnueabi(glibc+eabi)、gnueabihf (hf 指默认编译参数支持硬件浮点功能)等
工具链的种类
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。
arm-none-eabi-gcc 一般适用用于 Arm Cortex-M/Cortex-R 平台,它使用的是 newlib 库。arm-linux-gnueabi-gcc 和 aarch64-linux-gnu-gcc 适用于 Arm Cortex-A 系列芯片,前者针对 32 位芯片,后者针对 64 位芯片,它使用的是 glibc 库。可以用来编译 u-boot、linux kernel 以及应用程序。
另外需要补充一点的是,32 位的 Arm 和 64 位的 Arm,它们的指令集是不同的,所以需要使用不同的工具链。当然,Arm64 为了保证前向兼容,提供了一个 32 位的兼容模式,所以我们用 arm-linux-gnueabi-gcc 编译的应用程序也是可以直接在Arm64 的系统上运行的,但是 Linux Kernel 和 U-Boot 就不行,除非你提前把 CPU 切换到 32 位模式。曾经有个项目使用了一颗四核的 Arm64 芯片,但是内存只有64M,为了节省空间,在 CPU 运行到 U-Boot 之前,我们就把它切到了 32 位模式,后面的 U-Boot、Linux Kernel,应用全部都用 32 位编译,加上 Thumb 指令集,节省了不少空间。
3.GCC交叉编译工具链
GCC(GNU Compiler Collection)是一个广泛使用的编译器套件,提供了用于多种体系结构的交叉编译工具链。对于Linux系统上的交叉编译,GCC交叉工具链是一个常见且强大的选择。
GCC交叉工具链的命名约定通常使用目标体系结构作为前缀,并在后面加上"-"和ABI(Application Binary Interface)标识符。以下是一些常见的GCC交叉工具链示例:
1. arm-linux-gnueabi-gcc:用于ARM体系结构的交叉编译工具链。"arm"表示ARM体系结构,"linux"表示目标操作系统为Linux,"gnueabi"表示使用GNU的嵌入式ABI。
2. arm-linux-gnueabihf-gcc:与上面的工具链类似,但是添加了"hf"表示使用硬浮点(hard-float)的ABI。这意味着该工具链支持使用硬件浮点指令进行浮点运算。
3. x86_64-linux-gnu-gcc:用于x86-64体系结构(也称为AMD64或Intel 64)的交叉编译工具链。"x86_64"表示目标体系结构为x86-64,"linux"表示目标操作系统为Linux,"gnu"表示使用GNU的ABI。
4. mips-linux-gnu-gcc:用于MIPS体系结构的交叉编译工具链。"mips"表示MIPS体系结构,"linux"表示目标操作系统为Linux,"gnu"表示使用GNU的ABI。
这些工具链提供了gcc、g++等编译器和相关工具,可以用于编译C、C++等源代码,并生成适用于特定体系结构的可执行文件。您可以根据目标体系结构和所需的ABI选择适当的GCC交叉工具链。
举个例子
当使用GCC交叉工具链时,以下是一个示例:
假设您正在开发一个嵌入式系统,目标平台是ARM体系结构,并且目标操作系统是Linux。您可以使用arm-linux-gnueabi-gcc来进行交叉编译。
- 编写源代码:创建一个名为"hello.c"的C语言源文件,内容如下:
#include <stdio.h> int main() { printf("Hello, world!\n"); return 0; }
- 执行交叉编译:在命令行中使用arm-linux-gnueabi-gcc工具链进行交叉编译,生成适用于ARM体系结构的可执行文件。命令如下:
arm-linux-gnueabi-gcc -o hello hello.c
这将使用arm-linux-gnueabi-gcc编译器将"hello.c"源文件编译为名为"hello"的可执行文件。