LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 20563|回复: 49

[原创]换个角度看LFS——反向分析LFS

[复制链接]
发表于 2006-6-21 14:25:06 | 显示全部楼层 |阅读模式
更新日志
2006-08-12:修改有歧义的句子一处。
2006-06-21:增加对结尾插图的说明。
2006-06-21:修改最后一副插图。
2006-06-21:修改笔误一处。

前言
  写了几篇关于LFS的制作过程中的文章,但分析性的文章还没怎么写过,论坛上也有一些分析性的文章,但大多数都是真对某个特定部分的,最近酝酿了一下,准备写点分析性质的文章调剂调剂。
  这次用的标题大概已经能说明本文分析的角度,按照LFS的顺序写,似乎总不能摆脱LFS的制作过程的牵制,总觉得像写制作教程,所以决定反过来写,利用一个大家熟悉的情景为开始反过来推出整个LFS的过程,本文不能算专业的分析文章,只是想简单的说明白LFS为什么要这样的过程。
  本文并不是要完全还原LFS,只是为了说明一种分析过程,因此文中部分内容和实际的LFS略有出入。
  限于水平的问题,我只能将我现在的理解来写,如果有什么错误或者不当的地方希望大家及时指出。
  本文的读者应该是一个已经经历过LFS至少一次的朋友,如果你从来没搞过LFS,建议亲自动手制作一遍后再看本文,应至少看过下面文章中的一篇:
  《Linux from scratch》英文版本
  《LFS-Book 6.1.1 中文正式版》
  《手把手教你如何建立自己的Linux系统(LFS速成手册)》

  更新,由于篇幅比较长所以难免出现一些错误或者笔误,也有可能加入新内容,因此难免会进行修正或增删一些内容,如果本文被转载您可以在本人的Blog或者www.linuxsir.cn的LFS版中中查看最新版本。
  我的Blog:http://youbest.cublog.cn
  linuxsir:
http://www.linuxsir.cn/bbs/showthread.php?t=262010
  如须转载请注明作者为冲天飞豹(youbest),并请保持文章的完整和提供转载出处。

工作情景:
  我正在用VIM编辑一篇文件


分析:
  问:那么要完成这个任务我需要些什么呢?
  答:硬件(略),本文将不对硬件做任何分析。
    软件:VIM

  问:那么运行VIM又需要什么条件呢?
  答:一个Linux内核
    一组支持VIM运行的动态库,按照比较标准的组合,应该是glibc和ncurses这两个库来承担VIM的运行时动态库

  问:那么内核需要什么条件呢?
  答:符合内核运行的硬件环境。

  问:glibc又需要什么条件呢?
  答:于glibc相适应的Linux内核

  问:ncurses需要什么条件呢?
  答:合适的glibc

最后我们来画一副图来描述这个关系



  那么这个关系图基本上就可以描述一个VIM运行的环境需求,当然在启动VIM的过程中少不了一个shell的参与,通常我们用BASH来完成,那么这个任务的整个大致环境和关系大致如下图所示。



  清楚了这个问题,下面需要解决的就是这个运行环境从哪里来的呢?
  通常Linux下的软件都提供了源代码,我们可以用这些源代码来组合成我们自己需要的二进制程序。
  在这个例子中,我们想要有一个VIM,那么我们要先下载一份VIM的完整源代码,然后利用一组编译工具来完成VIM的编译。
  对于一个通常编译的过程大致如下图


  这其中最复杂的就是make阶段,make会调用目录中的Makefile来执行一系列的工作,其中包括创建必要的文件,以及调用gcc和binutils来编译源代码和链接目标文件,最终生成需要的可执行文件和附属文件。
  所以make过程中一般需要用到的是gcc,binutils,make和一些系统程序(不同的软件需求不同)。



这样我们再来画最开始的运行环境的图



  好了,这样我们就清楚了这个整个运行时候的环境是从哪里来的了。用红色虚线框起来的就是整个构造运行时环境的必要条件了,其实就是我们通常在LFS中最常见到的一个词汇:工具链。
  那么下面的一个问题就是这些工具运行的条件是什么?
  这些编译环境中的应用程序也和其它程序一样必须有运行的环境:
  GCC依赖于glibc
  binutils依赖于glibc
  make依赖于glibc
  头文件是在编译时候gcc所需要的,但本身都是一些文本文件,因此没有需要的运行环境。
  常用工具依赖于glibc和各种需要用到的动态库。


  这里的一个新问题就是编译环境中使用的glibc和Linux内核和“运行时环境”中的glibc与Linux内核是否是同一个。
  答案很显然,绝对不是,因为“运行时环境”中的glibc和Linux内核是依靠工具链中编译工具来完成的,所以工具链所依赖的glibc和Linux内核于目标系统的不可能是同一个(但版本什么的是可以一样的,这里说的不同是指已经编译成二进制的实体不同)。
说明:
  为了说明方便,下面将“运行时环境”称为目标系统。
  但就LFS而言目标就是要做一个通用的可自主扩展(编译)的系统,所以在完成目标系统的glibc后又编译了一整套工具链中的东西,目的是将工具链中的工具全部移植到目标系统中,以便在完成目标系统后可以抛弃工具链而又能够自主的进行编译,而这些工具依赖的环境就是目标系统的glibc了。
  内核这东西比较特殊,虽然运行任何程序都需要用的内核,但本身在制作目标系统过程中,目标系统的Linux内核却不需要先进行编译,因为使用Linux内核并不像glibc那样是依靠动态链接库的方式被调用的,内核不是用动态库的方式被调用的,因此不需要先编译,只要提供对应的头文件即可,后面将不再探讨Linux内核的问题。
  作为LFS的另一个目标就是要建立一个“纯净”的系统,因此编译glibc的编译器和最后目标系统里的编译器应该保持一致,同时目标系统是完全依靠工具链编译出来的,而工具链应该是在目标系统建立完毕后可以很方便的剥离掉的,而且为了保持工具链的稳定工具链中的工具所依赖的glibc以及其它用到的动态库应该是不会被替换掉的。
  要解决上面这个问题,那么最好的方法就是将工具链放置在一个独立的目录中,LFS将其放在了/tools目录下,因此在用工具链建立目标系统的过程中将PATH设置为/bin:/usr/bin:/tools/bin来让bash调用命令时能首先调用目标系统中已经建立好的命令,如果没有则从工具链中调用。这样的话在目标系统还没有编译工具的情况下使用工具链来进行编译。
  好了,现在已经可以用工具链来完成目标系统的编译了,下面的问题就是这个工具链是如何来的呢?
  这个问题就要回到前面所提到的工具链运行时所依赖的环境,还是这个glibc,要编译这个glibc必须是在工具链的编译工具生成之前,而工具链的编译工具又依赖于glibc,那么这个glibc就不能是现在工具链中的编译工具编译出来的,那么是谁编译的呢?
  这个问题的答案:当然还是编译器编译的这个glibc和工具链里的编译工具,也就是说在工具链中的编译工具编译目标系统之前需要另一个编译器来编译这个在使用的工具链中的编译器和编译器所依赖的glibc。



  用蓝色的虚线框起来的部分就是生成工具链的工具链,我暂时称为“预工具链”。
  “预工具链”的存在则能完成工具链中的glibc,以及工具链中的编译工具,并且工具链中的工具将被编译成依赖于工具链中的glibc。
  那么现在要解决的问题就是这个“预工具链”是如何建立起来的。
  答案还是一样,需要一套编译工具来编译出这个“预工具链”。

  现在要提到的一个问题就是,用不同版本的gcc编译出来的程序可能不一样,而不同的gcc编译出来的目标文件要用能正确处理的binutils的版本来链接成可执行文件,因此我们现在已经能确定的gcc、binutils版本是工具链中的版本,那么用工具链编译出来的目标系统是符合我们的要求的。
  那么编译工具链中的glibc和gcc以及binutils的gcc和binutils的版本现在还没有确定,但根据LFS的“纯净”目标,也就是说gcc和binutils也必须和工具链中的gcc和binutils相同才行。而其它的常用工具及make虽然参与,但不会对编译的二进制产生影响(前提是必须能正确处理它应该做的事情)。

  现在的问题就集中到“预工具链”中的gcc和binutils上了,只要能编译出和工具链中的gcc与binutils相同版本就可以了,也就是说只要一套编译环境能编译gcc和binutils就可以了。

  那么问题是这一套编译环境是怎么来的呢?
  如果还继续按照前面的套路,这个问题就成了无穷无尽的了,这个不是我们想做的,现在已经能“纯净”的建立一套符合条件的工具链就已经达到我们的目的了,因此编译“预工具链”的binutils和gcc的任务我们就采用一套能正确编译的发行版或者预制好的编译环境就可以了,我们可以称这个发行版或者预制好的编译环境为“主系统”。
  那么我们现在只要能用这个“主系统”编译出“预工具链”的binutils和gcc就可以了,“预工具链”中的其它部分就直接采用“主系统”里的就可以了。
  但这里有一个问题就是:“主系统”中的gcc和binutils与“预工具”中要求的gcc和binutils版本不同(通常会老些),但只要能正确编译binutils、gcc就行了,gcc具备自我编译的功能,因此建议编译不同版本的gcc采用bootstrap的方式比较好。当然“主系统”中的在参与编译过程中的其它工具也需要符合要求就成。
  最后用一副图来表达简单的表达整个过程,也算本文的结尾。
(转载请保持文章的完整性,请注明作者和出处)

                               作者:冲天飞豹(youbest)
                               Email:youbest@sina.com
                               2006年6月21日

希望大家能多写一些分析性的文章,共同提高。





说明:上图的内容实际上并不是标准的LFS编译关系,按照LFS的做法,应该在预工具链编译完成工具链中的glibc、gcc和binutils,工具链后续的部分是由工具链的gcc和binutils来完成的,但本文并不追求和LFS完全一致,只是为了说明整个过程是如何反向推出来的,而且我认为按照图里的方法也完全没问题,完全不影响目标系统的“纯净”度。
图中实际上也表现了一种可以用来编译不同平台上的工具链的方法,因为在编译整个工具链的过程中都由预工具链来完成的(此方法我自己没实验过,只是一个设计)。


[color="Red"]更新日志:

2006年6月21日:
修改笔误一处
由linuxsir上的doom3d发现并报告

2006年6月21日:
在结尾的图片上加入gcc的bootstrap的标记。
由linuxsir上的doom3d建议

2006年6月21日:
对结尾的图片做出说明。

2006年8月12日:
修改有歧义的句子一处。
发表于 2006-6-21 15:19:28 | 显示全部楼层
天啊。。youbest的文章,简直就是 精华贴 的代名词啊。。。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-6-21 15:26:40 | 显示全部楼层
不要这样夸我嘛!:rolleyes:
回复 支持 反对

使用道具 举报

发表于 2006-6-21 15:42:33 | 显示全部楼层
赞,真不错........
回复 支持 反对

使用道具 举报

发表于 2006-6-21 17:58:07 | 显示全部楼层

好,真好

看了这样的好贴,不顶都不行呀!
回复 支持 反对

使用道具 举报

发表于 2006-6-21 18:32:45 | 显示全部楼层
好!收藏!:thank
回复 支持 反对

使用道具 举报

发表于 2006-6-21 19:34:03 | 显示全部楼层
Post by 终极幻想
天啊。。youbest的文章,简直就是 精华贴 的代名词啊。。。。。
真的没有比这个形容得更贴切了。。。:2cool

  好了,现在已经可以用工具链来完成目标系统的编译了,下面的问题就是这个工具链是如何来的呢?
  这个问题就要回到前面所提到的工具链运行时所依赖的环境,还是这个glibc,要编译这个glibc必须是在工具链的编译工具生成之前,而工具链的编译工具又依赖于glibc,那么这个glibc就不能是现在工具链中的编译工具编译出来的,那么是谁编译的呢?
  这个问题的答案:当然还是编译器编译的这个glibc和工具链里的编译工具,也就是说在工具链中的编译工具编译目标系统之前需要另一个编译器来编译这个在使用的工具链中的编译器和编译器所依赖的glibc。
这正是 LFS 手册提过的 "To compile a compiler, you need a compiler",哈哈

更正:
  现在的问题就集中到“预工具链”中的gcc和binutils上了,只要能编译出和工具链中的gcc与binutils相同版本就可以了,也就是说只要一套编译环境能[color="Red"]便宜gcc和binutils就可以了。
[color="Red"]便宜gcc和binutils 应该是 [color="Red"]编译gcc和binutils 吧

  但这里有一个问题就是:“主系统”中的gcc和binutils与“预工具”中要求的gcc和binutils版本不同(通常会老些),但只要能正确编译binutils、gcc就行了,gcc具备自我编译的功能,因此建议编译不同版本的gcc采用bootstrap的方式比较好。当然“主系统”中的在参与编译过程中的其它工具也需要符合要求就成。
  最后用一副图来表达简单的表达整个过程,也算本文的结尾。
提议在最後的那张图加入 Bootstrap 的行径,如附图

最後,图中提及过头文件,我们上次探讨过内核头文件要用"净化过"的版本来编译 glibc,不知道这里是否适合加入一点补充?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2006-6-21 19:36:51 | 显示全部楼层
弱问:youbest 你是怎样把图贴在文章之间的?这样排版比上传图片缩在後面好多了!
回复 支持 反对

使用道具 举报

发表于 2006-6-21 19:49:16 | 显示全部楼层
这样的文章真的不错,我之前也有过这样的考虑,还有些奇怪的想法,不过一直没整理过

应该是用插入图片的方式吧?应该不是上传的图片
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-6-21 20:50:59 | 显示全部楼层
Post by d00m3d

便宜gcc和binutils 应该是 编译gcc和binutils 吧


已经更正
Post by d00m3d

提议在最後的那张图加入 Bootstrap 的行径,如附图

已经加入,但我觉得你加的位置是不是错了?
Post by d00m3d

最後,图中提及过头文件,我们上次探讨过内核头文件要用"净化过"的版本来编译 glibc,不知道这里是否适合加入一点补充?
文章部分内容和LFS是有出入的,所以这个似乎不需要太强调,而且我觉得没"净化过"的头文件也没啥问题.
Post by d00m3d
弱问:youbest 你是怎样把图贴在文章之间的?这样排版比上传图片缩在後面好多了!
我有自己的blog,所以图片都在blog上,直接用[IMG]标签引用就可以了.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表