LFS && Raspberry && pin

最近干了这三件事。记录之。

LFS:Linux from scratch。

LFS是我的一个心结,很久之前就说要好好做一遍这个,却一直借口没有时间,其实真正做下来也就花了25个小时左右,两次机房血战就差不多能做一次了。

LFS的基本思想是借助一台已有的linux环境,从碎片开始安装linux。自己搭建工具链,自己编译内核,自己编译shell。所有的一切都是从源代码开始一点一点慢慢编译。

做LFS学到的东西比我预期少了点,init之后的启动流程还是云里雾里,估计这阶段是不会认真去读那堆启动脚本了,留个遗憾。

最大的收获就是工具链的制作原理以及常用命令都是来自哪个包。

GNU的工具链分为三个部分,binutil,Glibc,GCC。

GCC负责编译,把c语言代码编译成汇编语言。这期间会用到C库(glibc)。

Glibc主要包括C库,还有动态加载器(/lib/ld-linux.so.2),此动态加载器负责加载二进制文件到进程地址空间。

Binutil是二进制工具,处理二进制文件。包括ar,as(汇编器,把汇编文件翻译成二进制文件),ld(静态链接器),以及我最喜欢的反编译objdump。

这三者的关系如下:

Gcc编译过程需要链接Glibc。

Binutil编译过程需要链接Glibc。

Glibc是自包含的,编译过程不需要链接到Glibc,但是它需要工具链来编译自己,并受到工具链的影响,工具链是什么?工具链就是gcc+glibc+binutil(严格来讲编译glibc时不需要宿主的glibc,只要gcc和binutil就可以)。

基本上算是循环依赖= =!。

那么如何制作一个pure的工具链?LFS曾今的做法也是有缺陷的,后来被一名内核黑客提出了改进办法[1]。

现今的办法如下:

(注:gcc0表示第0代gcc,也就是宿主上原来的gcc程序,gcc1表示第一次编译出来的gcc。其他同)

gcc0 + glibc0 + binutil0 -> binutil1,gcc1 (一代gcc和binutil链接都是宿主上的glibc,所以受宿主的影响)

gcc1 + binutil1 -> glibc1 (一代glibc 只受一代gcc影响,开始隔离宿主)

gcc1 + glibc1 + binutil1 -> binutil2, gcc2 (二代工具链用的是新生成的glibc1)

gcc2,binutil2,glibc1 三者构成了临时编译环境。用这套工具链生成了一堆临时环境需要用到的各种工具,比如make,sed等等。

Gcc2 + binutil2 -> glibc2

Gcc2 + binutil2 + glibc2 -> gcc3 ,binutil3

Gcc3,binutil3,glibc2 三者构成了最终LFS的编译环境,LFS上最后运行的所有程序都是来自这三个家伙。

(吐槽一句,其实无论怎么折腾,这也是个鸡生蛋蛋生鸡的问题,只要在gcc0中做手脚,后面的gcc永远不会干净。在此向伟大的C语言之父Dennis Ritchie致敬。)

LFS意外收获:

  1. cp abc{,.new}  = cp abc abc.new
  2. tar xf file.tar.**          不用指定压缩算法,tar自动探测,指定还容易指定错- -!
  3. W命令看当前登录用户,lastb 看最后失败登录。

 

 

[1]http://www.linuxfromscratch.org/hints/downloads/files/OLD/pure_lfs.txt