1、什么是交叉编译
嵌入式开发过程中,由于嵌入式平台不一定有操作系统,也就运行不了编译程序(如 gcc 和 llvm)。即便能运行,受限于 CPU 性能,编译效率也会比较“感人”。
编译过程是将源码转化为目标平台二进制指令的过程,并不涉及二进制的执行,所以本身不存在对目标平台的硬件依赖,因此编译过程和执行过程可以是不同的平台。考虑到开发效率,构建环境可以是 PC 或者服务器环境,完成编译过程后再将二进制下载到嵌入式单板执行。这种构建环境和运行环境(主要是操作系统、处理器架构和型号)不同的情况,就涉及交叉编译。参考维基百科中对交叉编译的定义:交叉编译是指在一个平台生成另一个平台可执行文件的过程。
2、交叉编译的使用
1)交叉编译器的选择
以在 x86 Linux 环境构建 arm64 平台下的可执行文件为例,第一步就需要在构建环境中安装交叉编译器。一般在对应体系结构的官网上可以找到对应的交叉编译器。如 arm 平台交叉 gcc 编译器的下载路径为:
https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
在该页面看到有很多个版本,这里需要根据交叉编译器的命名规则选择适合自己的版本。一般来说,交叉编译器的命名规则为:
arch[-vendor][-os]-abi
arch:目标平台的架构,如 arm,aarch64(arm64 ),riscv32,x86,x86_64 等。
vendor:提供编译工具链的厂商,如 mingw-w64。
os:目标平台的操作系统,如 linux。指示编译器使用哪些库和如何使用系统调用。
abi:用于指示编译器使用的二进制接口(Application Binary Interface)类型,如 gnueabi 表示 GNU 的 EABI(Embedded Application Binary Interface)。gnueabihf 在 gnieabi 的基础上指示编译器使用硬件浮点单元进行浮点运算(不带 hf 的编译器使用软件浮点)。abi 相同的二进制可以进行互操作。
并不是所有的编译器都会严格按照这个规则命名,还有的命名规则中将 vendor 替换为了 core,用于指示具体的 CPU 型号,如 arm-cortex_a8-linux-gnueabi。
常见的交叉编译器:
arm-none-eabi:arm 架构,不含 vendor,目标平台不带 OS(裸机系统),使用 ARM 的 eabi。
aarch64-none-linux-gnueabihf:aarch64 架构,不含 vendor,目标平台为 Linux 系统,使用支持硬件浮点的 GNU EABI。
x86_64-w64-mingw32:x86_64 架构,厂商为 mingw-w64(w64 = mingw-64),二进制接口为 mingw32(Minimalist GNU for windows)。
arm-elf-eabi:arm 架构,不含 vendor,构建可以跑在任何支持 elf 文件并且支持 EABI 的系统上。
arm-elf:用于构建操作系统无关的 arm 体系结构下通用的 elf 文件。
通过以上介绍,就可以根据自己的构建环境在 arm 官网选择适合自己的工具链了。
2)交叉编译器的使用
选择完合适的交叉编译器后,还需要通过编译选项给编译器传递目标平台的更多信息,方便编译器生成正确且高效的可执行文件。这些选项往往和体系结构相关,需要查看编译器手册中对应体系结构相关的描述使用。以 aarch64 体系结构为例为例,和交叉编译相关的编译选项有:
-mabi=name
用于指定特定的数据模型,比如可以通过 "ilp32" 指示编译器将 int、long 和 pointer 都按照 32 位处理。
-mbig-endian/-mlittle-endian
用于指定生成大端/小端的代码。
-march=name
用于指定特定的体系结构,编译器据此决定如何生成汇编指令。aarch64 下可选的体系结构有:armv8-a、armv8.1-a、armv8.2-a…armv8.7-a、armv9-a、armv8-r 等。
-mtune=name/-mcpu=name
用于指定具体的 CPU 型号,编译器可据此执行更具体的优化。可选的型号有:generic、cortex-a35、cortex-a53、cortex-a55、cortex-a57、cortex-a72、cortex-a73、cortex-a75、cortex-a76、cortex-a77、cortex-a78、cortex-a78ae、cortex-r82、cortex-x1、cortex-x2、cortex-a510、cortex-a710 等。还可指定为 cortex-a57.cortex-a53、cortex-a72.cortex-a53、cortex-a73.cortex-a35、cortex-a75.cortex-a55、cortex-a76.cortex-a55 等指示编译器针对 big.LITTLE 架构进行优化。还可以指定为 native,编译器可以根据构建环境的 CPU 型号进行优化。
当 march、mtune 和 mcpu 均未指定时,编译器将尽可能生成通用的指令。而如果 多个选项均提供且存在冲突时,march 和 mtune 选项的设置将拥有更高的优先级。
march 和 mcpu 选项可以根据 CPU 支持的特性类型通过 arch/cpu{+[no]feature} 的形式对某些特性进行开关设置。相关的特性有:crc(使能 CRC 扩展)、crypto(使能 crypto 扩展)、fp(使能硬件浮点单元)、simd(使能 SIMD 指令)、sha2(使能 sha2 扩展)、sha3(使能 sha3 扩展)、sm4(使能 sm4 扩展)。