LinuxSir.cn,穿越时空的Linuxsir!

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

未完成的pure lfs翻译

[复制链接]
发表于 2003-3-24 06:46:15 | 显示全部楼层 |阅读模式
标题:                如何创建一个“纯净的”LFS 系统
LFS 版本:        CVS
作者:            Ryan Oliver <Ryan.Oliver@pha.com.au>,
                Greg Schafer <gschafer@zip.com.au>

概要:
        目前 LFS 编译的方法比以前要完善多了,但是还有某种程度上的缺陷,没有把重点放在如何创建一个正确的工具链上。最近 Linux 内核维护者 Alan Cox 在内核邮件列表上对 LFS 提出了批评,强调了这一点。我们马上将展现一个新的策略,目标就是创建一个正确的工具链,进而一个“纯净的”LFS 系统。我们相信,对阅读 LFS BOOK 的人来说,如何创建一个正确的工具链是最应该知道的。其他的都是第二位的。

提示:

变动
=========

本文档的最新版本在:-

    http://linuxfromscratch.org/~greg/

如果上面连接不上,还有一个备份在:-

    http://www.zipworld.com.au/~gschafer/

  * 1.0   2003-03-21   最初版本

声明
==========

你自己承担使用本提示的风险。本文作者和 Linux From Scratch 项目组不承担使用本提示或相关文件造成的任何责任。下面的做法是经过了认真测试的,但如果由于意外事件而毁坏了你的系统,you get to keep both pieces.

介绍
============

总的来说,工具链由 binutils, gcc 和 glibc 组成。写本文的时候,最新的 LFS 版本是 4.0.这个版本中编译方法的问题可以归纳成以下几点:-

  * 太依赖于主(编译)系统。比如,静态工具的 autoconf 测试时,是在与最终系统可能大不相同的主系统中寻找。这个问题最常记载和表现在 gcc 错误的编译了一部份的 glibc( HAVE_GAS_HIDDEN 是解决这一特定错误的变通办法).

  * 从主系统里带入了太多代码。比如,所有静态工具都静态连接到主系统的 glibc.主系统的 glibc 质量不明,可能会有 bug 或其他的问题。

  * 对不兼容的 glibc 变化太敏感。比如,在 glibc-2.2.x 的系统里静态连接的工具,如果包含了对 getpwuid() 的调用,在 glibc-2.3.x系统里运行就会崩溃。

  * glibc 是在没有 glibc 的情况下编译的。比如,glibc 的 autoconf 测试在这种情况下会产生与有 glibc 时完全不同的结果,会造成不一致,需要 hack 和变通办法。

(注意:上面提到的一些问题在 CVS 版本的书中已经部份的处理了,但还不充分,留下了太多出错的可能。)

为了克服所有的问题,需要我们找到一个新的解决方案。本文将阐述的办法,它的本质可以归纳为:-

  * 创建一个完全“自给自足”的工具链,它不依赖于主系统。

这个办法和现在的 LFS 主要区别在:-

  * 在第五章里编译一个 glibc

  * 这个 glibc 用第五章的 gcc 和 binutils(而不是主系统的版本)来编译

  * 第五章的余下部份就连接到新的 glibc 并使用新的 binutils 和 gcc

  * 第五章的包安装在“/stage1”前缀下而不是 "$LFS/static"

这个办法的好处有:-

  * 我们可以动态的连接所有东西。在第五章中也无须编译静态二进制文件(当然如果你想,也是可以的),因为我们在 chroot 环境中仍然能使用第五章中创建的共享库文件。

  * 在第六章里编译共享二进制文件和库文件所需要的一切,都是连接到我们移植的 glibc 上。这就避免了 gblic 的移植问题,不管是现在还是将来。

  * 适合编译 LFS 的主系统应该更多了,因为对主系统的依赖少了。理论上来说,唯一的要求是主系统的编译器能从 bootstrap 阶段开始编译 gcc。

  * 目前 LFS 技术支持中的很大一部份问题都会消失。例如,“不能静态编译第五章的包”,“不能编译 texinfo”,“binutils 检测相关问题”。

这个方法如何工作的技术要点在于:-

  * 与跨平台编译的原则有些相似,靠把工具装到某个前缀下,并协同工作,这利用了一些 GNU 的“魔术”。

  * 仔细的控制 ld 的连接器脚本(尤其是 SEARCH_DIR 变量)

  * 编辑 gcc 的 "specs" 文件来告诉 gcc 为哪个动态连接器创建可执行程序

应该说明,有更简单的方法来得到一个“纯净的”LFS 系统。一个"粗鲁的"方法是编译第六章两次。例如,删除 /static 目录(既是物理上删除,同时也从‘PATH’中去掉它)然后使用第六章来重新编译它自身。这是 Linux Standards Base (是linux的一个统一技术标准)中在 LSB Sample Implementation[1]中所用方法的主要思想。对 LFS 来说,使用这个方法不可行,因为它既费力,与我们下面所揭示的工具链相比又没有什么教育意义。

过程
=========

工具链清洁性
---------------------
必须明白,我们在编译一个新的工具链时,可以采用不同级别的"anal retentiveness"(指心理上要求干净,有点像洁癖)。我们越有洁癖,工具链就越干净。因此,我们会更多次数地编译软件包,可能这并不是必需的,但你要记住,这里的目标是得到一个完全自给自足和非常干净的工具链,并用它们来干净地实行第六章中的目标系统。有些不是必需的步骤(就是没那么多洁癖的)将在本文中指出。换句话说,如果你没有洁癖,就可以走捷径。


如何测试
-------------
我们从一个 glibc-2.2.5/gcc-2.95.3 的主系统起步,以使所有的缺陷都早一些显示出来(因为它们的版本比较低)。工具链软件包使用的版本是 binutils-2.13.2, gcc-3.2.1 和 glibc-2.3.1. 主要的测试平台是 "i686-pc-linux-gnu".


从哪里得到补丁和脚本
------------------------------------
本文中使用的补丁可以从下面这里得到:-

  http://linuxfromscratch.org/~greg/patches/pure_lfs/

另外,我们还提供了一些脚本:-

  http://linuxfromscratch.org/~greg/scripts/pure_lfs/

请注意,现在脚本比文档要新一些,所以可能不完全符合文档。
 楼主| 发表于 2003-3-24 06:47:51 | 显示全部楼层
编译考虑
--------------------
本文中,我们有一些假设,你可能需要根据环境来决定。例如,在几个地方的编译命令中你会看到对"i686-pc-linux-gnu"的硬编码引用。如果你的平台不是 i686-pc-linux-gnu (如 "i586-pc-linux-gnu" 或 "powerpc-unknown-linux-gnu") 那就要作相应的改动。

我们还使用 "*" 通配符,如果你有几个版本的源码包放在一起,就要注意了。

核心工具链软件包都是在它们的 build 目录里编译的(glibc 是一个例外,它会在 manual 子目录里生成一些文件,不过我们会做相应调整以允许它这样做的)。因此可以多次使用同一个源码(而不用重新解压)。如果你这样做的话,就要注意取消对下一个阶段不合适的补丁。我们将在需要的地方提醒你。

在本文的最后部份,你能找到独立的一节,是讨论一个老生常谈的问题:到底用哪个发布的 binutils (FSF 还是 HJL).现在,只需要知道你可以有一个选择。

最后,NLS(本地语言支持) 在整个编译过程中都是打开的。只有两个地方我们使用了 "--disable-nls",是静态的 "pass 1" 编译 binutils 和 gcc 时。这是因为在某些情况下,"--enable-nls"与静态编译相结合会造成符号冲突的编译错误。请注意你完全可以在余下的所有编译中使用"--disable-nls",如果你不需要 NLS 和/或你想节省硬盘空间。


运行测试套件 - 简述
------------------------------------------
多数软件包都提供了测试套件。运行测试套件是个好主意,因为它提供了很好的"sanity check"(检查环境的合理性)并证实了新编译的软件包大致具备开发者预想的功能。但它并不保证软件包没有 bug,因为这基本上是不可能的。

gcc 和 binutils 的测试套件依赖于三个额外的软件包:tcl, expect 和 dejagnu. 如果你想在最开始的阶段运行测试套件,你必须保证主系统里安装了这三个包。本文假设主系统没有安装它们,因此在静态"pass 1"的 binutils 和 gcc 时不运行测试套件。"pass 1" 编译很快就会被"pass 2"编译所覆盖,所以我们认为省掉"pass 1"的测试不是什么大问题。

警告,gcc 和 glibc 的测试套件要花很长的时间,如果你编译时间很紧张,就省掉第五章的测试套件,但我们并不推荐这样做。如果你选择了这个捷径,至少不要省掉第六章里 glibc, binutils 和 gcc 的测试套件。但记住,如果你在第六章里发现了本应是第五章里测试套件就能找出的问题,那你肯定会后悔当时的选择。



第五章 - 创建 /stage1 目录
------------------------------------------

我们假设你已经到了 LFS book的第五章,也就是已经创建了分区和文件系统,加载了分区,创建了$LFS/static,添加了 lfs 用户并设置了相应的环境。

正如简介中所述,我们将使用"/stage1"而不是"/static",因为我们将编译动态(共享)的第五章。这个名字只是为了与 /static 相区分以避免混淆。请重新回到 LFS book 中"Creating the $LFS/static directory"(创建$LFS/static目录)那一章,但是要用下面的命令:-

    mkdir $LFS/stage1

同时,也别忘了执行 chown 操作:-

    chown lfs $LFS/stage1

下一步是在主系统里创建 "/stage1" 符号链接。它将指向我们刚刚在 LFS 分区上创建的目录:-

    ln -s $LFS/stage1 /

这保证了我们的工具链在第五章和第六章(chroot环境中)里将在相同的位置(如/stage1)查找。这是一个很重要的概念,如果现在还不太明白,没关系,只要进了第六章,就什么都清楚了。

第五章 - 设置环境
--------------------------------------

对环境的设置,也要加以调整。首先,我们不使用:-    export CC="gcc -s".我们这里试图正确的做事情,严格说来,"-s" 是一个连接器标志。所以我们将把"-s"放在 LDFLAGS 中,如下:-

    export LDFLAGS="-s"

第二,我们需要把"/stage1/bin"添加到 lfs 用户的 `PATH'里:-

    export PATH=/stage1/binPATH

由于我们一步步地把第五章软件包安装到"/stage1",我们新编译的工具在`PATH'中排在前面,所以就会结合到下面的编译过程里。

第三,如果使用 bash shell,关掉bash的 "hash"功能是个好主意:-

    set +h

Bash 有一个很有用的特性,它使用 hash 表(哈希表)来记住可执行文件的完整路径,以避免多次的 `PATH' 搜索。然而,我们希望立刻就能使用新安装的工具。关掉hash功能,那些交互的命令(make, patch, sed, cp 等等)将总是使用新的程序。
configure 脚本中的 Shell 文件名扩展并不会受 hash 功能的影响,所以这一步不是必需的。
关掉 hash 功能对性能的影响基本可以忽略。为了确认它已经关上了,运行:-    hash    。应该会显示类似这样的结果:"su: hash: hashing disabled".如果你在使用其他的 shell,看一下它的文档,是否也有这个 hash 功能。

注意,我们将把上面的命令加到"/home/lfs/.bash_profile"中,以使每次用 "su"来切换到 lfs 用户时,都能恢复设置。因此"设置环境"的命令是:-

    cat > ~/.bash_profile << "EOF"
    set +h
    umask 022
    LFS=/mnt/lfs
    LC_ALL=POSIX
    LDFLAGS="-s"
    PATH=/stage1/binPATH
    export LFS LC_ALL LDFLAGS PATH
    EOF
    source ~/.bash_profile

在整个编译过程中,你将注意到,我们会小心的调整 CFLAGS 环境变量. 这不是优化!而是把"-g"标志去掉以节省空间。我们还引入了"-pipe"以得到稍微快一点的程序。我们没有把 CFLAGS 放在 lfs 用户的全局环境中,因为并不是每个包都那么合作的对待CFLAGS.

另一件要注意的事情是,少数几个地方我们在 make 命令中使用了 LDFLAGS="-s"尽管我们已经在环境中设置了它。这是因为这几个包不把环境中的 LDFLAGS 放到顶级的 Makefile 中,因此也就不会把它传递给下面的子make进程。


第五章 - 安装 binutils - Pass 1 (静态)
-------------------------------------------------

这一步和现在的第五章 binutils 安装很相似,不过有一个额外的技巧。

    mkdir ../binutils-build &&
    cd ../binutils-build &&
    CFLAGS="-O2 -pipe" ../binutils-2*/configure --prefix=/stage1 \
       --disable-nls &&
    make LDFLAGS="-all-static -s" &&
    make install

注意 - 如果你碰巧使用的是 HJL binutils 发布 2.13.90.0.18 或更高版本,遇到了"C compiler cannot create executables"编译错误,你需要在 configure 和 make 命令中间插入"make configure-host"命令。这是因为顶级编译系统最近的变化不能处理LDFLAGS中的"-all-static".

重要! - 不要删除 binutils-build 目录,因为我们后面会再用它。以后会解释这样做的原因,不过现在只需要运行:-

    cd ld &&
    make clean &&
    make LIB_PATH=/stage1/lib

现在不要运行 "make install"!我们留下以后用。到时候就什么都清楚了。

主要的区别是我们使用 /stage1 作为安装前缀而不是通常的 $LFS/static.注意没有$LFS.这里值得提到的是,让 binutils 一开始就能使用是很重要的,因为 glibc 和 gcc 都要执行多种针对连接器和汇编器的测试,以决定该打开什么特性。


第五章 - 安装 gcc - Pass 1 (静态)
--------------------------------------------

基本与目前的第五章 gcc 安装相同,不过也有一些变化。首先,我们需要运用"no_fixincludes"补丁来防止fixincludes脚本的运行。我们用一个补丁而不是使用"install-no-fixedincludes",因为这样更干净,并能使编译稍微快一点,如果你碰巧使用了"--enable-version-specific-runtime-libs"配置开关,也不会出错。我们还要使用 "mmap_test" 补丁,它修正了gcc的一个小bug[2],能(并且会)在某些情况下破坏 gcc 编译的完整性。

    patch -Np1 -i ../gcc-3*.no_fixincludes.patch &&
    patch -Np1 -i ../gcc-3*.mmap_test.patch &&
    mkdir ../gcc-build &&
    cd ../gcc-build &&
    CFLAGS="-O2 -pipe" ../gcc-3*/configure --prefix=/stage1 \
       --with-local-prefix=/stage1 --enable-languages=c \
       --disable-nls --enable-shared &&
    make BOOT_LDFLAGS="-static -s" BOOT_CFLAGS="-O2 -pipe" \
       STAGE1_CFLAGS="-pipe" bootstrap &&
    make install &&
    ln -s gcc /stage1/bin/cc
 楼主| 发表于 2003-3-24 07:01:03 | 显示全部楼层
后面的不打算翻译了,因为我开始编译以后,发现脚本和文档差得很多,还是应该以最新的脚本为主。文档的参考价值,可能只是在出问题的时候才有用。有很多包的编译方法都变了,所以还是等文档更新了以后再说。
下面写一下我的编译过程:
首先是按照LFS BOOK上那样来分区,加载。
然后是找文件和补丁,所找文件的版本按照那个编译脚本里的版本来找。补丁可以参考现在的 LFS BOOK CVS和上面链接里的地址。
再把文件和补丁给放到$LFS/usr下。$LFS/usr下分别有这么几个目录:src(放解压的代码和编译目录)、tarballs(放源码的压缩包)、scripts(放解压后的编译脚本)、patches(放解压后的补丁)。
接下来就是改脚本,主要改的是LFS的位置。改好了脚本,运行$LFS/usr/scripts/build-ch5xxxx.sh,我感觉他的意思是用root来运行,因为里面有一些root的操作,ln这些,不过为了安全起见,我还是用lfs用户来运行,把$LFS分配给lfs用户。运行脚本后,报了几个错误,一个是补丁名字不对,要把gcc的mmap补丁改成gcc-3.2.2-mmap_test.patch,也就是中间用“-”来连接。如果不改,它报的错很离谱,说是找不到zlib的补丁,还害得我找了半天。
现在刚编译过了第五章binutils的pass1。
发表于 2003-3-24 07:22:44 | 显示全部楼层
不要太辛苦了,又一晚上没睡觉吧。

我也看了那个文档,觉得有些的地方必须要实践过了才好翻译,比如对local的设置。还是等他们出来新的lfs文档再翻译吧。
 楼主| 发表于 2003-3-24 10:31:48 | 显示全部楼层
是啊,有的地方问题还不少。我刚才就出错了,还是应该用root来编译。
发表于 2003-3-31 21:52:40 | 显示全部楼层
up
发表于 2003-3-31 22:37:54 | 显示全部楼层
pure lfs 的脚本,如果没有用root来进行的话,到半中间就会出错。
即使是用root来执行,好像在编译第6章的GCC的时候也会出错,所以最好,还是看着说明,对照着脚本手工来进行,比较好,对于学习也比较好呀。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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