现在的位置: 首页 > 综合 > 正文

LFS6.1.1构建GNU-i686工具链笔记(why to)

2013年04月07日 ⁄ 综合 ⁄ 共 7389字 ⁄ 字号 评论关闭
1. 建议使用Firefox浏览本文档, 以达到最好的浏览效果.IE在浏览时易发生排版显示变形.

2. 文档发布的初衷是方便大家交流学习, 欢迎转载, 并请一并标注版权.
+-----------------------------------------------------------------------+

+-----------------------------------------------------------------------+

|                       第一部分 文档说明                                |
+-----------------------------------------------------------------------+
1 作用
##########
   Gnu tool chain in LFS-6.1.1
   构建工具链的具体步骤参见lfs_6.1.1.note.(How to).
   本文档说明相应的关键点(Why to).

2 版权
######
  版权: 聂大鹏(dozec)

3.2 作者
========
3.2.1 作者1
-----------
   姓名: 聂大鹏
   email: dozec@mail.csdn.net

4 产生时间
##########
  时间: 2007-2-9

5 版本
######
  版本: 0.1 版

6 修订过程
##########
6.1 第0.1版
===========

+-----------------------------------------------------------------------+
|                       第二部分 文档正文                                |
+-----------------------------------------------------------------------+
1 Gnu tool china说明
####################
1.1 实验环境
============
工作站: RHEL4
        Linux version 2.6.14.7
        gcc version 3.4.6 20060404 (Red Hat 3.4.6-3))
        CPU: Pentium 1.7G
        Memory: 256MB
        装LFS的分区: /dev/hdd1 (hdd是一块4.3G硬盘,只有1个分区)

1.2 笔记
========
  a).在LFS-6.1.1当中一共构建了2次Gnu tool chain.
     第1次是LFS-6.1.1第5章,构建了一个不依赖于宿主系统(就是我们工作站)的Gnu工具链.
             然后用这个工具链来编译生成最后目标LFS系统当中的软件包.这里涉及到2点注
             意,第一点是为什么要构建这个GNU工具链来编译目标LFS系统当中的软件包而非
             使用宿主系统当中的工具链,原因就在于我们最终构建目标LFS系统当中的软件包
             之前,会先chroot到$LFS(/就变成了/mnt/lfs), 这样宿主系统当中的工具链就无
             法使用了(例如:相应的头文件,库文件,gcc,g++,ar,as,ld等). 第二点就是我们
             构建的这个新的GNU工具链是用原有宿主系统当中的GNU工具链来编译生成的,有点
             鸡生蛋嘛,当这个蛋长大时(就是我们新工具链GCC第一遍完成时),再用破壳而出的
             鸡再生蛋.(编译第5章剩下的软件包,包括GCC第二遍以及第6章目标LFS系统的软件
             包,其中又包括目标LFS的GNU工具链).

      第2次是LFS-6.1.1第6章创建的目标LFS系统的Gnu tool chain.

  b).构建一个不依赖于宿主系统的GNU工具链最重要的有2点:
     一是Binutils中的ld: Gcc生成.o文件后, ld会将.o与库文件链接生成可执行文件.
                         重点就在于ld将会到哪些路径去搜索库文件.由于第5章中构建的
                         不依赖于宿主系统的GNU工具链是安装到/tools目录下,所以ld应该
                         到/tools/lib下去找我们新装的Glibc的库文件,而非到/lib下去找
                         宿主系统的库文件.
                         查看ld的库搜索路径的命令如下:
                         # ld --verbose | grep SEARCH
                         调整ld的库搜索路径需要在Binutils源码当中执行如下:
                         # make -C ld LIB_PATH=/tools/lib (库搜索路径为/tools/lib)

     二是Glibc中的动态库加载器: 动态库加载器实为一个动态库文件ld-linux.so.2.当程序加
                                载到内存运行时,ld-linux.so.2负责完成将程序所需使用的
                                动态库映射到进程的内存空间(使用pmap可以查看一个进程的
                                内存空间分布).ld-linux.so.2的默认搜索动态库路径为/lib
                                and /usr/lib, 可以通过修改/etc/ld.so.conf文件来增加搜
                                索路径.由于第5章中构建的不依赖于宿主系统的GNU工具链是
                                安装到/tools目录下,所以用这条新工具链编译出的程序使用
                                的应该为/tools/lib/ld-linux.so.2, 而非宿主系统/lib/ld
                                -linux.so.2.
                                查看一个程序使用的动态库加载器命令如下:
                                # readelf -l 用新工具链编译的可执行文件 | grep interpreter
                                指定编译董成的程序所使用的动态库加载器需要如下:
                                # 调整Gcc的specs文件.

  c).第1次构建的GNU工具链说明(LFS-6.1.1 第5章):
     这个时候是用宿主系统的GNU工具链来编译生成一个不依赖于宿主系统的工具链.
     c.1) 首先要说的就是编译这个GNU工具链使用的是lfs用户来完成的,其PATH环境变量如下:
          PATH=/tools/bin:/bin:/usr/bin
          /tools/bin优于宿主系统当中的/bin and /usr/bin, 这样当Binutils和Gcc的第1遍
          编译生成后, 再编译Glibc以及Binutils和Gcc的第2遍均是使用新的GCC.

     c.2) 先装Binutils到/tools目录下,因为Gcc和Glibc的configure要对as和ld进行测试.
          值得注意的是最后执行了如下2条命令:
          # make -C ld clean
          # make -C ld LIB_PATH=/tools/lib
          生成一个库搜索路径为/tools/lib的ld, 但现在不能安装这个ld,原因很简单--Glibc没装.
          当Glibc装完之后,调整工具链的时候就把这个ld安装上.

          注意: 此次是使用宿主系统的GCC编译生成的Binutils, 并且动态库加载器ld-linux.so.2
                使用的是宿主系统/lib下的.

     c.3) 再装GCC(pass 1)到/tools目录下,第1遍只装GCC的c编译器就成.(GCC == Gnu compiler collection).
          创建cc符号链接使其指向gcc.
          这个时候GCC的第1遍完成, 由于PATH当中的/tools/bin在前, 所以其后编译的软件均使用
          新gcc,而非宿主系统当中的gcc了.下面的任务就是要编译Glibc,但编译Glibc之前,要先把
          Linux-Libc-Headers头文件先装上.

          注意: 此次是使用宿主系统的GCC编译生成的我们的GCC,并且动态库加载器ld-linux.so.2
                使用的是宿主系统/lib下的.

     c.4) 使用新安装的GCC来编译Glibc到/tools目录下,以下2个参数需要注意一下:
          --with-binutils=/tools/bin     保证在编译Glibc时不会使用/tools/bin下的Binutils程序.
                                         也就是c.2当中提到的Binutils.
          --with-headers=/tools/include  前面的头文件是安装到/tools/include当中.现在就指定
                                         Glibc使用这里的头文件.

          注意: 使用第一遍生成的GCC编译生成Glibc.

     c.5) 调整工具链:
          -1: 因为Glibc已经安装完成, 所以要把在c.1当中已经编译生成的库搜索路径为/tools/lib的ld
              安装生成. 这样用新GCC编译生成的程序所使用的库均为我们刚刚安装的Glibc当中的库,而
              非宿主系统当中的/lib下的库.

          -2: 调整GCC的specs文件,使其编译生成的程序所使用的动态库加载器均为/tools/lib/ld-linux.so.2
              而非宿主系统当中的/lib/ld-linux.so.2.
          
          -3: 这个时候做一个合理性检查是非常有必要的,从而来确定我们上述2步工具链是否成功.

     c.6) 用第1遍生成的GCC再次编译GCC(pass 2)并安装到/tools目录下,目的有二:
          -1: 把c/c++编译器也一并编译.
          -2: 使用经过调整的第1遍生成的GCC来第2次编译GCC, 生成的第2遍GCC动态库加载器使用的是
              /tools/lib/ld-linux.so.2, 而非宿主系统的. 这样, GCC已经独立于宿主系统了.

          gcc-3.4.3-specs-2.patch这个补丁它有2个功能:
          -1: 省去了安装完GCC后还要再次调整specs文件,以指向我们的动态库加载器/tools/lib/ld-linux.so.2
              这个步骤.
          -2: 把宿主系统头文件路径/usr/include从GCC的头文件搜索路径当中删除.

     c.7) 用第2遍生成的GCC再次安装Binutils(pass 2),目的就二:
          -1: 使用经过调整的第1遍生成的GCC来再次编译Binutils, 生成的第2遍Binutils动态库加载器使用的是
              /tools/lib/ld-linux.so.2, 而非宿主系统的. 这样, Binutils已经独立于宿主系统了.
          -2: --with-lib-path=/tools/lib   指定库搜索路径为/tools/lib
                                           其实这步在c.5工具链调整中做过了, 在这指定是省去了
                                           安装完Binutils再另行调整的步骤.

  d). 第2次构建GNU工具链说明(LFS-6.1.1 构建目标LFS的GNU工具链)
      这个时候是用第1次构建的那个独立于宿主系统的GNU工具链来构建目标LFS的GNU工具链.
     d.1) 首先要说的就是编译这个GNU工具链使用的是root用户来完成的,并且chroot到$LFS
          也就是说: 现在的/已经是/mnt/lfs(目标LFS系统的根), 而非我们宿主系统中的根了.
          并且其PATH环境变量如下:
          PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin
          /tools/bin位于最后,产生的行为就是向目标LFS编译安装完软件包后,即刻就使用
          新的软件包,而非/tools/bin的.
         
     d.2) 在第1次构建GNU工具链是如下顺序:
          Binutils -> Gcc -> Glibc -> 调整工具链 -> Gcc(pass 2) -> Binutils(pass 2)
          而第2次构建目标LFS的GNU工具链是如下顺序:
          Glibc -> 调整工具链 -> Gcc -> Binutils

          显然第2次比第1次少了一次编译Gcc/Binutils环节,原因就在于调整工具链上.
          按照第1次构建GNU工具链, 它调整工具链调整的是独立于宿主系统的我们自己创建的工具链,
                                  而宿主系统工具链仍然正常.(这就是要先装一遍GCC/Binutils的目
                                  的). 这样就会出现2个完全独立的工具链:一个是宿主系统的, 一
                                  个是我们自己的.
          按照第2次构建的目标LFS的工具链, 它调整工具链实际上是直接把我们第1次创建的独立于
                                          宿主系统的工具链给调整了. 然后在此之上完成目标LFS
                                          工具链的. 这样也会出现2个工具链: 一个是目标LFS的工
                                          具链, 一个是第1次创建的工具链(其中Binutils的ld和
                                          GCC的specs文件中指向的ld-linux.so.2已经被调整为/lib了,
                                          而非原先的/tools), 这个工具链可以说已经以依赖于目标
                                          LFS系统了.如果要用该工具链再次构建目标LFS系统,需要重新
                                          调整工具链.
          实验如下:
          [root@hellokitty lfs]# chroot "$LFS" /usr/bin/env -i /
                                 HOME=/root TERM="$TERM" PS1='[/u@lfs /W]//$ ' /
                                 PATH=/tools/bin /tools/bin/bash --login
          [root@lfs /]$ echo 'main() {}' > dummy.c
          [root@lfs /]$ cc dummy.c
          [root@lfs /]$ readelf -l a.out | grep preter
                  [Requesting program interpreter: /lib/ld-linux.so.2]
                                                   这已经是/lib/ld-linux.so.2了

        
     d.3). 在构建目标LFS工具链当中:
           Glibc: 线程库装上了, 这在第1次构建工具链当中是没有做的.
                  另外Glibc的2个比较重要的配置文件一定要注意: /etc/nsswitch.conf
                                                              /etc/ld.so.conf

1.3 参考文档
============
  < LFS-6.1.1 >
  < lfs_6.1.1.note > http://blog.csdn.net/dozec/  自己写的关于LFS6.1.1的笔记
 

抱歉!评论已关闭.