09.构建LFS系统──安装系统基础软件(一)
时间:2006-11-17 来源:anima
九、构建LFS系统──安装系统基础软件(一)
1.简介
在这一章,我们进入"建筑工地",开始精心构建 LFS 系统。也就是指我们通过 chroot 命令进入一个临时的微型 Linux 系统,并作一些最后的准备,然后开始安装软件包。
软 件的安装非常直截了当。尽管许多情况下对安装过程的说明可以更加简洁,但为了消除可能出现的错误,我们为每一个包都提供了全面的安装说明。理解 Linux 系统是如何工作的关键在于明白每个包的用途以及为什么用户(或系统)需要它。对每一个安装的软件包,我们都给出了对其内容的简要说明,另外,对该软件包所 安装的每一个程序文件和库文件也作了简要的描述。
如果在本章中进行编译器优化,那么请看看编译器优化提示:http://www.linuxfromscratch.org/hints/downloads/files/optimization.txt,也可以看看 LinuxSir 上的一篇帖子:GCC 编译选项及优化提示。编译器优化可以使程序运行的稍快一些,但也会出现某些编译问题。如果某个包在使用优化的情况下无法通过编译,试试不用优化编译能不能解决问题。即使使用优化编译成功,由于源码与编译工具之间复杂的相互作用,程序仍有可能被错误的编译了。要注意 -march 和 -mtune 选项或许会导致一些工具链软件包(Binutils, GCC, Glibc)的问题。使用编译器优化得到的小幅度性能提升,与它带来的风险相比微不足道。所以初次编译 LFS 的用户最好不要使用任何优化,你的系统依然会又快又稳定。
本 章中软件包的安装顺序应当严格遵守,以确保没有一个程序会把 /tools 作为路径硬连接到代码中。同样不要并行编译包。并行编译可能会节省时间(特别是在双CPU的机器上),但也可能造成程序包含 /tools 硬连接路径,以致在 /tools 目录被删除之后,程序无法运行。
在每个软件包安装说明页的首部都提供了与该包相关的一些信息,包括:包内容的简要说明、编译大约所需时间、编译过程所需磁盘空间、编译所依赖的软件包。在安装说明之后还有该包所安装的程序和库的列表以及对它们的简要说明。
2.挂载虚拟内核文件系统
虚拟内核文件系统(Virtual Kernel File Systems),是指那些是由内核产生但并不存在于硬盘上(存 在于内存中)的文件系统,他们被用来与内核进行通信。
首先让我们为虚拟内核文件系统建立挂载目录:
[root@fish lfs-packages-6.2]# cd
[root@fish ~]# mkdir -pv $LFS/{dev,proc,sys}
mkdir: 已创建目录 ‘/mnt/lfs/dev’
mkdir: 已创建目录 ‘/mnt/lfs/proc’
mkdir: 已创建目录 ‘/mnt/lfs/sys’
[root@fish ~]#
2.1.创建初始设备节点
内核在引导时要求某些设备节点必须存在(特别是 console 和 null ),这些设备节点必须创建在硬盘 上才能使得内核在 udev 尚未启动之前就可以使用它们,此外还有当Linux以init=/bin/bash 启动。使用下面的命令来创建这些节点:
[root@fish ~]# mknod -m 600 $LFS/dev/console c 5 1
[root@fish ~]# mknod -m 666 $LFS/dev/null c 1 3
[root@fish ~]#
2.2.挂载并填充 /dev 目录
推荐的向 /dev 目录填充设备的方法是在 /dev 上挂载一个虚拟文件系统(比如 tmpfs),然后在设备 被检测到或被访问到的时候(通常是在系统引导的过程中)动态创建设备节点。既然现在新的系统尚未被引导, 那么就有必要通过手工挂载和填充 /dev 目录。这可以通过绑定挂载宿主系统的 /dev 目录。绑定挂载是一种 特殊的挂载方式,允许你创建一个目录或者是挂载点的镜像到其他的地方。可以使用下面的命令:
[root@fish ~]# mount --bind /dev $LFS/dev
2.3.挂载虚拟内核文件系统
现在挂载虚拟内核文件系统:
[root@fish ~]# mount -vt devpts devpts $LFS/dev/pts
devpts on /mnt/lfs/dev/pts type devpts (rw)
[root@fish ~]# mount -vt tmpfs shm $LFS/dev/shm
shm on /mnt/lfs/dev/shm type tmpfs (rw)
[root@fish ~]# mount -vt proc proc $LFS/proc
proc on /mnt/lfs/proc type proc (rw)
[root@fish ~]# mount -vt sysfs sysfs $LFS/sys
sysfs on /mnt/lfs/sys type sysfs (rw)
[root@fish ~]#
3.包管理
对于 LFS BOOK,包管理通常被请求加进去。一个包管理器允许跟踪文件的安装,使删除或升级软件包变得简单。在这一部分里,我们不会讨论或者是推荐任何一个包管理器。我们讲述的是一些流行的技术,以及他 们是怎么工作的。对于你来说,一个完美的包管理器可能在这些技术之中,也可能是一些技术的结合。这一部分 简明的描述了当升级软件包的时候会出现的几个问题。
LFS 和 BLFS 中没有涉及包管理器的几个原因有:
-
把精力拿来做包管理器,就偏离了我们的LFS的初衷:一个Linux系统是如何构建的。
-
包管理有很多解决方案,每一个都有优点和缺点。任何一个都不会令其他种类的fans满意的。
有一些hints是关于包管理。可以查看 Hints subproject 来选择一个适合你的。
3.1.升级问题
一个包管理器会使升级一个软件包到新的版本变得很简单。通常 LFS 和 BLFS 手册中的说明可以用来升级软件包。 这里有几点,你在升级软件包的时候应该注意的,尤其是在一个运行着的系统上。
-
如果工具链中的一个软件包 (Glibc, GCC 或 Binutils)需要升级到一个新的次版本,重新构建LFS是比较安全的。 尽管你可以按照依赖关系,只是重新构建一部分的软件包。但我们并不推荐这样做。例如,如果 glibc-2.2.x 需要 升 级到 glibc-2.3.x,重新构建是比较安全的。对于小版本的升级,简单的重新安装通常可以正常的工作,但是不能够保证。 例如,从 glibc-2.3.4 升级到 glibc-2.3.5 通常不会有问题。
-
如果包含一个共享库的软件包升级,并且共享库的名字发生了变化。动态链接到这个库的所有的 包都需要重新编译链接到新的库(注意包的版本和库的名字没有关系)。例如,一个软件包 foo-1.2.3 安装了一个名为 libfoo.so.1 的共享库。你升级这个包到新版本 foo-1.2.4,这个新版本安装名为 libfoo.so.2 的共享库。这种情况下,所有链接到 libfoo.so.1 的包都需要重新编译链接到 libfoo.so.2。注意在依赖的软件包没有编译完之前,不要删除原来的库。
3.2.包管理技术
下面是一些常用的包管理的技术。在决定安装包管理器之前,对多种包管理技术进行一下研究,找出某一种的缺点。
3.2.1.全部记在心里
是的,这是一种包管理的技术。一些人不需要包管理器,因为他们对包都非常熟悉,知道每一个包所安装的文件。 一些人也不需要包管理器,是因为当一个软件包改变时,他们重新构建整个系统。
3.2.2.分别安装到不同的目录
这是一种最简单的包管理方式,不需要安装额外的软件包来管理安装过程。每一个软件包安装到不同的目录下。 例如,包 foo-1.1 安装到 /usr/pkg/foo-1.1 ,创建一个从 /usr/pkg/foo 指向 /usr/pkg/foo-1.1 的符号链接。当安装一个新版本 foo-1.2 时,它会安装在 /usr/pkg/foo-1.2 ,前面的符号链接也指向新版本。
一些环境变量,像 PATH, LD_LIBRARY_PATH, MANPATH, INFOPATH 和 CPPFLAGS 都需要增加 /usr/pkg/foo。当软件包数量大了之后,就难于管理了。
3.2.3.符号连接风格的包管理
这是前面包管理技术的一个变种。每一个包也是按照类似于前面方法进行安装。但是不是创建符号链接, 而是每一个都被链接到 /usr 目录。这样就不需要添加环境变量了。尽 管有时在安装的时候符号链接自动创建,还是有很多的是采用这种方法的。一些比较流行的有: Stow,Epkg,Graft,和 Depot。
安装过程需要伪造,这样包就会认为自己被安装到了 /usr 目录,尽管实际上 它们安装到 /usr/pkg 目录下。以这种风格安装并不是很麻烦的事情。比如,你要 安装一个包 libfoo-1.1 。用下面的指令安装就不合适:
./configure --prefix=/usr/pkg/libfoo/1.1
make
make install
安装是没有问题,但是依赖的包不能够像你想像的那样链接到 libfoo。如果你编译一个链接到 libfoo 的包, 你就要注意,要链接到 /usr/pkg/libfoo/1.1/lib/libfoo.so.1 ,而不是 像你想像的那样链接到 /usr/lib/libfoo.so.1。正确的方法是使用 DESTDIR 来伪造包的安装。可以这样来使用这种方法:
./configure --prefix=/usr
make
make DESTDIR=/usr/pkg/libfoo/1.1 install
大多数的包都支持这种方法,但还是有一些不支持。对于这些不兼容的包,你可以手工安装,或许把一些有问题的包 安装到 /opt 可能更简单。
3.2.4.基于时间戳
这种技术里,在安装包之前,会创建一个时间戳标记文件。安装之后,简单的使用的 find 命令的某些选项就能生成一个时间戳标记文件创建之后安装的文件的日志。install-log 就是利用这种技术写的包管理器。
尽管这种方法简单,但是它有两个缺点。如果在安装的过程中,安装的文件的时间戳不是当前的时间,这些文件将不会被包管理器记录。 另外,这种方案只能用在一次只有一个包安装时。如果有两个包在两个终端下同时安装,那么这时的日志是不可靠的。
3.2.5.基于LD_PRELOAD
这种方法下,在安装之前会有一个库被提前加载。在安装的过程中,这个库就会跟踪正在安装的包,通过给自己附加上 各种可执行性的动作,像 cp, install, mv 。来跟踪那些修改文件系统系统调用。为了让这种方法正 常的工作,所有的可执行文件需要都是动态链接的且没有设置 suid 和 sgid 位。预先加载库可能会产生一些讨厌的 副作用。因此,建议做一些测试,来确保包管理器不会破坏任何东西,并且能够记录所有适当的文件。
3.2.6.创建包的归档
在这种方案中,包被分别安装到不同的目录树下,就像符号连接风格的包管理描述的。安装之后, 系统就会使用安装的文件创建一个包的归档。这个档案可以在本机上安装包,甚至可以在其他机器上 安装包。
这种方法被大多数商业发行版的包管理器采用。例如,RPM(自然是Linux Standard Base Specification所必需),pkg-utils,Debian 的 apt 和 Gentoo 的 Portage 系统。 有一个描述在 LFS 系统中如何应用这样的包管理器的hint,参见 http://www.linuxfromscratch.org/hints/downloads/files/fakeroot.txt.
3.2.7.基于用户的管理
这种方案是 LFS 特有的,是由 Matthias Benkmann 提出的,可以参考 Hints Project。在这种方案里,每一个包都是以不同的用户安装到标准的目录里。通过检验 user ID 可以很容易的标识一个软件包。这种方法的特点和缺点非常复杂,这里就不描述了。详细内容参见 http://www.linuxfromscratch.org/hints/downloads/files/more_control_and_pkg_man.txt。