凌云的博客

行胜于言

交叉编译工具链

分类:Linux| 发布时间:2021-04-12 17:44:00

前言

本文主要描述了交叉编译工具链的概念以及如何自己编译交叉编译工具链。

什么是交叉编译工具链

交叉编译工具链指的是一组用于将源代码编译成 target(目标)平台二进制代码的工具,包括:

  • 不同的 CPU 架构
  • 不同的 ABI
  • 不同的操作系统
  • 不同的 C 库

在编译交叉工具链的时候包含三个名称:

  • build 编译交叉编译工具链所在的机器
  • host 交叉编译工具链要运行的机器
  • target 交叉编译工具链生成的二进制代码所在的机器

对于 native toolchain 来说,build == host == target,而对于交叉编译来说,build == host != target。

这里的 build、host 和 target 对应了 autoconf 的 configure 脚本的 --build 、 --host 和 --target 选项。

在 autoconf 中 --build 等参数由以下组成:

<cpu>-<vendor>-<os>

或者

<cpu>-<vendor>-<os>-<libc/abi>

  • cpu 表示 CPU 的架构,比如 arm 、mips 、i686 、x86_64 等
  • vendor 任意字符串,会被 autoconf 忽略
  • os 操作系统,比如 linux
  • libc/abi 使用的 libc 和 ABI

交叉编译工具的构成

对于 Linux 来说,交叉编译工具主要由以下部分组成:

  • binutils
  • gcc
  • Linux kernel headers
  • C library

由于 Linux kernel 是向后兼容的,因此如果你的交叉工具编译链使用的 kernel headers 的版本必须要与 目标系统的 kernel 版本相同或者比目标系统的 kernel 版本更新。

比如:

  • 工具链使用的是 3.1 版本的 kernel header,然后编译出来的二进制文件运行在 4.4 版本的 kernel 这种情况是可以的
  • 工具链使用的是 4.8 版本的 kernel header,然后编译出来的二进制文件运行在 4.4 版本的 kernel 这种情况是不行的

交叉编译工具总体流程

  • 编译 binutils
  • 编译 GCC 的依赖:mpfr、gmp、mpc
  • 安装 Linux kernel headers
  • 编译第一阶段的 GCC,此时的 GCC 不支持 C library,只支持静态链接
  • 使用上一阶段的 GCC 编译 C library
  • 编译最终版本的 GCC,支持 C library 以及动态链接

sysroot 的概念

sysroot 是一个放置 headers 和 库文件的逻辑根目录。比如你的编译工具想寻找 /usr/include/foo.h 这个头文件, 对于交叉编译工具来说 foo.h 适当的位置为 /my/other/place/usr/include/foo.h 那么你应该使用 /my/other/place 作为你的 sysroot。

编译 GCC 的时候可以使用 --with-sysroot 选项指定,gcc 的 sysroot 可以通过:

path_of_gcc -print-sysroot

命令来参看,如果没输出表示 sysroot 为 /。

可以使用 gcc 的 --sysroot 参数来动态改变 gcc 使用的 sysroot。

什么是 ABI

ABI 是 Application Binary Interface 的缩写。

对于编译工具来说 ABI 定义了:

  • 函数如何调用
    • 函数参数如何传递,是在寄存器(哪一个寄存器)还是堆栈中,64 位的参数如何在 32 位的机器上传递等
    • 函数的返回值如何传递
  • 基础数据类型的大小
  • 结构体中的成员如何对齐
  • 当有操作系统时,如何进行系统调用

不同 ABI 的 object files 不能链接在一起(如果你由一些预先编译好的 object files 时这很重要)

对于特定的 CPU 架构,可能会拥有无数种 ABI,ABI 只是如何使用 CPU 架构的规格说明书。

如何获得交叉编译工具链

最简单的方法肯定时直接使用 Linux 发行商提供的交叉编译工具链,比如在 x86 的 Ubuntu 下可以使用如下命令安装 arm64 版的 gcc:

sudo apt install gcc-aarch64-linux-gnu

当然如果你需要的交叉编译工具链 Linux 发行商没有预先提供,可以自行编译,推荐使用 Crosstool-NG 进行编译。

参考