编译会知道三个系统名称: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没有要求。
依次构建组件:
- binutils
- 核心编译器(1)
- 内核头文件
- c库头文件和启动文件
- 核心编译器(2)
- 完整的C库
- 最终编译器
gcc有一些先决条件。它依靠一些外部库来执行一些重要的任务(比如处理常数中的复数……)。如果发行版不是太新的话,我们很有可能必须构建这些库(我们将在下面进行构建)。
- GNU多精度算术库——GMP(GNU Multiple Precision Arithmetic Library);
- 具有正确舍入的多精度浮点计算的C库——MPFR(Multiple-Precision Floating-point-computations with correct Rounding);
- 复数算术的C语言库——MPC。
这些库的依赖关系如下:
- MPC需要GMP和MPFR
- MPFR需要GMP
- GMP没有先决条件
因此,构建顺序变为:
- GMP
- MPFR
- MPC
- binutils
- 核心通道1编译器
- 内核头文件
- C库头文件和启动文件
- 核心通道2编译器
- 完整的C库
- 最终编译器