BLOG

Record, summarize, and improve.

compiler

编译会知道三个系统名称:build使用的机器(build)、输出文件的机器(host)以及 GCC 将为之生成代码的机器(target)。配置 GCC 时,您可以使用 --build=、--host= 和 --target= 指定这些名称。

应避免只指定host而不指定build,因为 configure 可能(曾经)假定您指定的host也是build的主机,但事实可能并非如此。
  • 如果build、host和target都相同,则称为本机。
  • 如果build和host相同,但target不同,则称为交叉(cross)。
  • 如果build、host和target都不同,则称为 "加拿大人"(出于与加拿大政党和当时构建人员背景有关的晦涩原因)。
  • 如果host和target相同,但build不同,则是使用交叉编译器为不同的系统build本地程序。有些人称之为 host-x-host、cross-native 或 cross-built native。
  • 如果build和target相同,但host不同,那么你就是在使用交叉编译器编译一个交叉编译器,为你正在编译的机器生成代码。这种情况很少见,因此没有通用的描述方法。有人建议将其称为交叉回溯。

如果build和host相同,则编译的 GCC 也将用于编译目标库(如 libstdc++)。如果 build 和 host 不同,则您必须已经编译并安装了用于编译目标库的交叉编译器(如果您配置了 --target=foo-bar,则该编译器将被称为 foo-bar-gcc)。

就目标库而言,你所构建的机器就是你用 --target 指定的机器。因此,build 指的是正在编译的机器(没有变化),host 指的是正在编译的机器(目标库是为目标机器编译的,所以 host 就是你指定的目标机器),target 不适用(因为你编译的不是编译器,而是库)。
libiberty 支持库最多构建三次:一次用于主机,一次用于目标(即使它们相同),如果编译和主机不同,则一次用于编译。这样,在编译过程中生成的所有程序都能使用它。

交叉编译工具链编译过程

依赖关系

  • 最终的编译器需要C库来知道如何使用它,还需要binutils
  • 构建C库需要核心编译器(2)和binutils
  • 核心编译器(2)需要C库头文件和启动文件,以了解如何使用C库和binutils
  • 构建启动文件需要编译器、内核头文件和binutils
  • 核心编译器(1)需要binutils

构建C库需要编译器,可以通过构建一个精简的编译器来解决该编译器不需要C库,但能够构建C库

核心编译器(2)需要C库头文件和启动文件,因此需要构建一个只安装头文件和启动文件的C库启动文件(也称为C运行时CRT)是gcc需要在NPTL系统上启用线程本地存储(TLS)的极少数文件

构建启动文件需要编译器,因此需要构建一个更简单的编译器,它不需要头文件,但需要启动文件。这个编译器也是一个引导、初始或核心编译器。核心编译器(1)

为目标编译代码时,我们需要汇编程序和链接程序。当然,这样的代码是从C库构建的,所以我们需要在C库启动文件之前构建binutils,以及完整的C库本身。此外,gcc中的一些代码也将转而在目标上运行。幸运的是,对binutils没有要求。

依次构建组件:

  1. binutils
  2. 核心编译器(1)
  3. 内核头文件
  4. c库头文件和启动文件
  5. 核心编译器(2)
  6. 完整的C库
  7. 最终编译器

gcc有一些先决条件。它依靠一些外部库来执行一些重要的任务(比如处理常数中的复数……)。如果发行版不是太新的话,我们很有可能必须构建这些库(我们将在下面进行构建)。

  • GNU多精度算术库——GMP(GNU Multiple Precision Arithmetic Library);
  • 具有正确舍入的多精度浮点计算的C库——MPFR(Multiple-Precision Floating-point-computations with correct Rounding);
  • 复数算术的C语言库——MPC。

这些库的依赖关系如下:

  1. MPC需要GMP和MPFR
  2. MPFR需要GMP
  3. GMP没有先决条件

因此,构建顺序变为:

  1. GMP
  2. MPFR
  3. MPC
  4. binutils
  5. 核心通道1编译器
  6. 内核头文件
  7. C库头文件和启动文件
  8. 核心通道2编译器
  9. 完整的C库
  10. 最终编译器