最后的准备工作

在构建 LFS 之前还有一些准备工作需要完成:为第三章构建的临时系统创建目录结构、添加 lfs 用户、设置环境。这些准备工作将在本节说明。

2.3.1 创建目录

我们需要创建在第三章构架临时环境时需要的所有目录。先创建符合 FHS 标准的这些目录,它们在构建临时环境后依然需要为第四章或者说最后的 LFS 系统服务。

以 root 用户运行以下的命令来创建需要的文件夹:

mkdir -pv $LFS/{bin,etc,lib,sbin,usr,var}
case $(uname -m) in
  x86_64) mkdir -pv $LFS/lib64 ;;
esac

然后创建$LFS/tools 目录,该目录只是用于存放交叉编译的中间产物的目录,在完成构建后应该和宿主系统一样可以和 LFS 系统完全分离。

mkdir -pv $LFS/tools

2.3.2 添加 lfs 用户

使用 root 实施构建操作是存在风险的,犯一个小错误可能会破坏或摧毁整个系统,这里主要指宿主系统。因此,建议在第 3 章中以非特权用户编译软件包。使用原本的用户名也是可以的,如果需要新建一个用户的话,可以以 root 用户运行以下命令来添加新的 lfs 用户和 lfs 用户组。

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

命令 useradd 的参数列表如表 2-4 所示。

表 2-3 命令 useradd 的参数列表
参数描述
-s /bin/bash将 bash 设置为 lfs 用户的默认 shell
-g lfs这个选项将用户 lfs 添加到组 lfs 中
-m为 lfs 用户创建主目录
-k /dev/null这个参数通过改变输入位置为特殊的空(null)设备,以防止可能从框架目录(默认是 /etc/skel)复制文件
lfs这是创建的组和用户的实际名称

为 lfs 用户设置密码:

passwd lfs

将 lfs 设为 $LFS 中所有目录的所有者,使 lfs 对它们拥有完全访问权:

chown -v lfs $LFS/{usr,lib,var,etc,bin,sbin,tools}
case $(uname -m) in
  x86_64) chown -v lfs $LFS/lib64 ;;
esac

如果你按照建议创建了单独的工作目录,那给 lfs 用户赋予这个目录的所有权:

chown -v lfs $LFS/sources

下一步,以 lfs 用户身份登录。可以重启一个虚拟控制台、显示控制器,或者直接使用命令切换用户:

su - lfs

命令符 - 表示 su 启动登录(login)shell,而非采用非登录(non-login)shell。关于这两种 shell 类型的区别,其实主要是登录时读取的配置文件有所不同,详细的内容可以在 man 手册 bash(1) 和 info bash 中查看详细详情。

2.3.3 设置环境

本节的设置与 2.1.3 节类似,不过这次针对的是 lfs 用户的.bash_profile 和.bashrc,设置的也不只是$LFS。运行以下命令创建一个新的.bash_profile 文件:

cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF

当以 lfs 用户身份登录时,初始 shell 通常是一个登录 shell,它先读取宿主机的/etc/profile 文件(很可能包括一些设置和环境变量),然后是.bash_profile 文件。添加到.bash_profile 中的 exec 命令使用了新的 shell(除了 HOME、TERM 和 PS1 变量外,其他环境变量完全为空),以代替运行中的 shell。这样能确保宿主系统中可能威胁到构建过程的环境变量不会侵入到构建环境中,以确保环境的“干净”。 而新的 shell 实例是一个非登录 shell,不会读取/etc/profile 或者.bash_profile 文件,而是会读取.bashrc。所以我们需要创建.bashrc 文件:

cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/usr/bin
if [ ! -L /bin ]; then PATH=/bin:$PATH; fi
PATH=$LFS/tools/bin:$PATH
CONFIG_SITE=$LFS/usr/share/config.site
export LFS LC_ALL LFS_TGT PATH CONFIG_SITE
EOF

下面逐条讲解每个指令地作用。

  1. set+h 命令关闭了 bash 的散列(hash)功能。通常散列是个不错的功能——bash 用一个散列表来记录可执行文件的完整路径,以规避对同一个可执行文件的重复寻找,节省检索 PATH 的时间。然而,新工具在安装后,我们希望它能够马上替换上次检索的结果。通过关闭散列功能,程序执行的时候就会一直检索 PATH。如此,新编译的工具一旦可用,shell 便能马上在$LFS/tools 目录中找到它们,而不是去使用存在于宿主机不同地方的旧版该程序。
  2. 设置用户文件新建时的掩码(umask)为 022,以确保新建的文件和目录只有其所有者(owner)可写,但任何人都可读可执行(假设系统调用的 open(2) 使用的是默认模式,新文件将使用 664 权限模式、文件夹为 755 模式)。
  3. LFS 变量应设置成选定的挂载点。
  4. LC_ALL 变量控制某些程序的本地化,使它们的消息遵循特定国家的惯例。设置 LC_ALL 为 POSIX 或 C(两者是等价的),确保在 chroot 环境中一切能如期望的那样进行。
  5. LFS_TGT 变量设置了一个虽非默认,但在构建交叉编译器、连接器和交叉编译临时工作链时,用得上到的兼容的机器说明。3.1 节工具链技术说明中包含更多信息。
  6. 设置 PATH 变量。一般来说设置/usr/bin 即可,如果/bin 不是符号链接,则也必须将其添加到 PATH 变量中。然后,通过把/tools/bin 放在常规 PATH 的前面,使得所有在第 3 章中安装的程序,一经安装 shell 便能马上使用。与之配合的关闭散列功能,能在第 3 章环境中的程序在可用的情况下,限制使用宿主机中旧程序的风险。
  7. 设置 CONFIG_SITE。在构建 LFS 的过程中配置文件可能会尝试加载/usr/share/config.site,导致覆盖宿主系统的问题。为防止该问题,将其设置为$LFS/usr/share/config.site。
  8. export 用于显示这些设置过后的变量,可以做好备份。

一些发行版可能会使用/etc/bash.bashrc。该文件可能会影响 LFS 软件包构建的方式修改 lfs 用户的环境,需要将其移开,以 root 用户运行:

[ ! -e /etc/bash.bashrc ] || mv -v /etc/bash.bashrc /etc/bash.bashrc.NOUSE

最后,启用刚才创建的用户配置:

source ~/.bash_profile

2.3.4 软件包构建时间 SBU

在着手之前,不少人想知道构建和安装一个软件包到底需要多长的时间。因为 Linux From Scratch 能够运行于众多的硬件上,所以具体的构建时间无法一概而论。举一个简单的例子:在最快的系统上,构建最大的软件包 Glibc 需要约 20 分钟,但在慢的系统上有可能需要 3 天!所以,这里使用 SBU(Standard Build Unit,标准构建单元)来代替具体的构建时间。

我们构建的第一个软件包是 Binutils(第 3 章需要用到的包)。将这个软件包在构建时所需要的时间作为 SBU。其他软件的构建时间,都以其为标准进行比较。举个例子,假如构建某个软件耗时 4.5SBU。这意味着如果这个系统,在构建 Binutils 需要 10 分钟,大概需要约 45 分钟来构建此软件包。很幸运,大部分的系统在生成 Binutils 时花的时间都要比这个系统要短。

一般来说,SBU 的结果并不完全准确,因为影响构建的因素太多,包括宿主机系统中 GCC 的版本也会有影响。所以更多的时候,这仅仅是提供一个构建和安装时间的预估。然而,在某些情况下,这个数字可能偏差约十几分钟。

对于大多数带有多个处理器(或内核)的现代操作系统而言,可以通过设置环境变量或者是告知 make 程序具体可用的处理器数目,通过“并行 make”来减少构建的时间。例如,对于 Core2Duo 可以通过以下参数实现两个处理器同时构建:

export MAKEFLAGS='-j 2'

或者直接这样来构建:

make -j2

以该方式使用多处理器时,SBU 值可能比书中的正常值还要大。某些情况下,make 过程仅仅是简单的就失败了。分析错误日志也十分困难:因为不同处理器之间的执行路线是交错的。如果你在构建过程中遇到了问题,为了正确分析错误信息,最好返回单处理器执行构建。