今天老师要求我构造一个基于x86_64架构的LFS,于是在此记录一下构建过程。
LFS手册链接:https://lfs.xry111.site/zh_CN/
环境配置
强烈建议仔细读LFS手册,手册内容还是很简单明了的
这里就直入主题了,我的宿主机配置如下:

准备宿主系统
我将从2.2. 宿主系统需求开始,首先需要检查宿主机的软件包情况,脚本如下:
# A script to list version numbers of critical development tools
# If you have tools installed in other directories, adjust PATH here AND
# in ~lfs/.bashrc (section 4.4) as well.
LC_ALL=C
PATH=/usr/bin:/bin
bail() { echo "FATAL: $1"; exit 1; }
grep --version > /dev/null 2> /dev/null || bail "grep does not work"
sed '' /dev/null || bail "sed does not work"
sort /dev/null || bail "sort does not work"
ver_check()
{
if ! type -p $2 &>/dev/null
then
echo "ERROR: Cannot find $2 ($1)"; return 1;
fi
v=$($2 --version 2>&1 | grep -E -o '[0-9]+\.[0-9\.]+[a-z]*' | head -n1)
if printf '%s\n' $3 $v | sort --version-sort --check &>/dev/null
then
printf "OK: %-9s %-6s >= $3\n" "$1" "$v"; return 0;
else
printf "ERROR: %-9s is TOO OLD ($3 or later required)\n" "$1";
return 1;
fi
}
ver_kernel()
{
kver=$(uname -r | grep -E -o '^[0-9\.]+')
if printf '%s\n' $1 $kver | sort --version-sort --check &>/dev/null
then
printf "OK: Linux Kernel $kver >= $1\n"; return 0;
else
printf "ERROR: Linux Kernel ($kver) is TOO OLD ($1 or later required)\n" "$kver";
return 1;
fi
}
# Coreutils first because --version-sort needs Coreutils >= 7.0
ver_check Coreutils sort 8.1 || bail "Coreutils too old, stop"
ver_check Bash bash 3.2
ver_check Binutils ld 2.13.1
ver_check Bison bison 2.7
ver_check Diffutils diff 2.8.1
ver_check Findutils find 4.2.31
ver_check Gawk gawk 4.0.1
ver_check GCC gcc 5.2
ver_check "GCC (C++)" g++ 5.2
ver_check Grep grep 2.5.1a
ver_check Gzip gzip 1.3.12
ver_check M4 m4 1.4.10
ver_check Make make 4.0
ver_check Patch patch 2.5.4
ver_check Perl perl 5.8.8
ver_check Python python3 3.4
ver_check Sed sed 4.1.5
ver_check Tar tar 1.22
ver_check Texinfo texi2any 5.0
ver_check Xz xz 5.0.0
ver_kernel 4.19
if mount | grep -q 'devpts on /dev/pts' && [ -e /dev/ptmx ]
then echo "OK: Linux Kernel supports UNIX 98 PTY";
else echo "ERROR: Linux Kernel does NOT support UNIX 98 PTY"; fi
alias_check() {
if $1 --version 2>&1 | grep -qi $2
then printf "OK: %-4s is $2\n" "$1";
else printf "ERROR: %-4s is NOT $2\n" "$1"; fi
}
echo "Aliases:"
alias_check awk GNU
alias_check yacc Bison
alias_check sh Bash
echo "Compiler check:"
if printf "int main(){}" | g++ -x c++ -
then echo "OK: g++ works";
else echo "ERROR: g++ does NOT work"; fi
rm -f a.out
if [ "$(nproc)" = "" ]; then
echo "ERROR: nproc is not available or it produces empty output"
else
echo "OK: nproc reports $(nproc) logical cores are available"
fi
运行结果如下:
OK: Coreutils 9.4 >= 8.1
OK: Bash 5.2.32 >= 3.2
OK: Binutils 2.43.1 >= 2.13.1
OK: Bison 3.8.2 >= 2.7
OK: Diffutils 3.10 >= 2.8.1
OK: Findutils 4.10.0 >= 4.2.31
OK: Gawk 5.2.1 >= 4.0.1
OK: GCC 14.2.0 >= 5.2
OK: GCC (C++) 14.2.0 >= 5.2
OK: Grep 3.11 >= 2.5.1a
OK: Gzip 1.12 >= 1.3.12
OK: M4 1.4.19 >= 1.4.10
OK: Make 4.3 >= 4.0
OK: Patch 2.7.6 >= 2.5.4
OK: Perl 5.38.2 >= 5.8.8
OK: Python 3.12.6 >= 3.4
OK: Sed 4.9 >= 4.1.5
OK: Tar 1.35 >= 1.22
OK: Texinfo 7.1.1 >= 5.0
OK: Xz 5.6.2 >= 5.0.0
OK: Linux Kernel 6.10.9 >= 4.19
OK: Linux Kernel supports UNIX 98 PTY
Aliases:
OK: awk is GNU
OK: yacc is Bison
OK: sh is Bash
Compiler check:
OK: g++ works
OK: nproc reports 24 logical cores are available
如果出现sh is not Bash
的问题可以手动更改
sudo rm /bin/sh
sudo ln -s /bin/bash /bin/sh
完成环境检查后,接下来是为LFS准备一个分区,手册建议分区的大小为30GB,我这里将使用一个32G的USB作为LFS分区,分区名为/dev/sdc1,因为USB已经存在了一个FAT32分区,所以这里可以直接省略掉用fdisk工具进行分区的操作,直接格式化,将其变为ext4。如果不存在一个分区,,或者想要创建多个分区,则需要用如fdisk之类的分区工具首先进行分区处理
sudo mkfs -v -t ext4 /dev/sdc1
完成格式化后挂载该分区
手册中还给出了多个分区的方案,例如一个分区作为/,另一个作为/home,那么这步需要将这两个分区依次挂载,更详细的内容可以参考2.7. 挂载新的分区。
sudo mkdir /mnt/LFS
sudo mount /dev/sdc1 /mnt/LFS
检查文件系统是否为ext4
df -T
接下来设置环境变量$LFS,这个变量指向了构建LFS时使用的目录,在我的情况中则是/mnt/LFS
,可以用echo $LFS
来检查环境变量是否被正确设置了
注意:可以通过向.bashrc
(或其他类似功能文件)中添加下面的命令来确保环境变量$LFS正确
export LFS=/mnt/LFS
软件包和补丁
接下来是下载软件包和补丁,首先创建一个目录用于存放软件包和补丁
mkdir -v $LFS/sources
然后更改sources
的权限,为该目录添加写入权限和 sticky 标志。
“Sticky” 标志使得即使有多个用户对该目录有写入权限,也只有文件所有者能够删除其中的文件
sudo chmod -v a+wt $LFS/sources
手册提供了一个包括了所有所需软件包的下载列表wget-list-sysv
,下载这个文件,然后将这个文件作为wget
的输入,把所有软件包下载到$LFS/sources
sudo wget --input-file=wget-list-sysv --continue --directory-prefix=$LFS/sources
手册还提供了一个用于检查所下载软件包正确性的md5sums,下面是一个检查正确性的脚本,确保md5sums
在$LFS/sources
目录下
pushd $LFS/sources
md5sum -c md5sums
popd
手册强烈建议以root用户执行这些操作,如果已经以非root用户创建了文件夹或下载了软件包和补丁,可以修改它们的所有者
chown root:root $LFS/sources/*
ls -l # 检查是否更改
如果以非 root 用户身份下载了软件包和补丁,则下载的文件会属于该用户。文件系统使用 UID 记录文件所有者,而宿主系统中普通用户的 UID 在 LFS 中未被分配。因此,这些文件保留到最终的 LFS 系统后,会属于一个没有命名的 UID 。
最后的准备工作
在LFS分区中创建一个目录树
cd $LFS
mkdir -pv $LFS/{etc,var} $LFS/usr/{bin,lib,sbin}
然后在$LFS目录下创建一个脚本,加入下列命令并运行
for i in bin lib sbin; do
sudo ln -sv usr/$i $LFS/$i
done
case $(uname -m) in
x86_64) sudo mkdir -pv $LFS/lib64 ;;
esac
为交叉编译器编译程序等工具创建一个专用目录,与其他程序分离
sudo mkdir -pv $LFS/tools
最后的目录结构应该如下所示
tree $LFS
/mnt/LFS
├── bin -> usr/bin
├── etc
├── lib -> usr/lib
├── lib64
├── lost+found [error opening dir]
├── sbin -> usr/sbin
├── sources
│ ├── acl-2.3.2.tar.xz
│ ├── attr-2.5.2.tar.gz
│ ├── autoconf-2.72.tar.xz
│ ├── automake-1.17.tar.xz
│ ├── bash-5.2.32.tar.gz
│ ├── bc-6.7.6.tar.xz
│ ├── binutils-2.43.1.tar.xz
│ ├── bison-3.8.2.tar.xz
│ ├── bzip2-1.0.8-install_docs-1.patch
│ ├── bzip2-1.0.8.tar.gz
│ ├── check-0.15.2.tar.gz
│ ├── coreutils-9.5-i18n-2.patch
│ ├── coreutils-9.5.tar.xz
│ ├── dejagnu-1.6.3.tar.gz
│ ├── diffutils-3.10.tar.xz
│ ├── e2fsprogs-1.47.1.tar.gz
│ ├── elfutils-0.191.tar.bz2
│ ├── expat-2.6.2.tar.xz
│ ├── expect-5.45.4-gcc14-1.patch
│ ├── expect5.45.4.tar.gz
│ ├── file-5.45.tar.gz
│ ├── findutils-4.10.0.tar.xz
│ ├── flex-2.6.4.tar.gz
│ ├── flit_core-3.9.0.tar.gz
│ ├── gawk-5.3.0.tar.xz
│ ├── gcc-14.2.0.tar.xz
│ ├── gdbm-1.24.tar.gz
│ ├── gettext-0.22.5.tar.xz
│ ├── glibc-2.40-fhs-1.patch
│ ├── glibc-2.40.tar.xz
│ ├── gmp-6.3.0.tar.xz
│ ├── gperf-3.1.tar.gz
│ ├── grep-3.11.tar.xz
│ ├── groff-1.23.0.tar.gz
│ ├── grub-2.12.tar.xz
│ ├── gzip-1.13.tar.xz
│ ├── iana-etc-20240806.tar.gz
│ ├── inetutils-2.5.tar.xz
│ ├── intltool-0.51.0.tar.gz
│ ├── iproute2-6.10.0.tar.xz
│ ├── jinja2-3.1.4.tar.gz
│ ├── kbd-2.6.4-backspace-1.patch
│ ├── kbd-2.6.4.tar.xz
│ ├── kmod-33.tar.xz
│ ├── less-661.tar.gz
│ ├── lfs-bootscripts-20240825.tar.xz
│ ├── libcap-2.70.tar.xz
│ ├── libffi-3.4.6.tar.gz
│ ├── libpipeline-1.5.7.tar.gz
│ ├── libtool-2.4.7.tar.xz
│ ├── libxcrypt-4.4.36.tar.xz
│ ├── linux-6.10.5.tar.xz
│ ├── lz4-1.10.0.tar.gz
│ ├── m4-1.4.19.tar.xz
│ ├── make-4.4.1.tar.gz
│ ├── man-db-2.12.1.tar.xz
│ ├── man-pages-6.9.1.tar.xz
│ ├── MarkupSafe-2.1.5.tar.gz
│ ├── meson-1.5.1.tar.gz
│ ├── mpc-1.3.1.tar.gz
│ ├── mpfr-4.2.1.tar.xz
│ ├── ncurses-6.5.tar.gz
│ ├── ninja-1.12.1.tar.gz
│ ├── openssl-3.3.1.tar.gz
│ ├── patch-2.7.6.tar.xz
│ ├── perl-5.40.0.tar.xz
│ ├── pkgconf-2.3.0.tar.xz
│ ├── procps-ng-4.0.4.tar.xz
│ ├── psmisc-23.7.tar.xz
│ ├── python-3.12.5-docs-html.tar.bz2
│ ├── Python-3.12.5.tar.xz
│ ├── readline-8.2.13.tar.gz
│ ├── sed-4.9.tar.xz
│ ├── setuptools-72.2.0.tar.gz
│ ├── shadow-4.16.0.tar.xz
│ ├── sysklogd-2.6.1.tar.gz
│ ├── systemd-256.4.tar.gz
│ ├── systemd-man-pages-256.4.tar.xz
│ ├── sysvinit-3.10-consolidated-1.patch
│ ├── sysvinit-3.10.tar.xz
│ ├── tar-1.35.tar.xz
│ ├── tcl8.6.14-html.tar.gz
│ ├── tcl8.6.14-src.tar.gz
│ ├── texinfo-7.1.tar.xz
│ ├── tzdata2024a.tar.gz
│ ├── udev-lfs-20230818.tar.xz
│ ├── util-linux-2.40.2.tar.xz
│ ├── vim-9.1.0660.tar.gz
│ ├── wheel-0.44.0.tar.gz
│ ├── XML-Parser-2.47.tar.gz
│ ├── xz-5.6.2.tar.xz
│ ├── zlib-1.3.1.tar.gz
│ └── zstd-1.5.6.tar.gz
├── tools
├── usr
│ ├── bin
│ ├── lib
│ └── sbin
└── var
创建一个新的用户lfs
用于编译软件包,这可以保证建立一个干净的工作环境
sudo groupadd lfs # 创建一个组lfs
sudo useradd -s /bin/bash -g lfs -m -k /dev/null lfs # 创建一个用户lfs
命令行中各选项的含义:
-s /bin/bash
设置 bash 为用户 lfs 的默认 shell。
-g lfs
添加用户 lfs 到组 lfs。
-m
为用户 lfs 创建一个主目录。
-k /dev/null
将模板目录设置为空设备文件,防止从默认模板目录 (/etc/skel) 复制文件到新的主目录。
lfs
这是新用户的名称。
将lfs
设为$LFS
目录的所有者
sudo chown -v lfs $LFS/{usr{,/*},lib,var,etc,bin,sbin,tools}
case $(uname -m) in
x86_64) sudo chown -v lfs $LFS/lib64 ;;
esac
检查更改
ls $LFS -l
drwxr-xr-x 9 root root 4096 Sep 27 20:26 .
drwxr-xr-x 3 root root 4096 Sep 26 23:37 ..
lrwxrwxrwx 1 root root 7 Sep 27 20:13 bin -> usr/bin
drwxr-xr-x 2 lfs root 4096 Sep 27 20:10 etc
lrwxrwxrwx 1 root root 7 Sep 27 20:13 lib -> usr/lib
drwxr-xr-x 2 lfs root 4096 Sep 27 20:13 lib64
drwx------ 2 root root 16384 Sep 26 23:40 lost+found
lrwxrwxrwx 1 root root 8 Sep 27 20:13 sbin -> usr/sbin
drwxrwxrwt 2 root root 4096 Sep 27 20:08 sources
drwxr-xr-x 2 lfs root 4096 Sep 27 20:19 tools
drwxr-xr-x 5 lfs root 4096 Sep 27 20:10 usr
drwxr-xr-x 2 lfs root 4096 Sep 27 20:10 var
最后以lfs
登录
sudo su - lfs
登录后,先为lfs
配置一下环境
cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF
命令的详细含义可以阅读4.4. 配置环境,注意LFS
变量的路径要设置正确,也就是$LFS
的路径
cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/LFS
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/usr/bin
if [ ! -L /bin ]; then PATH=/bin:$PATH; fi
PATH=$LFS/tools/bin:$PATH
CONFIG_SITE=$LFS/usr/share/config.site
export LFS LC_ALL LFS_TGT PATH CONFIG_SITE
EOF
一些商业发行版未做文档说明地将 /etc/bash.bashrc 引入 bash 初始化过程。该文件可能修改 lfs 用户的环境,并影响 LFS 关键软件包的构建。为了保证 lfs 用户环境的纯净,检查 /etc/bash.bashrc 是否存在,如果它存在就将它移走。以 root 用户身份,运行:
[ ! -e /etc/bash.bashrc ] || mv -v /etc/bash.bashrc /etc/bash.bashrc.NOUSE
设置编译时使用的核心数
cat >> ~/.bashrc << "EOF"
export MAKEFLAGS=-j$(nproc)
EOF
运行以确保上面的所有更改能现在就被应用
source ~/.bash_profile