进入 Chroot 并构建其他临时工具

构建临时系统最后缺失的部分:在构建一些软件包时必要的工具。由于已经解决了所有循环依赖问题,现在即可使用“chroot”环境进行构建,它与宿主系统 (除正在运行的内核外) 完全隔离。

为了隔离环境的正常工作,必须它与正在运行的内核之间建立一些通信机制。这些通信机制通过所谓的虚拟内核文件系统实现,将在进入 chroot 环境前挂载它们。用 findmnt 命令检查它们是否挂载好。

从现在开始,直到 "进入 Chroot 环境",所有命令必须以 root 用户身份执行,且 LFS 变量必须正确设定。在进入 chroot 之后,仍然以 root 身份执行所有命令,但幸运的是此时无法访问构建 LFS 的计算机的宿主系统。不过仍然要小心,因为错误的命令很容易摧毁整个 LFS 系统。

改变所有者

备注

本书中后续的所有命令都应该在以 root 用户登录的情况下完成,而不是 lfs 用户。另外,请再次检查 $LFS 变量已经在 root 用户的环境中设定好。

  • 执行以下命令,将 $LFS/* 目录的所有者改变为 root(避免chroot之后,新系统中没有lfs用户,其id会被其他用户占用):

修订 $LFS/* 目录的所有者改变为 root
chown --from lfs -R root:root $LFS/{usr,lib,var,etc,bin,sbin,tools}
case $(uname -m) in
  x86_64) chown --from lfs -R root:root $LFS/lib64 ;;
esac

准备虚拟内核文件系统

备注

这段步骤其实和 Gentoo Linux 安装过程类似,见 在MacBook Pro上安装Gentoo Linux

用户态程序使用内核创建的一些文件系统和内核通信。这些文件系统是虚拟的:它们并不占用磁盘空间。它们的内容保留在内存中。必须将它们被挂载到 $LFS 目录树中,这样 chroot 环境中的程序才能找到它们。

  • 创建这些文件系统的挂载点

创建虚拟内核文件系统挂载点
mkdir -pv $LFS/{dev,proc,sys,run,etc}

# var 空目录创建需要么?
mkdir -pv $LFS/var/{cache,local,log,mail,opt,spool}

# 需要mountbind的目录
mkdir -pv $LFS/root
mkdir -pv $LFS/home

# 为chroot之后的系统补全目录软链接
cd $LFS
ln -sv usr/lib .
ln -sv usr/sbin .
ln -sv usr/bin .

# 构建一个sketch目录存放需要定制的文件,这些文件在物理主机中会软链接到/sketch中文件
# mountbind物理主机/etc到chroot目录后,也能软链接到这些可定制文件
mkdir $LFS/sketch
cp /etc/hosts $LFS/sketch/
cp /etc/hostname $LFS/sketch/
cp /etc/resolv.conf $LFS/sketch/

# 补全 lib64 指向 lib 的库文件软链接,否则chroot会报错提示 /usr/bin/env 不存在
mkdir -pv lib64
cd $LFS/lib64
ln -s ../lib/ld-linux-x86-64.so.2 .
ln -s ../lib/ld-linux-x86-64.so.2 ld-lsb-x86-64.so.3

  • 挂载和填充 /dev

在 LFS 系统的正常引导过程中,内核自动挂载 devtmpfs 到 /dev,并在引导过程中,或对应设备被首次发现或访问时动态地创建设备节点。udev 守护程序可能修改内核创建的设备节点的所有者或访问权限,或创建一些新的设备节点或符号链接,以简化发行版维护人员或系统管理员的工作。如果宿主系统支持 devtmpfs,我们可以简单地将 devtmpfs 挂载到 $LFS/dev 并依靠内核填充其内容。

如果宿主系统支持 devtmpfs,我们可以简单地将 devtmpfs 挂载到 $LFS/dev 并依靠内核填充其内容。因此,为了在任何宿主系统上都能填充 $LFS/dev,只能绑定挂载宿主系统的 /dev 目录。绑定挂载是一种特殊挂载类型,它允许通过不同的位置访问一个目录树或一个文件。运行以下命令进行绑定挂载:

绑定挂载 /dev
mount -v --bind /dev $LFS/dev
  • 挂载虚拟内核文件系统

挂载虚拟内核文件系统
mount -vt devpts devpts -o gid=5,mode=0620 $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run

显式挂载一个 tmpfs:

显式挂载一个 tmpfs
if [ -h $LFS/dev/shm ]; then
  install -v -d -m 1777 $LFS$(realpath /dev/shm)
else
  mount -vt tmpfs -o nosuid,nodev tmpfs $LFS/dev/shm
fi

进入 chroot 环境

现在已经准备好了所有继续构建其余工具时必要的软件包,可以进入 chroot 环境并完成临时工具的安装。在安装最终的系统时,会继续使用该 chroot 环境。以 root 用户身份,运行以下命令以进入当前只包含临时工具的 chroot 环境:

进入 chroot 环境
chroot "$LFS" /usr/bin/env -i   \
    HOME=/root                  \
    TERM="$TERM"                \
    PS1='(lfs chroot) \u:\w\$ ' \
    PATH=/usr/bin:/usr/sbin     \
    MAKEFLAGS="-j$(nproc)"      \
    TESTSUITEFLAGS="-j$(nproc)" \
    /bin/bash --login

警告

本章剩余部分和后续各章中的命令都要在 chroot 环境中运行。如果因为一些原因 (如重新启动计算机) 离开了该环境,必须确认虚拟内核文件系统挂载好,然后重新进入chroot环境,才能继续安装LFS

创建目录

  • 创建一些位于根目录中的目录

在chroot环境中创建必要目录
mkdir -pv /{boot,home,mnt,opt,srv}

mkdir -pv /etc/{opt,sysconfig}
mkdir -pv /lib/firmware
mkdir -pv /media/{floppy,cdrom}
mkdir -pv /usr/{,local/}{include,src}
mkdir -pv /usr/lib/locale
mkdir -pv /usr/local/{bin,lib,sbin}
mkdir -pv /usr/{,local/}share/{color,dict,doc,info,locale,man}
mkdir -pv /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
mkdir -pv /var/{cache,local,log,mail,opt,spool}
mkdir -pv /var/lib/{color,misc,locate}

ln -sfv /run /var/run
ln -sfv /run/lock /var/lock

install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp

警告

FHS(Filesystem Hierarchy Standard) 不要求 /usr/lib64目录,而且 LFS 编辑团队决定不使用它。LFS 和 BLFS 中的一些命令只有在该目录不存在时才能正常工作。

应该经常检查并确认该目录不存在,因为往往容易无意地创建该目录,而它的存在可能破坏系统。

  • 创建必要的文件和符号链接

创建必要的文件和符号链接
# 历史上,Linux 曾在 /etc/mtab 维护已经挂载的文件系统的列表。现代内核在内部维护该列表,并通过 /proc 文件系统将它展示给用户。为了满足一些仍然使用 /etc/mtab 的工具,执行以下命令,创建符号链接
ln -sv /proc/self/mounts /etc/mtab

# 创建一个基本的 /etc/hosts 文件,一些测试套件,以及 Perl 的一个配置文件将会使用它
cat > /etc/hosts << EOF
127.0.0.1  localhost $(hostname)
::1        localhost
EOF

# 为了使得 root 能正常登录,而且用户名 “root” 能被正常识别,必须在文件 /etc/passwd 和 /etc/groups 中写入相关的条目
cat > /etc/passwd << "EOF"
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/dev/null:/usr/bin/false
daemon:x:6:6:Daemon User:/dev/null:/usr/bin/false
messagebus:x:18:18:D-Bus Message Daemon User:/run/dbus:/usr/bin/false
uuidd:x:80:80:UUID Generation Daemon User:/dev/null:/usr/bin/false
nobody:x:65534:65534:Unprivileged User:/dev/null:/usr/bin/false
EOF

# 执行以下命令,创建 /etc/group 文件
cat > /etc/group << "EOF"
root:x:0:
bin:x:1:daemon
sys:x:2:
kmem:x:3:
tape:x:4:
tty:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
cdrom:x:15:
adm:x:16:
messagebus:x:18:
input:x:24:
mail:x:34:
kvm:x:61:
uuidd:x:80:
wheel:x:97:
users:x:999:
nogroup:x:65534:
EOF

# 一些软件包需要一个 locale
localedef -i C -f UTF-8 C.UTF-8

# 一些测试需要使用一个非特权用户
echo "tester:x:101:101::/home/tester:/bin/bash" >> /etc/passwd
echo "tester:x:101:" >> /etc/group
install -o tester -d /home/tester

# 重新登陆shell
exec /usr/bin/bash --login

# login、agetty 和 init 等程序使用一些日志文件,以记录登录系统的用户和登录时间等信息
# 初始化日志文件,并为它们设置合适的访问权限
touch /var/log/{btmp,lastlog,faillog,wtmp}
chgrp -v utmp /var/log/lastlog
chmod -v 664  /var/log/lastlog
chmod -v 600  /var/log/btmp

安装Gettext

对于临时工具只要安装 Gettext 中的三个程序
cd $LFS/sources

gettext_VERSION=0.22.5
tar xf gettext-${gettext_VERSION}.tar.xz
cd gettext-${gettext_VERSION}

./configure --disable-shared
make
# 安装 msgfmt,msgmerge,以及 xgettext 这三个程序
cp -v gettext-tools/src/{msgfmt,msgmerge,xgettext} /usr/bin

安装Bison

安装Bison(语法分析器生成器)
cd $LFS/sources

bison_VERSION=3.8.2
tar xf bison-${bison_VERSION}.tar.xz
cd bison-${bison_VERSION}

./configure --prefix=/usr \
            --docdir=/usr/share/doc/bison-${bison_VERSION}
make
make install

安装Perl

安装Perl
cd $LFS/sources

perl_VERSION=5.40.0
tar xf perl-${perl_VERSION}.tar.xz
cd perl-${perl_VERSION}

sh Configure -des                                         \
             -D prefix=/usr                               \
             -D vendorprefix=/usr                         \
             -D useshrplib                                \
             -D privlib=/usr/lib/perl5/${perl_VERSION}/core_perl     \
             -D archlib=/usr/lib/perl5/${perl_VERSION}/core_perl     \
             -D sitelib=/usr/lib/perl5/${perl_VERSION}/site_perl     \
             -D sitearch=/usr/lib/perl5/${perl_VERSION}/site_perl    \
             -D vendorlib=/usr/lib/perl5/${perl_VERSION}/vendor_perl \
             -D vendorarch=/usr/lib/perl5/${perl_VERSION}/vendor_perl
make
make install

安装Python

安装Python
cd $LFS/sources

python_VERSION=3.12.5
tar xf Python-${python_VERSION}.tar.xz
cd Python-${python_VERSION}

./configure --prefix=/usr   \
            --enable-shared \
            --without-ensurepip
make
make install

备注

一些 Python 3 模块目前无法构建,这是因为它们的依赖项尚未安装。这些模块会在后续构建

安装Texinfo

安装Texinfo
cd $LFS/sources

texinfo_VERSION=7.1
tar xf texinfo-${texinfo_VERSION}.tar.xz
cd texinfo-${texinfo_VERSION}

./configure --prefix=/usr
make
make install

清理和备份临时系统

  • 清理

清理
# 删除已经安装的临时工具文档文件,以防止它们进入最终构建的系统
rm -rf /usr/share/{info,man,doc}/*

# 在现代 Linux 系统中,libtool 的 .la 文件仅用于 libltdl。LFS 中没有库通过 libltdl 加载,而且已知一些 .la 文件会导致 BLFS 软件包出现异常
find /usr/{lib,libexec} -name \*.la -delete

# 不需要临时系统中的 /tools 目录
rm -rf /tools
  • 备份

备份
# 在 chroot 环境之外进行备份,也就是先退出chroot再执行以下命令
exit

# 备份之前,解除内核虚拟文件系统的挂载
mountpoint -q $LFS/dev/shm && umount $LFS/dev/shm
umount $LFS/dev/pts
umount $LFS/{sys,proc,run,dev}

# 运行以下命令,创建备份档案
# xz压缩很消耗计算cpu
cd $LFS
#tar -cJpf $HOME/lfs-temp-tools-12.2.tar.xz .
tar -cpf $HOME/lfs-temp-tools-12.2.tar .

还原(除非执行出错,否则不需要还原)

  • 以下命令是出错时恢复,参考备用,无需执行:

如果出错时需要恢复(正常情况下无需执行)
cd $LFS
rm -rf ./*
tar -xpf $HOME/lfs-temp-tools-12.2.tar.xz