LFS安装基本系统软件

概述

  • LFS不推荐在编译中使用自定义优化:

    • 虽然使用自定义优化编译可能会使程序运行稍快一点,但是由于源代码和编译工具的复杂相互作用,仍然存在编译不正确的风险

    • 除非LFS手册明确说明外,设置 -march-mtune 是未经验证的,可能子啊工具链软件包(binutils,gcc和glibc)中引发问题

    • LFS采用软件包默认配置启用的优化选项,原因是认为软件包维护者已经测试了这些配置并认为他们是安全的,这样不太可能导致构建失败

    • 通常默认配置已经启用了 -O2-O3 ,因此即使不使用任何自定义优化情况下,得到的系统应该仍然会运行很快并保持稳定

  • LFS不建议构建和安装静态库:

    • 在现代 Linux 系统中,多数静态库已经失去存在的意义

    • 将静态库链接到程序中可能是有害的

    • 如果静态库存在安全问题,则需要所有使用这个静态库的程序重新链接到新版本库,这是非常困难的,甚至可能无法查明有哪些程序需要重新链接 (以及如何重新链接)

    • LFS手册在安装过程删除或者禁止安装多数静态库: 通常传递 --disable-static 选项给 configure 来达到这个目的;不过极个别情况,特别是 GlibcGCC ,静态库在一般软件包的构建过程中仍然很关键,就不能禁用静态库

软件包管理

LFS 或 BLFS 不介绍任何包管理器的原因:

  • 处理软件包管理会偏离这两本手册的目标 —— 讲述如何构建 Linux 系统

  • 存在多种软件包管理的解决方案,它们各有优缺点。很难找到一种让所有读者满意的方案

升级问题

  • 内核可以独立升级,不需要重构任何软件包: 内核态与用户态的接口十分清晰;升级内核 不需要 一同更新Linux API头文件

  • Glibc升级需要额外处理以防止损坏系统

  • 如果更新一个包含共享库的软件包,并且共享库的名称发生改变,则所有动态链接到这个库的软件包都要重新编译,以链接到新版本的库。注意,不能删除旧版本的库,直到将所有依赖它的软件包都重新编译完成

  • 如果更新共享库的库文件版本号降低,则需要删除就版本软件包安装的库,这是因为 ldconfig 命令会将符号链接到版本号更大(看起来更"新")的旧版本库。也就是不得不降级软件包或者软件包作者更改库文件版本号格式时,需要注意这个操作。

  • 如果更新包含共享库的软件包,且共享库的名称没有改变,则需要重启所有链接到该库的程序以生效(例如升级ssl库需要重启ssh服务)

  • 如果一个可执行程序或共享库被覆盖,则正在使用该程序或库中代码或数据的进程可能崩溃。解决方法时先删除就版本,再安装新版本。Coreutils提供的 install 已经实现了这个过程,多数软件使用这个安装命令安装二进制文件和库。

跟踪安装程序

使用 strace 能够记录安装脚本执行过程中所有系统调用

警告

从现在开始的操纵是在 chroot 环境中进行,每次ssh登陆到服务器上都需要重新完成 进入 Chroot 并构建其他临时工具 开头部分

所有操作以 root 身份完成,由于是 chroot 之后操作,所以对Host主机没有影响

安装Man-pages

安装Man-pages(手册页是描述 C 语言函数、重要的设备文件以及主要配置文件)
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

安装 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

安装 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

安装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

安装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

安装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

安装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

安装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

安装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

安装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

安装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

安装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

安装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

安装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 环境中正常工作:

返回输出ok则表明PTY在chroot环境工作
python3 -c 'from pty import spawn; spawn(["echo", "ok"])'

如果不正常则需要检查前面虚拟内核文件系统,确认 devpts 文件系统是否正确挂载。并重新进入chroot环境。这是确保Expect测试套件能正常工作,避免产生隐蔽问题。

安装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(工具命令语言):

安装DejaGNU
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 的接替者,用于在软件包安装的配置和生成阶段向构建工具传递头文件或库文件搜索路径的工具。

安装Pkgconf
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

安装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 软件包包含提供任意精度算术函数的数学库

安装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 软件包包含多精度数学函数

安装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 软件包包含一个任意高精度,且舍入正确的复数算术库

安装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 软件包包含管理文件系统对象扩展属性的工具

安装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 软件包包含管理访问控制列表的工具,访问控制列表能够细致地自由定义文件和目录的访问权限

安装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 用户的最高特权分割成的一组不同权限。

安装Libcap
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 软件包包含用于对密码进行单向散列操作的现代化的库

安装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 软件包包含安全地处理密码的程序

安装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
# 如果要对用户密码启用 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++ 编译器

安装GCC
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/

完成后通过以下方式验证确认编译和链接:

检查GCC安装
echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'

输出不应报错,应该显示类似如下结果(不同平台的动态链接器名称可能不同):

检查GCC安装输出
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

确认使用正确的启动文件:

检查GCC使用正确的启动文件
grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log

确认编译器能正确查找头文件:

检查GCC正确查找头文件
grep -B4 '^ /usr/include' dummy.log

确认新的链接器使用了正确的搜索路径:

检查确认新的链接器使用了正确的搜索路径
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'

确认使用了正确的 libc:

确认使用了正确的 lib
grep "/lib.*/libc.so.6 " dummy.log

确认 GCC 使用了正确的动态链接器:

确认 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:

安装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:

安装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 软件包包含显示正在运行的进程信息的程序

安装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 (本地语言支持) 功能,使它们能够以用户的本地语言输出消息

安装Gettext
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 软件包包含语法分析器生成器

安装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 软件包包含在文件内容中进行搜索的程序

安装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

安装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 通用库支持脚本。它提供一致、可移植的接口,以简化共享库的使用

安装Libtool
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。该库提供用于存储键值对、通过键搜索和获取数据,以及删除键和对应数据的原语。

安装GDBM
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 根据一组键值,生成完美散列函数

安装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 语言库

安装Expat
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 软件包包含基本网络程序

安装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 软件包包含一个文本文件查看器

安装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

安装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 接口

安装XML::Parser
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 是一个从源代码文件中提取可翻译字符串的国际化工具

安装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 脚本的程序

安装Autoconf
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 一同使用的程序

安装Automake
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 站点)。

安装OpenSSL
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 软件包包含用于加载内核模块的库和工具

安装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 (可执行和可链接格式) 文件的库

安装Libelf
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++ 编写的共享库中子程序的能力。

安装Libffi
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 是一种解释性的计算机语言。

安装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 模块的打包工具) 中用于为发行版进行构建的组件

安装Flit-Core
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 软件包标准格式的参考实现

安装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 软件包的工具

安装Setuptools
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 是一个注重速度的小型构建系统

安装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 是一个开放源代码构建系统,它的设计保证了非常快的执行速度,和尽可能高的用户友好性。

安装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 软件包包含各种操作系统都需要提供的基本工具程序

安装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 语言单元测试框架

安装Check
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 软件包包含显示文件或目录之间差异的程序

安装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 软件包包含操作文本文件的程序

安装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 程序,它能够对一次搜索列出的所有文件执行给定的命令。

安装Findutils
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 软件包包含处理和格式化文本和图像的程序

安装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依赖)

安装freetype
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

安装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 软件包包含压缩和解压缩文件的程序

安装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 的基本和高级网络程序

安装IPRoute2
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 软件包包含按键表文件、控制台字体和键盘工具

安装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 软件包包含用于灵活、方便地处理子进程流水线的库

安装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 软件包包含一个程序,用于控制从软件包源代码生成可执行文件和其他非源代码文件的过程。

安装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 程序创建的。

安装Patch
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 可以对已经创建的归档文件进行提取文件,存储新文件,更新文件,或者列出文件等操作。

安装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 页面的程序

安装Texinfo
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

安装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 模块。

安装MarkupSafe
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 模块

安装Jinja2
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 作为源代码包

安装Udev
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 软件包包含查找和阅读手册页的程序

安装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 软件包包含监视进程的程序

安装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 软件包包含若干工具程序。这些程序中有处理文件系统、终端、分区和消息的工具

安装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 日志文件系统。

安装E2fsprogs
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 软件包包含记录系统消息 (例如在意外情况发生时内核输出的消息) 的程序

安装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 软件包包含控制系统启动、运行和关闭的程序

安装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

参考