交叉编译gcc时为什么一定要编译glibc?

交叉编译gcc时为什么一定要先编译一个freestanding的gcc,再编一个glibc,最后生成目标平台的gcc,如果把运行环境的根目录(包含gl…
关注者
19
被浏览
20,887
登录后你可以
不限量看优质回答 私信答主深度交流 精彩内容一键收藏

UPDATE:2023.02.09

C语言标准规定了两种运行环境: hosted freestanding

  • hosted 就是我们日常开发的用户程序的运行方式,它的入口点必须是main,原型也得符合标准。
  • freestanding 不指定程序的入口,由程序员自行决定;该模式适用于编译OS、bootloader、firmware等特殊的程序。

最终目标

我们的目的是制作一套支持目标平台的 完整工具链 ,它应该支持目标平台的所有特性和功能(ABI、系统调用等)。这个工具链里面的gcc就必然是支持生成hosted程序的完整版gcc。

终版gcc需要glibc

  • 生成hosted程序需要glibc的支持
  • gcc需要知道目标库glibc的路径
  • glibc依赖目标平台(比如printf等封装了对目标平台的系统调用的使用细节)。

注:gcc里面的libgcc也依赖于glibc(可以在构建gcc的时候,通过选项diable)

freestanding的gcc可以编译glibc

因此,我们应当编译出目标平台的glibc。好在freestanding的gcc足够编译glibc这种库。

本机的gcc可以编译目标平台的glibc,但是很难保证没有引用本地的依赖。

因此,保险起见还是先构建一个独立于本机的freestanding gcc。

流程

  1. 用本机的gcc编译一个freestanding-cross-gcc, cross-binutils(汇编器,链接器等)
  2. 用cross-gcc & cross-binutils,编译cross-glibc
  3. 用cross-glibc编译完整版的full-cross-gcc
  4. done

上面已经提到了,完整功能的gcc依赖glibc,也需要知道glibc的路径等信息。

因此,如果你拷贝本机的glibc,那么gcc会依赖你本机的环境,而且本机的glibc跟目标平台的架构不一定兼容。

目标平台的运行环境此时尚未构建,也没有glibc可以给你拷贝。


请先确认自己理解了编译期间要配置的几个 variant :

--host, --target,--build

==========================================

正好,我最近刚做完交叉工具链编译 GNU/Linux 系统。

一般是出于某种原因(一般是性能方面),要在宿主系统上打造一套工具链,能够在宿主系统上编译生成目标系统上的目标文件。

这个目标系统可能处理器架构、系统等等都和宿主系统完全不兼容。

所以,你说把运行环境拷贝到本地只适用于本地和目标系统环境一致或者兼容的情况下,是可行的。还有一个前提,你必须要在配置 binutils之前,就设置好sysroot的路径,并且保证你正确地拷贝目标系统上的 glibc 的相关文件到该路径。

这样,你在编译完整版gcc的时候,才能让交叉链接器到你想要的sysroot去链接libc。

这种方式很难保证没有依赖到宿主机器,但是因为宿主环境和目标环境一致,所以你也看不出来问题 。。。

==================================

为什么要先编译 freestanding 的gcc

简而言之, 要解决“鸡和蛋”的循环依赖问题

1).编译 glibc 需要目标一致的gcc

编译运行 (--host=$TARGET) 在目标平台上的 glibc,需要 ( --target=$TARGET ) 设置一致的 gcc,而不是目标为本地的 gcc;

2).编译完整版gcc需要glibc

  1. 理论上,gcc不应该依赖于C库。但是,gcc 需要包含一些 glibc 的头文件来了解要支持哪些 C 库的特性;
  2. gcc 中也使用了一些C库的接口 (有现成的接口,谁还想再发明一遍轮子);
  3. gcc 不光是编译器,他还包含了一些库,这些库依赖于 glibc。

freestanding 的gcc不需要依赖于glibc,所以用它先编译glibc,然后完整版的gcc就有了。。。

编辑于 2023-02-09 11:43 ・IP 属地新加坡