LinuxSir.cn,穿越时空的Linuxsir!

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

[总算明白了] 解析 LFS 的 toolchain 技巧。

[复制链接]
发表于 2006-2-17 10:33:32 | 显示全部楼层 |阅读模式
[color="Red"]BOOK Version: LFS-SVN 20060210

主要是帮助读者理解LFS的编译原理。诸如 为什么要分开两大章编译,调整toolchain的真正意义是什么 之类的问题,本文尝试给出解释。

抛砖引玉,欢迎评论。

[html]
文中术语:
库文件:library file:*.so 文件
动态连接库:Dynamic Linker:一般是指 ld-linux.so.2 这个文件。
[/html]
==========================================================================
5.3. Binutils-2.16.1 - Pass 1
一开始先安装基础的binutils包。里边包括了ar/nm/ld等最底层的编译工具。
具体作用是把编译的文件组合成系统可执行的文件。

make -C ld 的那一段:
重新编译 ld 这个程序,但是改变 LIB_PATH 这个参数。具体作用就是 这样产生的新的 ld-new 是利用 /tools/lib 里边的库来进行组合程序,而不是使用默认的 /lib:/usr/lib:/usr/local/lib 里边的库。/tools 是我们的临时系统存放点,这样做是要保证在第一次调整工具链后,不把原系统的那些库混杂进来,污染我们的临时系统。

我的推测:(我后来测试了,证实这个设想是正确的。)
LIB_PATH 可以通过 --with-lib-path 来指定。也就是说如果你喜欢,可以编译2次 binutils,在第二次编译的时候把 --with-lib-path=/tools/lib 传入 configure。编译后,保留 ld/ld-new 这个文件。
(指定 --with-lib-path 这个方法其实也是 5.12. Binutils-2.16.1 - Pass 2中用的方法。)
注意,我这里说的第二次不是  5.12. Binutils-2.16.1 - Pass 2,是这个 Pass 1 编译两次 binutils。

我测试了一下,2个文件 (ld-new) 虽然不一致,但是通过 strings ld-new 的结果却是一样的。而且 ldscripts 目录里边文件的内容全部一致。
(基本上来说,2个 ld-new 文件就是一样的了,从后边的讨论可以基本证实这点,谁能提出不同看法的话,非常欢迎!这样我会继续深究。)

最后补充两句:ld.so.conf 用来控制搜索范围。这个文件是在安装glibc的时候建立的。
我的新系统就是采用编译了2次binutils的方式,还没发现任何问题。

==========================================================================
5.7. Adjusting the Toolchain
到现在我们已经把 toolchain 做出来了。Linux-Libc-Headers 是给 glibc用的。接下来就是把所有的库连接都指向这个临时 toolchain,这样就不会受到 原系统 的影响了。
Binutils-2.16.1 - Pass 1
GCC-4.0.2 - Pass 1
Linux-Libc-Headers-2.6.12.0
Glibc-2.3.6

一改以前的作风,LFS现在只拷贝 ld 这一个文件,而不是以前的 make -C ld install 方式。这个也就是说其他都不用变,只有这个文件受到了改变,
这个让我感觉之前的我的推测应该是可以成立的,也就是第二次编译生成的 ld-new 可以用来代替第一次的那个。要的就是 LIB_PATH 这个参数的改变。

在用我说的第二次编译得到的 ld-new 覆盖了原来的 ld 文件后,效果是:From this point onwards, everything will link only against the libraries in /tools/lib。
说的具体清楚一点,就是编译过程中,所有的这些 -ldes -lXXX 这些都是从 /tools/lib 里边寻找,而不是在 /lib:/usr/lib:/usr/local/lib 里边找。

接下来的是 gcc 的动态工具链调节。
首先是 specs 文件的位置。因为 gcc 4.X 中,specs是默认不存在的。读取的是内部的specs文件(可用 gcc -dumpspecs 查看)。要创建该文件
才会使gcc去读取。至于是什么文件,你可以通过BOOK上的语句查看。实际上还有其他地方可以放置 specs 文件的。这个可以通过 strace gcc 来确定,也可以查看 cc dummy.c -Wl,--verbose &> dummy.log 的输出结果。
修改 specs 的具体作用是:让编译器用 /tools/lib/ld-linux.so.2 这个动态连接库(而不是/lib/ld-linux.so.2)来寻找相应的库文件,
配合 ld 这个命令,可以限定搜索范围了。

最后,清除那些错旧的header文件。效果就是 从host系统拷贝过来的header 统统不要。

修改完后,做一下测试。确保操作正确。

==========================================================================
5.11. GCC-4.0.2 - Pass 2

因为gcc的fixincludes问题,一开始就去掉。fixincludes 就是刚刚提到的那些 错旧headers 的生成脚本。

接着是调整优化参数  -fomit-frame-pointer。

打 gcc-4.0.2-specs-1.patch 补丁。这个补丁很重要,作用是把所有的体系的linker位置调整为/tools/lib下的新的linker。linker就是动态连结库。默认的 gcc 是去 /lib 寻找 linker 的。

==========================================================================
5.12. Binutils-2.16.1 - Pass 2

传入 --with-lib-path-,重新编译一次binutils。这次是其他的那些bfd什么的也跟着一起,不单单只有 ld 一个了。

在最后,旧计重施。重新编译一次 ld, 并且保存为 ld-new。二次编译的 ld 和原来不同的就是 新的会去/lib:/usr/lib去查找库文件 而不是 /tools/lib。
编译这次 binutils 的目的,主要是为第六章做工具链修改做准备。

稍微深入一下话题:
如果传入的 --with-lib-path 或者 LIB_PATH 值不一样的话,那么ld这个文件也会不一样。而且很不一样。最明显的就是文件包括的路径不一样。如下是diff出来的结果。
相信你们也能看出不同了:)。
diff <(strings b1/build/ld/ld-new) <(strings b2/build/ld/ld-new)
2088c2087
< SEARCH_DIR("/tools/i686-pc-linux-gnu/lib"); SEARCH_DIR("/ll");
---
> SEARCH_DIR("/tools/i686-pc-linux-gnu/lib"); SEARCH_DIR("/tools/lib");

==========================================================================
一直到后边都没什么好说的了,机械的编译所有需要的包。注意到的一点就是第五章的包能不打补丁的都不打,这些都在第六章进行的。

==========================================================================
6.12. Glibc-2.3.6
没什么好说的,这里是把主系统的glibc装上。glibc 是 self-contained的,就是说不会受到外界的影响。具体的表现是 只要规定了 --prefix,那么 glibc 就会装入这个目录,也因为glibc 是最基础的库,不需要任何依赖库,所以也就不受任何其他因素的影响。能成功安装就可以了!
临时系统里边已经有“干净”的 binutils/gcc/glibc 组合了,装glibc很容易。调整了 toolchain 后,马上就安装 binutils/gcc。

==========================================================================
6.13. Re-adjusting the Toolchain

重新调整工具链。把 5.12 中保留下来的那个 ld 暂时放上来,因为这个时候还没有安装新的 binutils。但是在马上要安装的 binutils中,就需要把库 link 到/lib下的glibc,而不是
/tools/ 中的glibc。这个是鸡蛋和鸡的问题。所以这里暂时用一下原来编译好的 ld 来顶替。接着马上就编译 binutils 来重新覆盖。

调整 gcc 的 linker 的话,和一开始的原理一样,就不复述了。不过这里多了一个东西,就是 startfile_prefix_spec。主要是为了让gcc能正确的找到相应的文件。这些文件是 crt1.o crti.o crtn.o 这3个文件。

为了保证操作正确,后边马上给出一系列的测试。

==========================================================================
6.14. Binutils-2.16.1

这里没什么特殊的,就是最后 make tooldir=/usr install 这里说一下。
ar as ld nm objdump ranlib  strip 这几个是binutils提供的工具,主要是用来拼组文件用的。当然,不同的体系有不同的组合。体系一般用triplet来表示。如 i686-pc-linux-gnu。
binutils 的 tooldir 的安装位置应该是 /usr/[triplet]/bin 和 /usr/[triplet]/lib下。但是为了简便,LFS就把他直接安装到 /usr/bin 和 /usr/lib 下边,也就是说默认用的就是用当前体系编译。
这样做的后果是不能提供跨体系编译。不过一般来说也不需要。/usr/bin 提供的就是native toolchain的体系。/usr/[triplet]提供一般是用来跨体系编译的。
(几句话说的也不清楚,如果要搞明白的话,请 google 搜索更多的资料。我安装的时候是忽略 tooldir=/usr 这个参数的。)

==========================================================================
6.15. GCC-4.0.2
开始的几个sed,是为了调整一些设置。第一个是去掉libiberty的安装,因为binutils已经装了。fixincludes 和上边原因一样。至于其他的,似乎没什么好说的。基本上
系统已经开始成形了,剩下的就是那些软件的安装了。

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

转载请保持完整。

by 终极幻想@LinuxSir.org
发表于 2006-2-17 11:01:32 | 显示全部楼层
正在仔细看,我觉得5.3. Binutils-2.16.1 - Pass 1这里讲的不太清楚,也可能是理解的问题,我补充一下make -C这段是为了给5.7. Adjusting the Toolchain这章做铺垫,也就是在5.7. Adjusting the Toolchain这节之前使用的ld指向的依然是/lib:/usr/lib,直到5.7节的make -C ld install执行后才变成/tools/lib。

LFS最精华的就是建立工具链和调整工具链的过程,LFS精华中的精华。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-17 11:09:07 | 显示全部楼层
谢谢提出意见。:)。

兄弟请看看最新的版本,这个做法已经改了,不用 make -C ld install 了。用的是复制文件的方法(就是我描述的方法)。:)。

文中各方面的细节我还会补充详细。尤其是一些重要的小动作。^_^。


PS:发现我的中文表达能力非常不好,总是不知道该如何表达一些东西。郁闷ing。
回复 支持 反对

使用道具 举报

发表于 2006-2-17 11:21:16 | 显示全部楼层
Post by 终极幻想
谢谢提出意见。:)。

兄弟请看看最新的版本,这个做法已经改了,不用 make -C ld install 了。用的是复制文件的方法(就是我描述的方法)。:)。

文中各方面的细节我还会补充详细。尤其是一些重要的小动作。^_^。


不好意思啊,许久没看LFS-book了,因为要写的文章还没完稿,等过几天要学习一下了。

Post by 终极幻想
PS:发现我的中文表达能力非常不好,总是不知道该如何表达一些东西。郁闷ing。


我也有这个苦恼呀!以前作文成绩一直就不太好。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-17 11:44:58 | 显示全部楼层
Post by youbest
不好意思啊,许久没看LFS-book了,因为要写的文章还没完稿,等过几天要学习一下了。

我也有这个苦恼呀!以前作文成绩一直就不太好。


兄弟加油。期待有新的文章。哈哈。。。。

我打算把本系统的 glibc 升级到 snapshot-20060213 版本 ,希望成功。
之后再看看CLFS,尽量写一些心得。(如果能看出什么心得的话。)


看来弄计算机的人,文科都不好。哈哈。。。。
回复 支持 反对

使用道具 举报

发表于 2006-2-18 20:00:20 | 显示全部楼层

请问无法识别选项-mtune=prntiumpro是怎么回事?

我编译的gcc版本是3.4.4,在我编译完glibc后调整工具链时,报错无法识别选项-mtune=prntiumpro请问是怎么回事?
另外,请问3.4.4版本的gcc的specs文件是放在什么地方的?
谢谢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-18 20:25:28 | 显示全部楼层
这个,host的gcc版本是什么?之前的就识别?-mtune是一个比较老的参数,用-march试试。
3.4.4的specs,你用 gcc -print-file specs看看是否能打印出来?
应该是 /usr/lib/gcc/i686-pc-linux-gnu/3.4.4/specs 这个文件,不过也许不存在的。
回复 支持 反对

使用道具 举报

发表于 2006-2-18 21:17:19 | 显示全部楼层
host的gcc版本是4.0的,我的电脑上运行gcc --print-file specs,显示的是/mnt/lfs/tools/bin/../lib/gcc/i686-pc-linux-gnu/3.4.3/specs。于是我去手动的更改整个文件,但是不起作用。用gcc -dumpspecs查看的结果,动态连接器的路径仍然是/lib/ld-linux.so.2,而不是/tools/lib/ld-linux.so.2。请问这怎么解决呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-18 22:06:53 | 显示全部楼层
你的 toolchain 有问题,不应该是 /mnt/lfs 开头的,应该是 /tools 开头的。

你的 LFS book 版本是?
回复 支持 反对

使用道具 举报

发表于 2006-2-18 22:28:44 | 显示全部楼层
我的lfs版本是6.1.1,执行which gcc的结果是/tools/bin/gcc。我的一切步骤都是按照书上来的,除了内核头文件是直接取自host系统,但是这点好像对于这里的问题没有影响。大侠帮忙想想吧,这是怎么回事,郁闷惨了。
回复 支持 反对

使用道具 举报

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

本版积分规则

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