LFS安装基本系统软件
概述
LFS不推荐在编译中使用自定义优化:
虽然使用自定义优化编译可能会使程序运行稍快一点,但是由于源代码和编译工具的复杂相互作用,仍然存在编译不正确的风险
除非LFS手册明确说明外,设置
-march
和-mtune
是未经验证的,可能子啊工具链软件包(binutils,gcc和glibc)中引发问题LFS采用软件包默认配置启用的优化选项,原因是认为软件包维护者已经测试了这些配置并认为他们是安全的,这样不太可能导致构建失败
通常默认配置已经启用了
-O2
或-O3
,因此即使不使用任何自定义优化情况下,得到的系统应该仍然会运行很快并保持稳定
LFS不建议构建和安装静态库:
在现代 Linux 系统中,多数静态库已经失去存在的意义
将静态库链接到程序中可能是有害的
如果静态库存在安全问题,则需要所有使用这个静态库的程序重新链接到新版本库,这是非常困难的,甚至可能无法查明有哪些程序需要重新链接 (以及如何重新链接)
LFS手册在安装过程删除或者禁止安装多数静态库: 通常传递
--disable-static
选项给configure
来达到这个目的;不过极个别情况,特别是Glibc
和GCC
,静态库在一般软件包的构建过程中仍然很关键,就不能禁用静态库
软件包管理
LFS 或 BLFS 不介绍任何包管理器的原因:
处理软件包管理会偏离这两本手册的目标 —— 讲述如何构建 Linux 系统
存在多种软件包管理的解决方案,它们各有优缺点。很难找到一种让所有读者满意的方案
升级问题
内核可以独立升级,不需要重构任何软件包: 内核态与用户态的接口十分清晰;升级内核 不需要 一同更新Linux API头文件
Glibc升级需要额外处理以防止损坏系统
如果更新一个包含共享库的软件包,并且共享库的名称发生改变,则所有动态链接到这个库的软件包都要重新编译,以链接到新版本的库。注意,不能删除旧版本的库,直到将所有依赖它的软件包都重新编译完成
如果更新共享库的库文件版本号降低,则需要删除就版本软件包安装的库,这是因为
ldconfig
命令会将符号链接到版本号更大(看起来更"新")的旧版本库。也就是不得不降级软件包或者软件包作者更改库文件版本号格式时,需要注意这个操作。如果更新包含共享库的软件包,且共享库的名称没有改变,则需要重启所有链接到该库的程序以生效(例如升级ssl库需要重启ssh服务)
如果一个可执行程序或共享库被覆盖,则正在使用该程序或库中代码或数据的进程可能崩溃。解决方法时先删除就版本,再安装新版本。Coreutils提供的
install
已经实现了这个过程,多数软件使用这个安装命令安装二进制文件和库。
跟踪安装程序
使用 strace
能够记录安装脚本执行过程中所有系统调用
警告
从现在开始的操纵是在 chroot
环境中进行,每次ssh登陆到服务器上都需要重新完成 进入 Chroot 并构建其他临时工具 开头部分
所有操作以 root
身份完成,由于是 chroot
之后操作,所以对Host主机没有影响
安装Man-pages
cd /sources
man_VERSION=6.9.1
tar xf man-pages-${man_VERSION}.tar.xz
cd man-pages-${man_VERSION}
rm -v man3/crypt*
make prefix=/usr install
安装Iana-Etc
cd /sources
iana_VERSION=20240806
tar xf iana-etc-${iana_VERSION}.tar.gz
cd iana-etc-${iana_VERSION}
cp services protocols /etc
Iana-Etc
安装了:
/etc/protocols
描述 TCP/IP 子系统中可用的各种 DARPA Internet 协议/etc/services
提供 Internet 服务的可读文本名称、底层的分配端口号以及 协议类型之间的对应关系
安装Glibc
cd /sources
glibc_VERSION=2.40
tar xf glibc-${glibc_VERSION}.tar.xz
cd glibc-${glibc_VERSION}
patch -Np1 -i ../glibc-${glibc_VERSION}-fhs-1.patch
mkdir -v build
cd build
echo "rootsbindir=/usr/sbin" > configparms
../configure --prefix=/usr \
--disable-werror \
--enable-kernel=4.19 \
--enable-stack-protector=strong \
--disable-nscd \
libc_cv_slibdir=/usr/lib
make
make check
# 避免安装是报告/etc/ld.so.conf 不存在(无害信息)
touch /etc/ld.so.conf
# 跳过一个过时的,对于现代的 Glibc 构型会失败的完整性检查
sed '/test-installation/s@$(PERL)@echo not running@' -i ../Makefile
make install
# 改正 ldd 脚本中硬编码的可执行文件加载器路径
sed '/RTLDLIST=/s@/usr@@g' -i /usr/bin/ldd
# 安装locale,locale不是必须的,但是一些软件包测试套件需要其完成重要的测试
# 我这里尝试只安装2个locale,如果不行再按照原文档安装必要的最小集合locale
# 已经验证确实后续测试报错有locale相关不支持错误(gawk),看来确实需要完整安装最小集合
localedef -i C -f UTF-8 C.UTF-8
localedef -i en_US -f UTF-8 en_US.UTF-8
localedef -i ja_JP -f SHIFT_JIS ja_JP.SJIS 2> /dev/null || true
配置Glibc
由于 Glibc 的默认值在网络环境下不能很好地工作,需要创建配置文件 /etc/nsswitch.conf
/etc/nsswitch.conf
cat > /etc/nsswitch.conf << "EOF"
# Begin /etc/nsswitch.conf
passwd: files
group: files
shadow: files
hosts: files dns
networks: files
protocols: files
services: files
ethers: files
rpc: files
# End /etc/nsswitch.conf
EOF
添加时区数据
安装并设置时区数据:
tar -xf ../../tzdata2024a.tar.gz
ZONEINFO=/usr/share/zoneinfo
mkdir -pv $ZONEINFO/{posix,right}
for tz in etcetera southamerica northamerica europe africa antarctica \
asia australasia backward; do
zic -L /dev/null -d $ZONEINFO ${tz}
zic -L /dev/null -d $ZONEINFO/posix ${tz}
zic -L leapseconds -d $ZONEINFO/right ${tz}
done
cp -v zone.tab zone1970.tab iso3166.tab $ZONEINFO
zic -d $ZONEINFO -p America/New_York
unset ZONEINFO
说明:
zic -L /dev/null ...
该命令创建没有闰秒的 POSIX 时区。一般的惯例是将它们安装在 zoneinfo 和 zoneinfo/posix 两个目录中。必须将 POSIX 时区安装到 zoneinfo,否则若干测试套件会报告错误。
zic -L leapseconds ...
该命令创建正确的,包含闰秒的时区。
zic ... -p ...
该命令创建 posixrule 文件。我们使用纽约时区,因为 POSIX 要求与美国一致的夏令时规则。
创建
/etc/localtime
# 我这里设置北京时间
ln -sfv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
配置动态加载器
默认情况下,动态加载器 ( /lib/ld-linux.so.2
) 在 /usr/lib
中搜索程序运行时需要的动态库
有两个目录
/usr/local/lib
和/opt/lib
经常包含附加的共享库,所以现在将它们添加到动态加载器的搜索目录中
cat > /etc/ld.so.conf << "EOF"
# Begin /etc/ld.so.conf
/usr/local/lib
/opt/lib
EOF
此外动态加载器可以搜索目录,如下配置:
cat >> /etc/ld.so.conf << "EOF"
# Add an include directory
include /etc/ld.so.conf.d/*.conf
EOF
mkdir -pv /etc/ld.so.conf.d
安装Zlib
cd /sources
zlib_VERSION=1.3.1
tar xf zlib-${zlib_VERSION}.tar.gz
cd zlib-${zlib_VERSION}
./configure --prefix=/usr
make
make check
make install
#删除无用静态库
rm -fv /usr/lib/libz.a
安装Bzip2
cd /sources
bzip2_VERSION=1.0.8
tar xf bzip2-${bzip2_VERSION}.tar.gz
cd bzip2-${bzip2_VERSION}
# 应用一个补丁,以安装该软件包的文档
patch -Np1 -i ../bzip2-${bzip2_VERSION}-install_docs-1.patch
# 保证安装的符号链接是相对的
sed -i 's@\(ln -s -f \)$(PREFIX)/bin/@\1@' Makefile
# 确保手册页被安装到正确位置
sed -i "s@(PREFIX)/man@(PREFIX)/share/man@g" Makefile
# 执行以下命令,准备编译 Bzip2
make -f Makefile-libbz2_so
make clean
make
make PREFIX=/usr install
# 安装共享库
cp -av libbz2.so.* /usr/lib
ln -sv libbz2.so.${bzip2_VERSION} /usr/lib/libbz2.so
# 安装链接到共享库的 bzip2 二进制程序到 /bin 目录,并将两个和 bzip2 完全相同的文件替换成符号链接
cp -v bzip2-shared /usr/bin/bzip2
for i in /usr/bin/{bzcat,bunzip2}; do
ln -sfv bzip2 $i
done
# 删除无用的静态库
rm -fv /usr/lib/libbz2.a
安装Xz
cd /sources
xz_VERSION=5.6.2
tar xf xz-${xz_VERSION}.tar.xz
cd xz-${xz_VERSION}
./configure --prefix=/usr \
--disable-static \
--docdir=/usr/share/doc/xz-${xz_VERSION}
make
make check
make install
安装Lz4
cd /sources
lz4_VERSION=1.10.0
tar xf lz4-${lz4_VERSION}.tar.gz
cd lz4-${lz4_VERSION}
make BUILD_STATIC=no PREFIX=/usr
make -j1 check
make BUILD_STATIC=no PREFIX=/usr install
安装Zstd
cd /sources
zstd_VERSION=1.5.6
tar xf zstd-${zstd_VERSION}.tar.gz
cd zstd-${zstd_VERSION}
make prefix=/usr
make check
make prefix=/usr install
rm -v /usr/lib/libzstd.a
安装File
cd /sources
file_VERSION=5.45
tar xf file-${file_VERSION}.tar.gz
cd file-${file_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Readline
cd /sources
readline_VERSION=8.2.13
tar xf readline-${readline_VERSION}.tar.gz
cd readline-${readline_VERSION}
# 重新安装 Readline 会导致旧版本的库被重命名为 <库名称>.old
# 某些情况下会触发 ldconfig 的一个链接 bug
# 修复:
sed -i '/MV.*old/d' Makefile.in
sed -i '/{OLDSUFF}/c:' support/shlib-install
# 防止在共享库中硬编码库文件搜索路径 (rpath)
sed -i 's/-Wl,-rpath,[^ ]*//' support/shobj-conf
./configure --prefix=/usr \
--disable-static \
--with-curses \
--docdir=/usr/share/doc/readline-${readline_VERSION}
make SHLIB_LIBS="-lncursesw"
make SHLIB_LIBS="-lncursesw" install
install -v -m644 doc/*.{ps,pdf,html,dvi} /usr/share/doc/readline-${readline_VERSION}
安装M4
cd /sources
m4_VERSION=1.4.19
tar xf m4-${m4_VERSION}.tar.xz
cd m4-${m4_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Bc
cd /sources
bc_VERSION=6.7.6
tar xf bc-${bc_VERSION}.tar.xz
cd bc-${bc_VERSION}
CC=gcc ./configure --prefix=/usr -G -O3 -r
make
make test
make install
安装Flex
cd /sources
flex_VERSION=2.6.4
tar xf flex-${flex_VERSION}.tar.gz
cd flex-${flex_VERSION}
./configure --prefix=/usr \
--docdir=/usr/share/doc/flex-${flex_VERSION} \
--disable-static
make
make check
make install
安装Tcl
cd /sources
tcl_VERSION=8.6.14
tcl_MAIN_VERSION=8.6
tar xf tcl${tcl_VERSION}-src.tar.gz
cd tcl${tcl_VERSION}
SRCDIR=$(pwd)
cd unix
./configure --prefix=/usr \
--mandir=/usr/share/man \
--disable-rpath
make
sed -e "s|$SRCDIR/unix|/usr/lib|" \
-e "s|$SRCDIR|/usr/include|" \
-i tclConfig.sh
tcdc_VERSION=1.1.7
sed -e "s|$SRCDIR/unix/pkgs/tdbc${tcdc_VERSION}|/usr/lib/tdbc${tcdc_VERSION}|" \
-e "s|$SRCDIR/pkgs/tdbc${tcdc_VERSION}/generic|/usr/include|" \
-e "s|$SRCDIR/pkgs/tdbc${tcdc_VERSION}/library|/usr/lib/tcl${tcl_MAIN_VERSION}|" \
-e "s|$SRCDIR/pkgs/tdbc${tcdc_VERSION}|/usr/include|" \
-i pkgs/tdbc${tcdc_VERSION}/tdbcConfig.sh
itcl_VERSION=4.2.4
sed -e "s|$SRCDIR/unix/pkgs/itcl${itcl_VERSION}|/usr/lib/itcl${itcl_VERSION}|" \
-e "s|$SRCDIR/pkgs/itcl${itcl_VERSION}/generic|/usr/include|" \
-e "s|$SRCDIR/pkgs/itcl${itcl_VERSION}|/usr/include|" \
-i pkgs/itcl${itcl_VERSION}/itclConfig.sh
unset SRCDIR
make test
make install
chmod -v u+w /usr/lib/libtcl${tcl_MAIN_VERSION}.so
#安装 Tcl 的头文件
make install-private-headers
# 建立必要符号链接
ln -sfv tclsh${tcl_MAIN_VERSION} /usr/bin/tclsh
# 重命名一个与 Perl 手册页文件名冲突的手册页
mv /usr/share/man/man3/{Thread,Tcl_Thread}.3
# 安装文档(可选)
cd ..
tar -xf ../tcl${tcl_VERSION}-html.tar.gz --strip-components=1
mkdir -v -p /usr/share/doc/tcl-${tcl_VERSION}
cp -v -r ./html/* /usr/share/doc/tcl-${tcl_VERSION}
安装Expect
测试验证PTY 是否在 chroot 环境中正常工作:
python3 -c 'from pty import spawn; spawn(["echo", "ok"])'
如果不正常则需要检查前面虚拟内核文件系统,确认 devpts
文件系统是否正确挂载。并重新进入chroot环境。这是确保Expect测试套件能正常工作,避免产生隐蔽问题。
cd /sources
expect_VERSION=5.45.4
tar xf expect${expect_VERSION}.tar.gz
cd expect${expect_VERSION}
# 修改软件包允许gcc-14.1或更新版本来构建它
patch -Np1 -i ../expect-${expect_VERSION}-gcc14-1.patch
./configure --prefix=/usr \
--with-tcl=/usr/lib \
--enable-shared \
--disable-rpath \
--mandir=/usr/share/man \
--with-tclinclude=/usr/include
make
make test
make install
ln -svf expect${expect_VERSION}/libexpect${expect_VERSION}.so /usr/lib
安装DejaGNU
DejaGNU 包含私用GNU工具进行测试套件的框架,使用 expect
编写,后者又使用了Tcl(工具命令语言):
cd /sources
dejagnu_VERSION=1.6.3
tar xf dejagnu-${dejagnu_VERSION}.tar.gz
cd dejagnu-${dejagnu_VERSION}
mkdir -v build
cd build
../configure --prefix=/usr
makeinfo --html --no-split -o doc/dejagnu.html ../doc/dejagnu.texi
makeinfo --plaintext -o doc/dejagnu.txt ../doc/dejagnu.texi
make check
make install
install -v -dm755 /usr/share/doc/dejagnu-${dejagnu_VERSION}
install -v -m644 doc/dejagnu.{html,txt} /usr/share/doc/dejagnu-${dejagnu_VERSION}
安装Pkgconf
pkgconf
软件包是 pkg-config
的接替者,用于在软件包安装的配置和生成阶段向构建工具传递头文件或库文件搜索路径的工具。
cd /sources
pkgconf_VERSION=2.3.0
tar xf pkgconf-${pkgconf_VERSION}.tar.xz
cd pkgconf-${pkgconf_VERSION}
./configure --prefix=/usr \
--disable-static \
--docdir=/usr/share/doc/pkgconf-${pkgconf_VERSION}
make
make install
ln -sv pkgconf /usr/bin/pkg-config
ln -sv pkgconf.1 /usr/share/man/man1/pkg-config.1
安装Binutils
cd /sources
binutils_VERSION=2.43.1
tar xf binutils-${binutils_VERSION}.tar.xz
cd binutils-${binutils_VERSION}
mkdir -v build
cd build
../configure --prefix=/usr \
--sysconfdir=/etc \
--enable-gold \
--enable-ld=default \
--enable-plugins \
--enable-shared \
--disable-werror \
--enable-64-bit-bfd \
--enable-new-dtags \
--with-system-zlib \
--enable-default-hash-style=gnu
make tooldir=/usr
# 确实有失败,通过 grep '^FAIL:' $(find -name '*.log') 列出失败,文档中说明: Gold 测试套件中,有十二项测试在构建 GCC 时启用 --enable-default-pie 和 --enable-default-ssp 的情况下会失败
make -k check
make tooldir=/usr install
rm -fv /usr/lib/lib{bfd,ctf,ctf-nobfd,gprofng,opcodes,sframe}.a
安装GMP
GMP 软件包包含提供任意精度算术函数的数学库
cd /sources
gmp_VERSION=6.3.0
tar xf gmp-${gmp_VERSION}.tar.xz
cd gmp-${gmp_VERSION}
./configure --prefix=/usr \
--enable-cxx \
--disable-static \
--docdir=/usr/share/doc/gmp-${gmp_VERSION}
make
make html
# 测试套件是关键 无论如何都不要跳过测试过程
# 测试编译结果
make check 2>&1 | tee gmp-check-log
# 执行以下检查任务,务必确认测试套件中至少 199 项测试通过
awk '/# PASS:/{total+=$3} ; END{print total}' gmp-check-log
make install
make install-html
警告
GMP 中的代码是针对本机处理器高度优化的。在偶然情况下,检测处理器的代码会错误识别 CPU 的功能,导致测试套件或使用 GMP 的其他程序输出消息 Illegal instruction (非法指令)。如果发生这种情况,需要使用选项 --build=none-pc-linux-gnu
重新配置 GMP 并重新构建它。
安装MPFR
MPFR 软件包包含多精度数学函数
cd /sources
mpfr_VERSION=4.2.1
tar xf mpfr-${mpfr_VERSION}.tar.xz
cd mpfr-${mpfr_VERSION}
./configure --prefix=/usr \
--disable-static \
--enable-thread-safe \
--docdir=/usr/share/doc/mpfr-${mpfr_VERSION}
make
make html
# MPFR 的测试套件被认为是非常关键的,无论如何不能跳过
# 确认所有 198 项测试都能通过
make check
make install
make install-html
安装MPC
MPC 软件包包含一个任意高精度,且舍入正确的复数算术库
cd /sources
mpc_VERSION=1.3.1
tar xf mpc-${mpc_VERSION}.tar.gz
cd mpc-${mpc_VERSION}
./configure --prefix=/usr \
--disable-static \
--docdir=/usr/share/doc/mpc-${mpc_VERSION}
make
make html
make check
make install
make install-html
安装Attr
Attr 软件包包含管理文件系统对象扩展属性的工具
cd /sources
attr_VERSION=2.5.2
tar xf attr-${attr_VERSION}.tar.gz
cd attr-${attr_VERSION}
./configure --prefix=/usr \
--disable-static \
--sysconfdir=/etc \
--docdir=/usr/share/doc/attr-${attr_VERSION}
make
make check
make install
安装Acl
Acl 软件包包含管理访问控制列表的工具,访问控制列表能够细致地自由定义文件和目录的访问权限
cd /sources
acl_VERSION=2.3.2
tar xf acl-${acl_VERSION}.tar.xz
cd acl-${acl_VERSION}
./configure --prefix=/usr \
--disable-static \
--docdir=/usr/share/doc/acl-${acl_VERSION}
make
# Acl 的测试套件必须在支持访问控制的文件系统上运行,且必须在使用 Acl 库构建 Coreutils 软件包之后才能运行
# 所以需要在Coreutils软件包构建以后才能回到这里执行 make check
make install
安装Libcap
Libcap 软件包为 Linux 内核提供的 POSIX 1003.1e 权能字实现用户接口。这些权能字是 root 用户的最高特权分割成的一组不同权限。
cd /sources
libcap_VERSION=2.70
tar xf libcap-${libcap_VERSION}.tar.xz
cd libcap-${libcap_VERSION}
# 防止静态库的安装
sed -i '/install -m.*STA/d' libcap/Makefile
# 编译
make prefix=/usr lib=lib
make test
make prefix=/usr lib=lib install
安装Libxcrypt
Libxcrypt 软件包包含用于对密码进行单向散列操作的现代化的库
cd /sources
libxcrypt_VERSION=4.4.36
tar xf libxcrypt-${libxcrypt_VERSION}.tar.xz
cd libxcrypt-${libxcrypt_VERSION}
./configure --prefix=/usr \
--enable-hashes=strong,glibc \
--enable-obsolete-api=no \
--disable-static \
--disable-failure-tokens
# 编译
make
make check
make install
安装Shadow
Shadow 软件包包含安全地处理密码的程序
cd /sources
shadow_VERSION=4.16.0
tar xf shadow-${shadow_VERSION}.tar.xz
cd shadow-${shadow_VERSION}
# 禁止该软件包安装 groups 程序和它的手册页,因为 Coreutils 会提供更好的版本
# 并且避免按阿黄man-pages软件包已经提供的手册页
sed -i 's/groups$(EXEEXT) //' src/Makefile.in
find man -name Makefile.in -exec sed -i 's/groups\.1 / /' {} \;
find man -name Makefile.in -exec sed -i 's/getspnam\.3 / /' {} \;
find man -name Makefile.in -exec sed -i 's/passwd\.5 / /' {} \;
# 不使用默认的 crypt 加密方法,使用安全程度高很多的 YESCRYPT 算法加密密码,这也允许设定长度超过 8 个字符的密码
# 需要把过时的用户邮箱位置 /var/spool/mail 改为当前普遍使用的 /var/mail 目录
# 从默认的 PATH 中删除/bin 和 /sbin,因为它们只是指向 /usr 中对应目录的符号链接
sed -e 's:#ENCRYPT_METHOD DES:ENCRYPT_METHOD YESCRYPT:' \
-e 's:/var/spool/mail:/var/mail:' \
-e '/PATH=/{s@/sbin:@@;s@/bin:@@}' \
-i etc/login.defs
touch /usr/bin/passwd
./configure --sysconfdir=/etc \
--disable-static \
--with-{b,yes}crypt \
--without-libbsd \
--with-group-name-max-length=32
# 编译
make
make exec_prefix=/usr install
make -C man install-man
配置Shadow
Shadow 软件包包含用于添加、修改、删除用户和组,设定和修改它们的密码,以及进行其他管理任务的工具
# 如果要对用户密码启用 Shadow 加密,执行以下命令
pwconv
# 如果要对组密码启用 Shadow 加密,执行
grpconv
# 为了修改默认参数,必须创建 /etc/default/useradd 文件,并定制其内容
mkdir -p /etc/default
useradd -D --gid 999
# 不希望 useradd 创建邮箱文件,执行以下命令
sed -i '/MAIL/s/yes/no/' /etc/default/useradd
# 现在为root用户创建密码
passwd root
安装GCC
GCC 软件包包含 GNU 编译器集合,其中有 C 和 C++ 编译器
cd /sources
gcc_VERSION=14.2.0
tar xf gcc-${gcc_VERSION}.tar.xz
cd gcc-${gcc_VERSION}
# 在 x86_64 上构建时,修改存放 64 位库的默认路径为 “lib”
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esac
mkdir -v build
cd build
../configure --prefix=/usr \
LD=ld \
--enable-languages=c,c++ \
--enable-default-pie \
--enable-default-ssp \
--enable-host-pie \
--disable-multilib \
--disable-bootstrap \
--disable-fixincludes \
--with-system-zlib
make
# 虽然多数宿主发行版 (和最终的 LFS 系统中),默认的硬上限值已经是无限大,但手工调整限制无论如何都不会造成损害
ulimit -s -H unlimited
# 移除或修复若干已知会失败的测试
sed -e '/cpython/d' -i ../gcc/testsuite/gcc.dg/plugin/plugin.exp
sed -e 's/no-pic /&-no-pie /' -i ../gcc/testsuite/gcc.target/i386/pr113689-1.c
sed -e 's/300000/(1|300000)/' -i ../libgomp/testsuite/libgomp.c-c++-common/pr109062.c
sed -e 's/{ target nonpic } //' \
-e '/GOTPCREL/d' -i ../gcc/testsuite/gcc.target/i386/fentryname3.c
# 以非特权用户身份测试编译结果,但出错时继续执行其他测试
chown -R tester .
su tester -c "PATH=$PATH make -k check"
# 输入以下命令提取测试结果的摘要
../contrib/test_summary
make install
# GCC 构建目录目前属于用户 tester,导致安装的头文件目录 (及其内容) 具有不正确的所有权。将所有者修改为 root 用户和组
chown -v -R root:root \
/usr/lib/gcc/$(gcc -dumpmachine)/${gcc_VERSION}/include{,-fixed}
# 创建必要的软链接
# 创建一个 FHS 因 “历史原因” 要求的符号链接
ln -svr /usr/bin/cpp /usr/lib
# 许多软件包使用 cc 这一名称调用 C 编译器
ln -sv gcc.1 /usr/share/man/man1/cc.1
# 创建一个兼容性符号链接,以支持在构建程序时使用链接时优化 (LTO)
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/14.2.0/liblto_plugin.so \
/usr/lib/bfd-plugins/
完成后通过以下方式验证确认编译和链接:
echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
输出不应报错,应该显示类似如下结果(不同平台的动态链接器名称可能不同):
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
确认使用正确的启动文件:
grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log
确认编译器能正确查找头文件:
grep -B4 '^ /usr/include' dummy.log
确认新的链接器使用了正确的搜索路径:
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
确认使用了正确的 libc:
grep "/lib.*/libc.so.6 " dummy.log
确认 GCC 使用了正确的动态链接器:
grep found dummy.log
以上输出不应有错误或没有输出,否则就需要检查问题原因并修复才能继续
在确认一切工作良好后,删除测试文件:
rm -v dummy.c a.out dummy.log
最后移动一个位置不正确的文件:
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib
安装Ncurses
安装Ncureses:
cd /sources
ncurses_VERSION=6.5
tar xf ncurses-${ncurses_VERSION}.tar.gz
cd ncurses-${ncurses_VERSION}
./configure --prefix=/usr \
--mandir=/usr/share/man \
--with-shared \
--without-debug \
--without-normal \
--with-cxx-shared \
--enable-pc-files \
--with-pkg-config-libdir=/usr/lib/pkgconfig
make
# 安装该软件包会直接覆盖文件 libncursesw.so.6.5
# 这可能导致正在使用该库文件中的代码和数据的 shell 进程发生崩溃
# 因此,需要使用 DESTDIR 进行安装,并正确地使用 install 命令安装库文件:
make DESTDIR=$PWD/dest install
install -vm755 dest/usr/lib/libncursesw.so.${ncurses_VERSION} /usr/lib
rm -v dest/usr/lib/libncursesw.so.${ncurses_VERSION}
sed -e 's/^#if.*XOPEN.*$/#if 1/' \
-i dest/usr/include/curses.h
cp -av dest/* /
# 许多程序仍然希望链接器能够找到非宽字符版本的 Ncurses 库。通过使用符号链接和链接脚本,诱导它们链接到宽字符库
for lib in ncurses form panel menu ; do
ln -sfv lib${lib}w.so /usr/lib/lib${lib}.so
ln -sfv ${lib}w.pc /usr/lib/pkgconfig/${lib}.pc
done
# 确保那些在构建时寻找 -lcurses 的老式程序仍然能够构建
ln -sfv libncursesw.so /usr/lib/libcurses.so
# 安装 Ncurses 文档(可选)
cp -v -R doc -T /usr/share/doc/ncurses-${ncurses_VERSION}
安装Sed
安装Sed:
cd /sources
sed_VERSION=4.9
tar xf sed-${sed_VERSION}.tar.xz
cd sed-${sed_VERSION}
./configure --prefix=/usr
make
make html
# 测试编译结果
chown -R tester .
su tester -c "PATH=$PATH make check"
# 安装软件包和文档
make install
install -d -m755 /usr/share/doc/sed-${sed_VERSION}
install -m644 doc/sed.html /usr/share/doc/sed-${sed_VERSION}
安装Psmisc
Psmisc 软件包包含显示正在运行的进程信息的程序
cd /sources
psmisc_VERSION=23.7
tar xf psmisc-${psmisc_VERSION}.tar.xz
cd psmisc-${psmisc_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Gettext
Gettext 软件包包含国际化和本地化工具,它们允许程序在编译时加入 NLS (本地语言支持) 功能,使它们能够以用户的本地语言输出消息
cd /sources
gettext_VERSION=0.22.5
tar xf gettext-${gettext_VERSION}.tar.xz
cd gettext-${gettext_VERSION}
./configure --prefix=/usr \
--disable-static \
--docdir=/usr/share/doc/gettext-${gettext_VERSION}
make
make check
make install
chmod -v 0755 /usr/lib/preloadable_libintl.so
安装Bison
Bison 软件包包含语法分析器生成器
cd /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 check
make install
安装Grep
Grep 软件包包含在文件内容中进行搜索的程序
cd /sources
grep_VERSION=3.11
tar xf grep-${grep_VERSION}.tar.xz
cd grep-${grep_VERSION}
# 使用 egrep 和 fgrep 时的警告,它会导致一些软件包测试失败
sed -i "s/echo/#echo/" src/egrep.sh
./configure --prefix=/usr
make
make check
make install
安装Bash
cd /sources
bash_VERSION=5.2.32
tar xf bash-${bash_VERSION}.tar.gz
cd bash-${bash_VERSION}
./configure --prefix=/usr \
--without-bash-malloc \
--with-installed-readline \
bash_cv_strtold_broken=no \
--docdir=/usr/share/doc/bash-${bash_VERSION}
make
# 测试
chown -R tester .
su -s /usr/bin/expect tester << "EOF"
set timeout -1
spawn make tests
expect eof
lassign [wait] _ _ _ value
exit $value
EOF
make install
# 执行新编译的 bash 程序 (替换当前正在执行的版本)
exec /usr/bin/bash --login
安装Libtool
Libtool 软件包包含 GNU 通用库支持脚本。它提供一致、可移植的接口,以简化共享库的使用
cd /sources
libtool_VERSION=2.4.7
tar xf libtool-${libtool_VERSION}.tar.xz
cd libtool-${libtool_VERSION}
./configure --prefix=/usr
make
# 在 LFS 构建环境中,已知有五项测试因为循环依赖而失败,但这些测试在 automake 安装后能够通过
# 在使用 grep-3.8 或更新版本时,两项测试触发关于非 POSIX 正则表达式的警告而失败
make -k check
make install
rm -fv /usr/lib/libltdl.a
安装GDBM
GDBM 软件包包含 GNU 数据库管理器。它是一个使用可扩展散列的数据库函数库,功能类似于标准的 UNIX dbm。该库提供用于存储键值对、通过键搜索和获取数据,以及删除键和对应数据的原语。
cd /sources
gdbm_VERSION=1.24
tar xf gdbm-${gdbm_VERSION}.tar.gz
cd gdbm-${gdbm_VERSION}
./configure --prefix=/usr \
--disable-static \
--enable-libgdbm-compat
make
make check
make install
安装Gperf
Gperf 根据一组键值,生成完美散列函数
cd /sources
gperf_VERSION=3.1
tar xf gperf-${gperf_VERSION}.tar.gz
cd gperf-${gperf_VERSION}
./configure --prefix=/usr --docdir=/usr/share/doc/gperf-${gperf_VERSION}
make
make -j1 check
make install
安装Expat
Expat 软件包包含用于解析 XML 文件的面向流的 C 语言库
cd /sources
expat_VERSION=2.6.4
tar xf expat-${expat_VERSION}.tar.xz
cd expat-${expat_VERSION}
./configure --prefix=/usr \
--disable-static \
--docdir=/usr/share/doc/expat-${expat_VERSION}
make
make check
make install
# 安装文档(可选)
install -v -m644 doc/*.{html,css} /usr/share/doc/expat-${expat_VERSION}
安装Inetutils
Inetutils 软件包包含基本网络程序
cd /sources
inetutils_VERSION=2.5
tar xf inetutils-${inetutils_VERSION}.tar.xz
cd inetutils-${inetutils_VERSION}
# 使得该软件包能够用 gcc-14.1 或更新版本构建
sed -i 's/def HAVE_TERMCAP_TGETENT/ 1/' telnet/telnet.c
./configure --prefix=/usr \
--bindir=/usr/bin \
--localstatedir=/var \
--disable-logger \
--disable-whois \
--disable-rcp \
--disable-rexec \
--disable-rlogin \
--disable-rsh \
--disable-servers
make
make check
make install
mv -v /usr/{,s}bin/ifconfig
安装less
Less 软件包包含一个文本文件查看器
cd /sources
less_VERSION=661
tar xf less-${less_VERSION}.tar.gz
cd less-${less_VERSION}
./configure --prefix=/usr --sysconfdir=/etc
make
# 我执行测试过程有2个错误
make check
make install
安装Perl
cd /sources
perl_VERSION=5.40
tar xf perl-${perl_VERSION}.0.tar.xz
cd perl-${perl_VERSION}.0
# 使得 Perl 使用已经安装到系统上的库
export BUILD_ZLIB=False
export BUILD_BZIP2=0
sh Configure -des \
-D prefix=/usr \
-D vendorprefix=/usr \
-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 \
-D man1dir=/usr/share/man/man1 \
-D man3dir=/usr/share/man/man3 \
-D pager="/usr/bin/less -isR" \
-D useshrplib \
-D usethreads
make
# 测试编译结果
TEST_JOBS=$(nproc) make test_harness
make install
unset BUILD_ZLIB BUILD_BZIP2
安装XML::Parser
XML::Parser 模块是 James Clark 的 XML 解析器 Expat 的 Perl 接口
cd /sources
xml_parser_VERSION=2.47
tar xf XML-Parser-${xml_parser_VERSION}.tar.gz
cd XML-Parser-${xml_parser_VERSION}
perl Makefile.PL
make
make test
make install
安装Intltool
Intltool 是一个从源代码文件中提取可翻译字符串的国际化工具
cd /sources
intltool_VERSION=0.51.0
tar xf intltool-${intltool_VERSION}.tar.gz
cd intltool-${intltool_VERSION}
# 修复由 perl-5.22 及更新版本导致的警告
sed -i 's:\\\${:\\\$\\{:' intltool-update.in
./configure --prefix=/usr
make
make check
make install
install -v -Dm644 doc/I18N-HOWTO /usr/share/doc/intltool-${intltool_VERSION}/I18N-HOWTO
安装Autoconf
Autoconf 软件包包含生成能自动配置软件包的 shell 脚本的程序
cd /sources
autoconf_VERSION=2.72
tar xf autoconf-${autoconf_VERSION}.tar.xz
cd autoconf-${autoconf_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Automake
Automake 软件包包含自动生成 Makefile,以便和 Autoconf 一同使用的程序
cd /sources
automake_VERSION=1.17
tar xf automake-${automake_VERSION}.tar.xz
cd automake-${automake_VERSION}
./configure --prefix=/usr --docdir=/usr/share/doc/automake-${automake_VERSION}
make
# 由于测试点内部的时延,使用四个并行任务能提高测试速度,即使系统的逻辑 CPU 核心数较小
make -j$(($(nproc)>4?$(nproc):4)) check
make install
安装OpenSSL
OpenSSL 软件包包含密码学相关的管理工具和库。它们被用于向其他软件包提供密码学功能,例如 OpenSSH,电子邮件程序和 Web 浏览器 (以访问 HTTPS 站点)。
cd /sources
openssl_VERSION=3.3.1
tar xf openssl-${openssl_VERSION}.tar.gz
cd openssl-${openssl_VERSION}
./config --prefix=/usr \
--openssldir=/etc/ssl \
--libdir=lib \
shared \
zlib-dynamic
make
# 一项名为 30-test_afalg.t 的测试失败可忽略(和Host内核没有启用提供CONFIG_CRYPTO_USER_API_SKCIPHER,AES-CBC 模式加密实现的选项相关)
# 我的实践测试 70-test_key_share.t 失败
HARNESS_JOBS=$(nproc) make test
# 安装
sed -i '/INSTALL_LIBS/s/libcrypto.a libssl.a//' Makefile
make MANSUFFIX=ssl install
# 版本号添加到文档目录名,以和其他软件包保持一致
mv -v /usr/share/doc/openssl /usr/share/doc/openssl-${openssl_VERSION}
# 安装一些额外的文档(可选)
cp -vfr doc/* /usr/share/doc/openssl-${openssl_VERSION}
安装Kmod
Kmod 软件包包含用于加载内核模块的库和工具
cd /sources
kmod_VERSION=33
tar xf kmod-${kmod_VERSION}.tar.xz
cd kmod-${kmod_VERSION}
./configure --prefix=/usr \
--sysconfdir=/etc \
--with-openssl \
--with-xz \
--with-zstd \
--with-zlib \
--disable-manpages
make
make install
# 重新创建一些用于和 Module-Init-Tools (曾用于处理 Linux 内核模块的软件包) 相兼容的符号链接
for target in depmod insmod modinfo modprobe rmmod; do
ln -sfv ../bin/kmod /usr/sbin/$target
rm -fv /usr/bin/$target
done
安装Elfutils中的Libelf
Libelf 是一个处理 ELF (可执行和可链接格式) 文件的库
cd /sources
elfutils_VERSION=0.191
tar xf elfutils-${elfutils_VERSION}.tar.bz2
cd elfutils-${elfutils_VERSION}
./configure --prefix=/usr \
--disable-debuginfod \
--enable-libdebuginfod=dummy
make
# 我的测试显示有9个失败
make check
# 只安装 Libelf
make -C libelf install
install -vm644 config/libelf.pc /usr/lib/pkgconfig
rm /usr/lib/libelf.a
安装Libffi
Libffi 库提供一个可移植的高级编程接口,用于处理不同调用惯例。这允许程序在运行时调用任何给定了调用接口的函数。
FFI 是 Foreign Function Interface (跨语言函数接口) 的缩写。FFI 允许使用某种编程语言编写的程序调用其他语言编写的程序。特别地,Libffi 为 Perl 或 Python 等解释器提供使用 C 或 C++ 编写的共享库中子程序的能力。
cd /sources
libffi_VERSION=3.4.6
tar xf libffi-${libffi_VERSION}.tar.gz
cd libffi-${libffi_VERSION}
./configure --prefix=/usr \
--disable-static \
--with-gcc-arch=native
make
make check
make install
安装Python
Python 3 软件包包含 Python 开发环境。它被用于面向对象编程,编写脚本,为大型程序建立原型,或者开发完整的应用。Python 是一种解释性的计算机语言。
cd /sources
python_VERSION=3.12.5
tar xf Python-${python_VERSION}.tar.xz
cd Python-${python_VERSION}
./configure --prefix=/usr \
--enable-shared \
--with-system-expat \
--enable-optimizations
make
# 这里限制测试最长运行实践是一些测试偶然会陷入无限等待状态
# Total test files: run=493/489 failed=7 skipped=28 resource_denied=3 rerun=7
make test TESTOPTS="--timeout 120"
make install
# 避免LFS引导并配置网络后出现指示用户泗洪PyPi提供的pip3(因为LFS将pip3作为Python 3的一部分所以不应该单独升级pip3)
cat > /etc/pip.conf << EOF
[global]
root-user-action = ignore
disable-pip-version-check = true
EOF
# 安装预先格式化的文档(可选)
install -v -dm755 /usr/share/doc/python-${python_VERSION}/html
tar --no-same-owner \
-xvf ../python-${python_VERSION}-docs-html.tar.bz2
cp -R --no-preserve=mode python-${python_VERSION}-docs-html/* \
/usr/share/doc/python-${python_VERSION}/html
安装Flit-Core
Flit-core 是 Flit (一个用于简单的 Python 模块的打包工具) 中用于为发行版进行构建的组件
cd /sources
flit_core_VERSION=3.9.0
tar xf flit_core-${flit_core_VERSION}.tar.gz
cd flit_core-${flit_core_VERSION}
pip3 wheel -w dist --no-cache-dir --no-build-isolation --no-deps $PWD
pip3 install --no-index --no-user --find-links dist flit_core
安装Wheel
Wheel 是 Python wheel 软件包标准格式的参考实现
cd /sources
wheel_VERSION=0.44.0
tar xf wheel-${wheel_VERSION}.tar.gz
cd wheel-${wheel_VERSION}
pip3 wheel -w dist --no-cache-dir --no-build-isolation --no-deps $PWD
pip3 install --no-index --find-links=dist wheel
安装Setuptools
Setuptools 是一个用于下载、构建、安装、升级,以及卸载 Python 软件包的工具
cd /sources
setuptools_VERSION=72.2.0
tar xf setuptools-${setuptools_VERSION}.tar.gz
cd setuptools-${setuptools_VERSION}
pip3 wheel -w dist --no-cache-dir --no-build-isolation --no-deps $PWD
pip3 install --no-index --find-links dist setuptools
安装Ninja
Ninja 是一个注重速度的小型构建系统
cd /sources
ninja_VERSION=1.12.1
tar xf ninja-${ninja_VERSION}.tar.gz
cd ninja-${ninja_VERSION}
# 由于默认ninja最大进程数是系统CPU核心数+2可能导致系统过载,所以可以通过环境变量来限制并行进程数
export NINJAJOBS=4
sed -i '/int Guess/a \
int j = 0;\
char* jobs = getenv( "NINJAJOBS" );\
if ( jobs != NULL ) j = atoi( jobs );\
if ( j > 0 ) return j;\
' src/ninja.cc
# 构建Ninja
python3 configure.py --bootstrap
# 安装软件包
install -vm755 ninja /usr/bin/
install -vDm644 misc/bash-completion /usr/share/bash-completion/completions/ninja
install -vDm644 misc/zsh-completion /usr/share/zsh/site-functions/_ninja
安装Meson
Meson 是一个开放源代码构建系统,它的设计保证了非常快的执行速度,和尽可能高的用户友好性。
cd /sources
meson_VERSION=1.5.1
tar xf meson-${meson_VERSION}.tar.gz
cd meson-${meson_VERSION}
pip3 wheel -w dist --no-cache-dir --no-build-isolation --no-deps $PWD
pip3 install --no-index --find-links dist meson
install -vDm644 data/shell-completions/bash/meson /usr/share/bash-completion/completions/meson
install -vDm644 data/shell-completions/zsh/_meson /usr/share/zsh/site-functions/_meson
安装Coreutils
Coreutils 软件包包含各种操作系统都需要提供的基本工具程序
cd /sources
coreutils_VERSION=9.5
tar xf coreutils-${coreutils_VERSION}.tar.xz
cd coreutils-${coreutils_VERSION}
# POSIX 要求 Coreutils 中的程序即使在多字节 locale 中也能正确识别字符边界。下面应用一个补丁,以解决 Coreutils 不满足该要求的问题,并修复其他一些国际化相关的 bug
patch -Np1 -i ../coreutils-${coreutils_VERSION}-i18n-2.patch
autoreconf -fiv
FORCE_UNSAFE_CONFIGURE=1 ./configure \
--prefix=/usr \
--enable-no-install-program=kill,uptime
make
# 先运行为root用户运行设计的测试
make NON_ROOT_USERNAME=tester check-root
# 再运行tester用户身份的其余测试
groupadd -g 102 dummy -U tester
chown -R tester .
su tester -c "PATH=$PATH make -k RUN_EXPENSIVE_TESTS=yes check" \
< /dev/null
groupdel dummy
make install
mv -v /usr/bin/chroot /usr/sbin
mv -v /usr/share/man/man1/chroot.1 /usr/share/man/man8/chroot.8
sed -i 's/"1"/"8"/' /usr/share/man/man8/chroot.8
安装Check
Check 是一个 C 语言单元测试框架
cd /sources
check_VERSION=0.15.2
tar xf check-${check_VERSION}.tar.gz
cd check-${check_VERSION}
./configure --prefix=/usr --disable-static
make
make check
make docdir=/usr/share/doc/check-${check_VERSION} install
安装Diffutils
Diffutils 软件包包含显示文件或目录之间差异的程序
cd /sources
diffutils_VERSION=3.10
tar xf diffutils-${diffutils_VERSION}.tar.xz
cd diffutils-${diffutils_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Gawk
Gawk 软件包包含操作文本文件的程序
cd /sources
gawk_VERSION=5.3.0
tar xf gawk-${gawk_VERSION}.tar.xz
cd gawk-${gawk_VERSION}
# 确保不安装某些不需要的文件
sed -i 's/extras//' Makefile.in
./configure --prefix=/usr
make
# 测试
chown -R tester .
su tester -c "PATH=$PATH make check"
# 安装
rm -f /usr/bin/gawk-${gawk_VERSION}
make install
安装Findutils
Findutils 软件包包含用于查找文件的程序。这些程序能直接搜索目录树中的所有文件,也可以创建、维护和搜索文件数据库 (一般比递归搜索快,但在数据库最近没有更新时不可靠)。Findutils 还提供了 xargs 程序,它能够对一次搜索列出的所有文件执行给定的命令。
cd /sources
findutils_VERSION=4.10.0
tar xf findutils-${findutils_VERSION}.tar.xz
cd findutils-${findutils_VERSION}
./configure --prefix=/usr --localstatedir=/var/lib/locate
make
chown -R tester .
su tester -c "PATH=$PATH make check"
make install
安装Groff
Groff 软件包包含处理和格式化文本和图像的程序
cd /sources
groff_VERSION=1.23.0
tar xf groff-${groff_VERSION}.tar.gz
cd groff-${groff_VERSION}
PAGE=A4 ./configure --prefix=/usr
make
make check
make install
安装GRUB
GRUB 软件包包含 “大统一” (GRand Unified) 启动引导器。
警告
如果系统支持UEFI,并且希望使用UEFI来引导LFS,则需要按照BLFS的说明,安装支持UEFI的GRUB(以及依赖项)。所以,可以跳过安装BRUB,或者同时安装GRUB和BLFS中为UEFI提供的GRUB包,并使两者互补干扰(BLFS页面提供了两种方案分别的操作。
备注
由于我的服务器使用了UEFI,所以我跳过这步,直接使用 BLFS: GRUB-2.12 for EFI
安装GRUB for EFI
安装FreeTuype(GRUB依赖)
cd /sources
freetype_VERSION=2.13.3
tar xf freetype-${freetype_VERSION}.tar.xz
cd freetype-${freetype_VERSION}
sed -ri "s:.*(AUX_MODULES.*valid):\1:" modules.cfg &&
sed -r "s:.*(#.*SUBPIXEL_RENDERING) .*:\1:" \
-i include/freetype/config/ftoption.h &&
./configure --prefix=/usr --enable-freetype-config --disable-static &&
make
make install
安装GRUB
# 准备字体
cd /sources
wget https://unifoundry.com/pub/unifont/unifont-15.1.05/font-builds/unifont-15.1.05.pcf.gz
grub_VERSION=2.12
tar xf grub-${grub_VERSION}.tar.xz
cd grub-${grub_VERSION}
mkdir -pv /usr/share/fonts/unifont &&
gunzip -c ../unifont-15.1.05.pcf.gz > /usr/share/fonts/unifont/unifont.pcf
# 添加一个缺失的文件到tar包
echo depends bli part_gpt > grub-core/extra_deps.lst
./configure --prefix=/usr \
--sysconfdir=/etc \
--disable-efiemu \
--enable-grub-mkfont \
--with-platform=efi \
--target=x86_64 \
--disable-werror &&
unset TARGET_CC &&
make
make install
mv -v /etc/bash_completion.d/grub /usr/share/bash-completion/completions
安装Gzip
Gzip 软件包包含压缩和解压缩文件的程序
cd /sources
gzip_VERSION=1.13
tar xf gzip-${gzip_VERSION}.tar.xz
cd gzip-${gzip_VERSION}
./configure --prefix=/usr
make
make check
make install
安装IPRoute2
IPRoute2 软件包包含基于 IPv4 的基本和高级网络程序
cd /sources
iproute2_VERSION=6.10.0
tar xf iproute2-${iproute2_VERSION}.tar.xz
cd iproute2-${iproute2_VERSION}
# arpd依赖LFS不安装的Bekeley DB,因此不会被构建。然而,用于 arpd 的一个目录和它的手册页仍会被安装。运行以下命令以防止它们的安装
sed -i /ARPD/d Makefile
rm -fv man/man8/arpd.8
#编译
make NETNS_RUN_DIR=/run/netns
#安装
make SBINDIR=/usr/sbin install
#安装文档(可选)
mkdir -pv /usr/share/doc/iproute2-${iproute2_VERSION}
cp -v COPYING README* /usr/share/doc/iproute2-${iproute2_VERSION}
安装Kbd
Kbd 软件包包含按键表文件、控制台字体和键盘工具
cd /sources
kbd_VERSION=2.6.4
tar xf kbd-${kbd_VERSION}.tar.xz
cd kbd-${kbd_VERSION}
# 退格和删除键的行为在 Kbd 软件包的不同按键映射中不一致。以下补丁修复 i386 按键映射中的这个问题
patch -Np1 -i ../kbd-2.6.4-backspace-1.patch
# 删除多余的 resizecons 程序 (它需要已经不存在的 svgalib 提供视频模式文件 —— 一般使用 setfont 即可调整控制台大小) 及其手册页
sed -i '/RESIZECONS_PROGS=/s/yes/no/' configure
sed -i 's/resizecons.8 //' docs/man/man8/Makefile.in
./configure --prefix=/usr --disable-vlock
make
make check
make install
安装Libpipeline
Libpipeline 软件包包含用于灵活、方便地处理子进程流水线的库
cd /sources
libpipeline_VERSION=1.5.7
tar xf libpipeline-${libpipeline_VERSION}.tar.gz
cd libpipeline-${libpipeline_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Make
Make 软件包包含一个程序,用于控制从软件包源代码生成可执行文件和其他非源代码文件的过程。
cd /sources
make_VERSION=4.4.1
tar xf make-${make_VERSION}.tar.gz
cd make-${make_VERSION}
./configure --prefix=/usr
make
chown -R tester .
su tester -c "PATH=$PATH make check"
make install
安装Path
Patch 软件包包含通过应用 “补丁” 文件,修改或创建文件的程序,补丁文件通常是 diff 程序创建的。
cd /sources
patch_VERSION=2.7.6
tar xf patch-${patch_VERSION}.tar.xz
cd patch-${patch_VERSION}
./configure --prefix=/usr
make
make check
make install
安装Tar
Tar 软件包提供创建 tar 归档文件,以及对归档文件进行其他操作的功能。Tar 可以对已经创建的归档文件进行提取文件,存储新文件,更新文件,或者列出文件等操作。
cd /sources
tar_VERSION=1.35
tar xf tar-${tar_VERSION}.tar.xz
cd tar-${tar_VERSION}
FORCE_UNSAFE_CONFIGURE=1 \
./configure --prefix=/usr
make
make check
make install
make -C doc install-html docdir=/usr/share/doc/tar-${tar_VERSION}
安装Texinfo
Texinfo 软件包包含阅读、编写和转换 info 页面的程序
cd /sources
texinfo_VERSION=7.1
tar xf texinfo-${texinfo_VERSION}.tar.xz
cd texinfo-${texinfo_VERSION}
./configure --prefix=/usr
make
make check
make install
# 安装Tex环境组件(可选)
make TEXMF=/usr/share/texmf install-tex
安装vim
cd /sources
vim_VERSION=9.1.0660
tar xf vim-${vim_VERSION}.tar.gz
cd vim-${vim_VERSION}
# 修改vimrc默认配置位于 /etc
echo '#define SYS_VIMRC_FILE "/etc/vimrc"' >> src/feature.h
./configure --prefix=/usr
make
chown -R tester .
su tester -c "TERM=xterm-256color LANG=en_US.UTF-8 make -j1 test" \
&> vim-test.log
make install
ln -sv vim /usr/bin/vi
for L in /usr/share/man/{,*/}man1/vim.1; do
ln -sv vim.1 $(dirname $L)/vi.1
done
安装MarkupSafe
MarkupSafe 是一个为 XML/HTML/XHTML 标记语言实现字符串安全处理的 Python 模块。
cd /sources
markupsafe_VERSION=2.1.5
tar xf MarkupSafe-${markupsafe_VERSION}.tar.gz
cd MarkupSafe-${markupsafe_VERSION}
pip3 wheel -w dist --no-cache-dir --no-build-isolation --no-deps $PWD
pip3 install --no-index --no-user --find-links dist Markupsafe
安装Jinja2
Jinja2 是一个实现了简单的,Python 风格的模板语言的 Python 模块
cd /sources
jinja2_VERSION=3.1.4
tar xf jinja2-${jinja2_VERSION}.tar.gz
cd jinja2-${jinja2_VERSION}
pip3 wheel -w dist --no-cache-dir --no-build-isolation --no-deps $PWD
pip3 install --no-index --no-user --find-links dist Jinja2
Systemd-256.4 中的 Udev
Udev 软件包包含动态创建设备节点的程序。安装的只是 systemd-256.4 软件包的一部分 ,所以使用 systemd-256.4.tar.xz 作为源代码包
cd /sources
systemd_VERSION=256.4
tar xf systemd-${systemd_VERSION}.tar.gz
cd systemd-${systemd_VERSION}
# 从默认的 udev 规则中删除不必要的组 render 和 sgx
sed -i -e 's/GROUP="render"/GROUP="video"/' \
-e 's/GROUP="sgx", //' rules.d/50-udev-default.rules.in
# 删除一条需要完整安装 Systemd 的 udev 规则
sed '/systemd-sysctl/s/^/#/' -i rules.d/99-systemd.rules.in
# 调整硬编码的网络配置文件路径,使之适合单独安装 udev
sed '/NETWORK_DIRS/s/systemd/udev/' -i src/basic/path-lookup.h
mkdir -p build
cd build
meson setup .. \
--prefix=/usr \
--buildtype=release \
-D mode=release \
-D dev-kvm-mode=0660 \
-D link-udev-shared=false \
-D logind=false \
-D vconsole=false
# 获取软件包提供的 udev 辅助程序列表并将其保存到环境变量中 (实际上并不需要导出该变量,但这使得以非特权用户身份进行构建或使用包管理器更容易):
export udev_helpers=$(grep "'name' :" ../src/udev/meson.build | \
awk '{print $3}' | tr -d ",'" | grep -v 'udevadm')
# 只构建 udev 需要的组件
ninja udevadm systemd-hwdb \
$(ninja -n | grep -Eo '(src/(lib)?udev|rules.d|hwdb.d)/[^ ]*') \
$(realpath libudev.so --relative-to .) \
$udev_helpers
# 安装
install -vm755 -d {/usr/lib,/etc}/udev/{hwdb.d,rules.d,network}
install -vm755 -d /usr/{lib,share}/pkgconfig
install -vm755 udevadm /usr/bin/
install -vm755 systemd-hwdb /usr/bin/udev-hwdb
ln -svfn ../bin/udevadm /usr/sbin/udevd
cp -av libudev.so{,*[0-9]} /usr/lib/
install -vm644 ../src/libudev/libudev.h /usr/include/
install -vm644 src/libudev/*.pc /usr/lib/pkgconfig/
install -vm644 src/udev/*.pc /usr/share/pkgconfig/
install -vm644 ../src/udev/udev.conf /etc/udev/
install -vm644 rules.d/* ../rules.d/README /usr/lib/udev/rules.d/
install -vm644 $(find ../rules.d/*.rules \
-not -name '*power-switch*') /usr/lib/udev/rules.d/
install -vm644 hwdb.d/* ../hwdb.d/{*.hwdb,README} /usr/lib/udev/hwdb.d/
install -vm755 $udev_helpers /usr/lib/udev
install -vm644 ../network/99-default.link /usr/lib/udev/network
# 安装一些在 LFS 环境中很有用的自定义规则和支持文件
tar -xvf ../../udev-lfs-20230818.tar.xz
make -f udev-lfs-20230818/Makefile.lfs install
# 安装手册页
tar -xf ../../systemd-man-pages-256.4.tar.xz \
--no-same-owner --strip-components=1 \
-C /usr/share/man --wildcards '*/udev*' '*/libudev*' \
'*/systemd.link.5' \
'*/systemd-'{hwdb,udevd.service}.8
sed 's|systemd/network|udev/network|' \
/usr/share/man/man5/systemd.link.5 \
> /usr/share/man/man5/udev.link.5
sed 's/systemd\(\\\?-\)/udev\1/' /usr/share/man/man8/systemd-hwdb.8 \
> /usr/share/man/man8/udev-hwdb.8
sed 's|lib.*udevd|sbin/udevd|' \
/usr/share/man/man8/systemd-udevd.service.8 \
> /usr/share/man/man8/udevd.8
rm /usr/share/man/man*/systemd*
# 最后,移除 udev_helpers 变量
unset udev_helpers
# 硬件设备的相关信息被维护在 /etc/udev/hwdb.d 和 /usr/lib/udev/hwdb.d 目录中。Udev 需要将这些信息编译到二进制数据库 /etc/udev/hwdb.bin 中。初始化该数据库
udev-hwdb update
# 每次硬件信息有更新时,都要运行该命令
安装Man-DB
Man-DB 软件包包含查找和阅读手册页的程序
cd /sources
man_db_VERSION=2.12.1
tar xf man-db-${man_db_VERSION}.tar.xz
cd man-db-${man_db_VERSION}
./configure --prefix=/usr \
--docdir=/usr/share/doc/man-db-${man_db_VERSION} \
--sysconfdir=/etc \
--disable-setuid \
--enable-cache-owner=bin \
--with-browser=/usr/bin/lynx \
--with-vgrind=/usr/bin/vgrind \
--with-grap=/usr/bin/grap \
--with-systemdtmpfilesdir= \
--with-systemdsystemunitdir=
make
make check
make install
安装Procps-ng
Procps-ng 软件包包含监视进程的程序
cd /sources
procps_ng_VERSION=4.0.4
tar xf procps-ng-${procps_ng_VERSION}.tar.xz
cd procps-ng-${procps_ng_VERSION}
# --disable-kill 该选项使得 kill 命令不被构建;它将由 Util-linux 软件包提供
./configure --prefix=/usr \
--docdir=/usr/share/doc/procps-ng-${procps_ng_VERSION} \
--disable-static \
--disable-kill
make
chown -R tester .
su tester -c "PATH=$PATH make check"
make install
安装Util-linux
Util-linux 软件包包含若干工具程序。这些程序中有处理文件系统、终端、分区和消息的工具
cd /sources
util_linux_VERSION=2.40.2
tar xf util-linux-${util_linux_VERSION}.tar.xz
cd util-linux-${util_linux_VERSION}
# --disable 和 --without 选项防止一些警告,它们与那些需要 LFS 中不存在的依赖项,或者和其他软件包安装的程序不兼容的组件的构建过程相关。
./configure --bindir=/usr/bin \
--libdir=/usr/lib \
--runstatedir=/run \
--sbindir=/usr/sbin \
--disable-chfn-chsh \
--disable-login \
--disable-nologin \
--disable-su \
--disable-setpriv \
--disable-runuser \
--disable-pylibmount \
--disable-liblastlog2 \
--disable-static \
--without-python \
--without-systemd \
--without-systemdsystemunitdir \
ADJTIME_PATH=/var/lib/hwclock/adjtime \
--docdir=/usr/share/doc/util-linux-${util_linux_VERSION}
make
# 警告: 这里不可以用root身份运行测试套件,可能会损害系统
touch /etc/fstab
chown -R tester .
su tester -c "make -k check"
make install
安装E2fsprogs
E2fsprogs 软件包包含处理 ext2 文件系统的工具。此外它也支持 ext3 和 ext4 日志文件系统。
cd /sources
e2fsprogs_VERSION=1.47.1
tar xf e2fsprogs-${e2fsprogs_VERSION}.tar.gz
cd e2fsprogs-${e2fsprogs_VERSION}
mkdir -v build
cd build
# --disable-*
这些选项防止构建和安装 libuuid 和 libblkid 库,uuidd 守护程序,以及 fsck 包装器;因为 Util-linux 会安装更新的版本。
../configure --prefix=/usr \
--sysconfdir=/etc \
--enable-elf-shlibs \
--disable-libblkid \
--disable-libuuid \
--disable-uuidd \
--disable-fsck
make
make check
make install
rm -fv /usr/lib/{libcom_err,libe2p,libext2fs,libss}.a
gunzip -v /usr/share/info/libext2fs.info.gz
install-info --dir-file=/usr/share/info/dir /usr/share/info/libext2fs.info
安装Sysklogd
Sysklogd 软件包包含记录系统消息 (例如在意外情况发生时内核输出的消息) 的程序
cd /sources
sysklogd_VERSION=2.6.1
tar xf sysklogd-${sysklogd_VERSION}.tar.gz
cd sysklogd-${sysklogd_VERSION}
./configure --prefix=/usr \
--sysconfdir=/etc \
--runstatedir=/run \
--without-logger
make
make install
安装SysVinit
SysVinit 软件包包含控制系统启动、运行和关闭的程序
cd /sources
sysvinit_VERSION=3.10
tar xf sysvinit-${sysvinit_VERSION}.tar.xz
cd sysvinit-${sysvinit_VERSION}
patch -Np1 -i ../sysvinit-3.10-consolidated-1.patch
make
make install
调试符号
许多程序和库在默认情况下被编译为带有调试符号的二进制文件 (通过使用 gcc 的 -g 选项)。这意味着在调试这些带有调试信息的程序和库时,调试器不仅能给出内存地址,还能给出子程序和变量的名称。
但是包含这些调试符号会显著增大程序或库的体积。移除调试符号的程序通常比移除调试符号前小 50% 到 80%。由于大多数用户永远不会用调试器调试系统软件,可以通过移除它们的调试符号,回收大量磁盘空间。
移除调试符号(可选)
本节是可选的。如果系统不是为程序员设计的,也没有调试系统软件的计划,可以通过从二进制程序和库移除调试符号和不必要的符号表项,将系统的体积减小约 2 GB。对于一般的 Linux 用户,这不会造成任何不便。
大多数使用以下命令的用户不会遇到什么困难。但是,如果打错了命令,很容易导致新系统无法使用。因此,在运行 strip 命令前,最好备份 LFS 系统的当前状态。
strip
命令的 --strip-unneeded
选项从程序或库中移除所有调试符号。它也会移除所有链接器 (对于静态库) 或动态链接器 (对于动态链接的程序和共享库) 不需要的符号表项。
需要注意的是,strip 命令会覆盖它正在处理的二进制程序或库文件。这可能导致正在使用该文件中代码或数据的进程崩溃。如果运行 strip 的进程受到影响,则可能导致正在被处理的程序或库完全损坏;这可能导致系统完全不可用。为了避免这种情况,将一些库和程序复制到 /tmp 中,在那里移除调试符号,再使用 install 命令重新安装它们。
save_usrlib="$(cd /usr/lib; ls ld-linux*[^g])
libc.so.6
libthread_db.so.1
libquadmath.so.0.0.0
libstdc++.so.6.0.33
libitm.so.1.0.0
libatomic.so.1.2.0"
cd /usr/lib
for LIB in $save_usrlib; do
objcopy --only-keep-debug --compress-debug-sections=zlib $LIB $LIB.dbg
cp $LIB /tmp/$LIB
strip --strip-unneeded /tmp/$LIB
objcopy --add-gnu-debuglink=$LIB.dbg /tmp/$LIB
install -vm755 /tmp/$LIB /usr/lib
rm /tmp/$LIB
done
online_usrbin="bash find strip"
online_usrlib="libbfd-2.43.1.so
libsframe.so.1.0.0
libhistory.so.8.2
libncursesw.so.6.5
libm.so.6
libreadline.so.8.2
libz.so.1.3.1
libzstd.so.1.5.6
$(cd /usr/lib; find libnss*.so* -type f)"
for BIN in $online_usrbin; do
cp /usr/bin/$BIN /tmp/$BIN
strip --strip-unneeded /tmp/$BIN
install -vm755 /tmp/$BIN /usr/bin
rm /tmp/$BIN
done
for LIB in $online_usrlib; do
cp /usr/lib/$LIB /tmp/$LIB
strip --strip-unneeded /tmp/$LIB
install -vm755 /tmp/$LIB /usr/lib
rm /tmp/$LIB
done
for i in $(find /usr/lib -type f -name \*.so* ! -name \*dbg) \
$(find /usr/lib -type f -name \*.a) \
$(find /usr/{bin,sbin,libexec} -type f); do
case "$online_usrbin $online_usrlib $save_usrlib" in
*$(basename $i)* )
;;
* ) strip --strip-unneeded $i
;;
esac
done
unset BIN LIB save_usrlib online_usrbin online_usrlib
备注
我的实践,在没有移除调试符号之前 /
根目录使用了 1.7G
空间,移除调试后, /
根目录使用 1.4G
空间,减少了300MB
清理系统
清理系统:
# 清理在执行测试的过程中遗留的一些文件
rm -rf /tmp/{*,.*}
# 清理不使用的 libtool 归档文件(在 /usr/lib 和 /usr/libexec 目录中还有一些扩展名为 .la 的文件)
find /usr/lib /usr/libexec -name \*.la -delete
# 清理不需要的构建过程的编译器
find /usr -depth -name $(uname -m)-lfs-linux-gnu\* | xargs rm -rf
# 移除tester账户
userdel -r tester