从头构建Linux系统之四 —— 构建临时系统之前的最终准备

在构建临时系统之前,还需要做一些最终的准备。本章会在$LFS目录中创建一个目录,用于安装临时工具链;然后创建一个专用于编译LFS系统的无特权用户,这样便能减少宿主机系统的风险;最后为上述用户创建一个合适的编译环境。本章还会介绍用于测量LFS各个源码包的编译时间的时间单位,也被称为SBU(Standard Build Unit,标准构建单位)。除此之外,本章还会简单介绍LFS源码包的测试套件。

一、创建临时工具目录

下一章编译的所有程序都会被安装在$LFS/tools目录之中,这些程序组成了编译LFS系统的临时工具链,它们不是最终LFS系统的组成部分。以root用户权限,创建临时工具目录:

  1. mkdir -v $LFS/tools

以root用户权限,创建指向$LFS/tools目录的符号链接:

  1. ln -sv $LFS/tools /

这个符号链接使得编译器、汇编器和链接器在宿主机系统(第5章)和chroot环境(第6章)中都能够正常工作,它们总是会使用/tools目录。

二、添加LFS用户

当以root用户登录宿主机系统时,如果操作失误,那么就有可能损坏宿主机系统。因此,本章会创建一个专用于编译LFS源码包的无特权用户。以root用户权限,创建一个名为lfs的用户和组:

  1. groupadd lfs
  2. useradd -s /bin/bash -g lfs -m -k /dev/null lfs

上述命令的各个选项的意义,如下所示:

  • -s /bin/bash
    指定lfs用户默认shell为bash。

  • -g lfs
    将lfs用户添加至lfs组。

  • -m
    为lfs用户创建家目录。

  • -k /dev/null
    将文件的输入位置修改为特殊的null设备,避免从框架目录(默认为/etc/skel)中拷贝文件。

  • lfs
    指定新建用户和组的名称为lfs。

为lfs用户创建登录密码(本章会将密码设置为password):

  1. passwd lfs

$LFS/tools目录的所有权赋予lfs用户,使其具有这个目录的完整访问权限:

  1. chown -v lfs $LFS/tools

$LFS/sources目录的所有权赋予lfs用户,使其具有这个目录的完整访问权限:

  1. chown -v lfs $LFS/sources

接下来,以lfs用户登录宿主机系统:

  1. su - lfs

-选项会使得su命令启动一个login shell,而不是一个non-login shell。login shell需要完整的登录流程,会读取/etc/profile~/.bash_profile来应用新的环境变量;non-login shell不需要用户登录流程,会读取~/.bashrc来应用新的环境变量。

三、设置编译环境

以lfs用户权限,新建.bash_profile文件:

  1. vi ~/.bash_profile

这个文件的内容如下所示:

  1. exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash

当以lfs用户登录宿主机系统时,初始的shell通常是一个login shell,它会读取宿主机系统的/etc/profile文件和.bash_profile文件,应用其中的系统设置和环境变量。.bash_profile文件中的exec env -i.../bin/ bash命令会将正在运行的shell替换为一个新建的shell,它会使用一个完全空白的环境,只有HOMETERMPS1环境变量。这样便能避免一些不需要的、有潜在危险的环境变量从宿主机系统泄露至编译环境。这个文件能够确保lfs用户使用一个干净的编译环境。

shell的新实例是一个non-login shell,它不会读取/etc/profile文件或.bash_profile文件,而是读取.bashrc文件。以lfs用户权限,新建.bashrc文件:

  1. vi ~/.bashrc

这个文件的内容如下所示:

  1. set +h
  2. umask 022
  3. LFS=/mnt/lfs
  4. LC_ALL=POSIX
  5. LFS_TGT=$(uname -m)-lfs-linux-gnu
  6. PATH=/tools/bin:/bin:/usr/bin
  7. export LFS LC_ALL LFS_TGT PATH

上述文件的每一行命令的意义,如下所示:

  • set +h
    set +h命令会关闭bash的哈希功能。通常,哈希是一种很有用的功能 —— bash会使用一张哈希表存储可执行文件的完整路径,这样便能避免为同一个可执行文件多次查找PATH环境变量而花费的时间。但是,新编译的工具应当一旦安装就能立即使用。如果关闭哈希功能,那么当需要运行某个程序时,bash总是会搜索PATH环境变量。

  • umask 022
    将用户的文件创建掩码(umask)设置为022,确保新创建的文件和目录只有所有者才有可写权限,其他用户只有可读和可执行权限(新创建文件的权限模式为644,新创建目录的权限模式为755)。

  • LFS=/mnt/lfs
    LFS环境变量设置为选定的挂载点,此处为/mnt/lfs目录。

  • LC_ALL=POSIX
    LC_ALL环境变量可以控制某些程序的本地化,使得它们的消息遵循某个指定国家的规定。将LC_ALL设置为“POSIX”或“C”(两者等效)能够确保所有组件在chroot环境中都能正常工作。

  • LFS_TGT=$(uname -m)-lfs-linux-gnu
    LFS_TGT环境变量会设置一个非默认的,但是兼容的机器描述信息。当构建交叉编译器和链接器时,以及当交叉编译临时工具链时,都会使用这个环境变量。

  • PATH=/tools/bin:/bin:/usr/bin
    /tools/bin的路径添加至PATH环境变量之后,一旦临时工具链构建完成,bash就能够立即使用这些工具。

最后,以lfs用户权限运行以下命令,使得.bash_profile文件生效:

  1. source ~/.bash_profile

四、关于SBU

在编译和安装每个源码包之前,很多人都想事先了解需要耗费的时间。因为可以在很多不同的系统上构建LFS系统,所以不可能精确地给出需要耗费的时间。在最快的系统上,最大的源码包(Glibc)将会耗费大约20分钟,但是在较慢的系统上,可能会耗费三天时间。本系列教程将会使用“标准构建单位(SBU)”来估算每个源码包的编译和安装需要耗费的时间。

下一章(构建临时系统)编译的第一个源码包是Binutils,本系列教程将编译Binutils的第一阶段需要耗费的时间称为SBU。所有其他源码包的编译时间都表示为SBU的倍数。

例如,假设编译某个源码包需要耗费的时间为4.5 SBU。这就意味着,如果在宿主机系统上编译和安装Binutils的第一阶段需要耗费10分钟,那么编译和安装示例源码包就需要耗费45分钟。幸运的是,大多数源码包耗费的时间短于Binutils耗费的时间。

通常,SBU并不是完全精确的,因为会有很多干扰因素,包括宿主机系统的GCC版本。SBU仅仅用于估算编译和安装某个源码包需要耗费的时间,在某些情况下,偏差可能会达到几十分钟。

五、关于测试套件

大多数源码包都会提供测试套件。为新编译的源码包运行测试套件是非常有必要的,因为它具有“完整性检查”的作用,能够校验源码包是否正确编译。通常,如果能够通过测试套件中的各个测试项,那么就证明源码包的功能符合开发者的预期。但是,测试套件也不能完全保证源码包是没有bug的。

某些源码包的测试套件具有非常重要的意义。例如,核心工具链的相关源码包(GCC、Binutils和Glibc)的测试套件就非常重要,因为这些组件在一个能够正常工作的系统中占据核心的角色。运行GCC和Glibc的测试套件需要耗费相当长的时间才能完成,特别是在较慢的硬件平台上,但是仍然强烈建议运行这些测试套件。

运行Binutils和GCC的测试套件时,最常遇到的问题便是耗尽虚拟终端(PTY)。这个问题可能导致大量的测试项运行失败。这个问题可以归因为若干个因素,但是最有可能的原因便是没有正确地设置宿主机系统的devpts文件系统。这个问题在以下FAQ页面中有着较为详细的描述:

  1. http://www.linuxfromscratch.org/lfs/faq.html#no-ptys

有时候,源码包的测试套件可能会运行失败,但是具体原因只有开发者才能意识到,这些原因可能并不重要。可以查阅以下页面中的编译日志,验证运行测试套件发生的错误是否在预期之内:

  1. http://www.linuxfromscratch.org/lfs/build-logs/7.10/