简介

LFS是Linux From Scratch的简称,LFS 存在的一个重要原因是可以帮助人们学习 linux 系统内部是如何工作的。构建一个 LFS 系统会帮助演示是什么使 linux  运转,各种组件如何在一起互相依赖的工作。最好的事情之一通过这种学习可以获得完全根据自己的需求定制 linux 系统的能力。

LFS 的一个关键的好处是它让用户对于系统有更多的控制,而不是依赖于他人的 linux 实现。在 LFS  的世界里,你自己坐在司机的位置,掌控系统的每一个细节,比如目录布局和启动脚本配置等等。你也能掌控在哪里、为何、以及怎样安装每一个程序。有关LFS相关的资料可以去这个链接中查找:http://www.linuxfromscratch.org

环境配置

项目软件CPU内存硬盘网络备注
虚拟机软件VirtualBox7.1.62450+20NAT映射端口访问
宿主机Windows11i3-9100161T

虚拟机系统Debian12



最小化安装
  • 虚拟机 50G 硬盘为 Debian12 的硬盘,20G硬盘为 LFS 的目标硬盘

  1. 参照 https://wiki.waringid.me/x/PgAS 完成 Debian 系统安装和镜像源配置
  2. 将新建用户 lf 加入 sudo 组。usermod -aG sudo lf
  3. 安装基础的开发组件
  4. 检查相关组件是否符合 LFS 项目的要求
sudo apt install -y build-essential vim
sudo apt install -y autoconf automake gdb libffi-dev zlib1g-dev libssl-dev git wget
cat > version-check.sh << "EOF"
#!/bin/bash
# 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 5.4 

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
EOF

sudo bash version-check.sh

针对上述检查结果补齐没有安装的组件

sudo apt install bison gawk texinfo

磁盘分区及格式

20G 为 LFS 的目标磁盘,共分3个区

  • sdb1 规划 300M ,目标格式 ext2 用于挂载启动分区 /boot
  • sdb2 规划 1G,用作交换分区
  • sdb3 规划剩余的空间,分区格式:ext4,挂载根分区

sudo mkfs -v -t ext2 /dev/sdb1
sudo mkswap /dev/sdb2
sudo mkfs -v -t ext4 /dev/sdb3

下载软件包

  1. 创建软件包的存储目录
  2. 下载对应的软件包
    1. 软件包的下载地址文件 https://www.linuxfromscratch.org/lfs/view/stable/wget-list-sysv
    2. 软件包的 md5 校验文件 https://www.linuxfromscratch.org/lfs/view/stable/md5sums
    3. 如果存在无法下载的软件包可以参考国内镜像网站 https://mirrors.ustc.edu.cn/lfs/lfs-packages/12.3/
  3. 验证软件包的 md5 值,确保软件包数量一致
export LFS=/mnt/lfs
echo $LFS
sudo mkdir -pv $LFS
sudo mount -v -t ext4 /dev/sdb3 $LFS
sudo chown root:root $LFS
sudo chmod 755 $LFS
wget https://www.linuxfromscratch.org/lfs/view/stable/wget-list-sysv
wget https://www.linuxfromscratch.org/lfs/view/stable/md5sums
sudo mv md5sums $LFS/sources/
vim wget-list-sysv 
sudo mkdir -pv $LFS/sources
sudo chmod -v a+wt $LFS/sources/
sudo wget --input-file=wget-list-sysv --continue --directory-prefix=$LFS/sources/
pushd $LFS/sources/
sudo md5sum -c md5sums
popd

创建文件目录布局

以下操作通过 root 用户操作

mkdir -pv $LFS/{etc,var} $LFS/usr/{bin,lib,sbin}

for i in bin lib sbin; do
  ln -sv usr/$i $LFS/$i
done

case $(uname -m) in
  x86_64) mkdir -pv $LFS/lib64 ;;
esac

mkdir -pv $LFS/tools

添加 LFS 用户并配置用户环境

groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs
passwd lfs
chown -v lfs $LFS/{usr{,/*},var,etc,tools}
case $(uname -m) in
  x86_64) chown -v lfs $LFS/lib64 ;;
esac

su - lfs

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

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

source ~/.bash_profile

  • LFS_TGT=$(uname -m)-lfs-linux-gnu。LFS_TGT变量设定了一个非默认,但与宿主系统兼容的机器描述符。该描述符被用于构建交叉编译器和交叉编译临时工具链。
  • set +h。set +h 命令关闭 bash 的散列功能。一般情况下,散列是很有用的 —— bash 使用一个散列表维护各个可执行文件的完整路径,这样就不用每次都在 PATH 指定的目录中搜索可执行文件。然而,在构建 LFS 时,我们希望总是使用最新安装的工具。关闭散列功能强制 shell 在运行程序时总是搜索 PATH。这样,一旦$LFS/tools/bin 中有新的工具可用,shell 就能够找到它们,而不是使用之前记忆在散列表中,由宿主发行版提供的 /usr/bin 或 /bin 中的工具。
  • 将 umask 设定为 022,保证只有文件所有者可以写新创建的文件和目录,但任何人都可读取或搜索 (仅针对目录) 它们

编译交叉工具链

构建临时编译环境前需要确认 LFS 环境变量是否配置正确,并确保使用 lfs 用户登入且已经进入 sources 目录

su - lfs
export LFS=/mnt/lfs
echo $LFS
cd $LFS/sources/
mkdir -v build

Binutils-2.44 第一遍

tar Jxvf binutils-2.44.tar.xz
cd $LFS/sources/build
..//binutils-2.44/configure --prefix=$LFS/tools \
             --with-sysroot=$LFS \
             --target=$LFS_TGT   \
             --disable-nls       \
             --enable-gprofng=no \
             --disable-werror    \
             --enable-new-dtags  \
             --enable-default-hash-style=gnu
make
make install

GCC-14.2.0 第一遍

tar Jxvf gcc-14.2.0.tar.xz
cd gcc-14.2.0
tar -xf ../mpfr-4.2.1.tar.xz
mv -v mpfr-4.2.1 mpfr
tar -xf ../gmp-6.3.0.tar.xz
mv -v gmp-6.3.0 gmp
tar -xf ../mpc-1.3.1.tar.gz
mv -v mpc-1.3.1 mpc
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                  \
    --target=$LFS_TGT         \
    --prefix=$LFS/tools       \
    --with-glibc-version=2.41 \
    --with-sysroot=$LFS       \
    --with-newlib             \
    --without-headers         \
    --enable-default-pie      \
    --enable-default-ssp      \
    --disable-nls             \
    --disable-shared          \
    --disable-multilib        \
    --disable-threads         \
    --disable-libatomic       \
    --disable-libgomp         \
    --disable-libquadmath     \
    --disable-libssp          \
    --disable-libvtv          \
    --disable-libstdcxx       \
    --enable-languages=c,c++
make
make install
cd ..
cat gcc/limitx.h gcc/glimits.h gcc/limity.h > \
  `dirname $($LFS_TGT-gcc -print-libgcc-file-name)`/include/limits.h

Linux-6.13.4 API  头文件

tar xf linux-6.13.4.tar.xz 
cd linux-6.13.4
make mrproper
make headers
find usr/include -type f ! -name '*.h' -delete
cp -rv usr/include $LFS/usr

Glibc-2.41

tar xf glibc-2.41.tar.xz 
cd glibc-2.41
case $(uname -m) in
    i?86)   ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3
    ;;
    x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64
            ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3
    ;;
esac

patch -Np1 -i ../glibc-2.41-fhs-1.patch
mkdir -v build
cd       build
echo "rootsbindir=/usr/sbin" > configparms
../configure                             \
      --prefix=/usr                      \
      --host=$LFS_TGT                    \
      --build=$(../scripts/config.guess) \
      --enable-kernel=5.4                \
      --with-headers=$LFS/usr/include    \
      --disable-nscd                     \
      libc_cv_slibdir=/usr/lib
make
make DESTDIR=$LFS install
sed '/RTLDLIST=/s@/usr@@g' -i $LFS/usr/bin/ldd
echo 'int main(){}' | $LFS_TGT-gcc -xc -
readelf -l a.out | grep ld-linux
rm -v a.out

如果一切正常,那么应该没有错误消息,而且最后一行命令应该输出下列格式的内容:

[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

GCC-14.2.0 中的 Libstdc++

Libstdc++ 是 C++ 标准库。我们需要它才能编译 C++ 代码 (GCC 的一部分用 C++ 编写)。但在构建第一遍的 GCC时我们不得不暂缓安装它,因为 Libstdc++ 依赖于当时还没有安装到目标目录的 Glibc。

cd gcc-14.2.0
cd build
../libstdc++-v3/configure           \
    --host=$LFS_TGT                 \
    --build=$(../config.guess)      \
    --prefix=/usr                   \
    --disable-multilib              \
    --disable-nls                   \
    --disable-libstdcxx-pch         \
    --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/14.2.0
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/lib{stdc++{,exp,fs},supc++}.la

交叉编译临时工具

使用刚刚构建的交叉工具链对基本工具进行交叉编译。这些工具会被安装到它们的最终位置,但现在还无法使用。基本操作仍然依赖宿主系统的工具。尽管如此,在链接时会使用刚刚安装的库。

M4-1.4.19

tar xvf m4-1.4.19.tar.xz 
cd m4-1.4.19
./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install

Ncurses-6.5

tar xf ncurses-6.5.tar.gz
cd ncurses-6.5
mkdir build
pushd build
  ../configure AWK=gawk
  make -C include
  make -C progs tic
popd
./configure --prefix=/usr                \
            --host=$LFS_TGT              \
            --build=$(./config.guess)    \
            --mandir=/usr/share/man      \
            --with-manpage-format=normal \
            --with-shared                \
            --without-normal             \
            --with-cxx-shared            \
            --without-debug              \
            --without-ada                \
            --disable-stripping          \
            AWK=gawk
make
make DESTDIR=$LFS TIC_PATH=$(pwd)/build/progs/tic install
ln -sv libncursesw.so $LFS/usr/lib/libncurses.so
sed -e 's/^#if.*XOPEN.*$/#if 1/' \
    -i $LFS/usr/include/curses.h

Bash-5.2.37

tar xvf bash-5.2.37.tar.gz
cd bash-5.2.37
./configure --prefix=/usr                      \
            --build=$(sh support/config.guess) \
            --host=$LFS_TGT                    \
            --without-bash-malloc
make
make DESTDIR=$LFS install
ln -sv bash $LFS/bin/sh

Coreutils-9.6

tar xvf coreutils-9.6.tar.xz
cd coreutils-9.6
./configure --prefix=/usr                     \
            --host=$LFS_TGT                   \
            --build=$(build-aux/config.guess) \
            --enable-install-program=hostname \
            --enable-no-install-program=kill,uptime
make
make DESTDIR=$LFS install
mv -v $LFS/usr/bin/chroot              $LFS/usr/sbin
mkdir -pv $LFS/usr/share/man/man8
mv -v $LFS/usr/share/man/man1/chroot.1 $LFS/usr/share/man/man8/chroot.8
sed -i 's/"1"/"8"/'                    $LFS/usr/share/man/man8/chroot.8

Diffutils-3.11

tar xvf diffutils-3.11.tar.xz
cd diffutils-3.11
./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(./build-aux/config.guess)
make
make DESTDIR=$LFS install

File-5.46

tar xvf file-5.46.tar.gz
cd file-5.46
mkdir build
pushd build
  ../configure --disable-bzlib      \
               --disable-libseccomp \
               --disable-xzlib      \
               --disable-zlib
  make
popd
./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess)
make FILE_COMPILE=$(pwd)/build/src/file
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/libmagic.la

Findutils-4.10.0

tar xvf findutils-4.10.0.tar.xz
cd findutils-4.10.0
./configure --prefix=/usr                   \
            --localstatedir=/var/lib/locate \
            --host=$LFS_TGT                 \
            --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install

Gawk-5.3.1

tar xvf gawk-5.3.1.tar.xz
cd gawk-5.3.1
sed -i 's/extras//' Makefile.in
./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install

Grep-3.11

tar xvf grep-3.11.tar.xz 
cd grep-3.11
./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(./build-aux/config.guess)
make
make DESTDIR=$LFS install

Gzip-1.13

tar xvf gzip-1.13.tar.xz
cd gzip-1.13
./configure --prefix=/usr --host=$LFS_TGT
make
make DESTDIR=$LFS install

Make-4.4.1

tar xvf make-4.4.1.tar.gz
cd make-4.4.1
./configure --prefix=/usr   \
            --without-guile \
            --host=$LFS_TGT \
            --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install

Patch-2.7.6

tar xvf patch-2.7.6.tar.xz
cd patch-2.7.6
./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install

Sed-4.9

tar xvf sed-4.9.tar.xz
cd sed-4.9
./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(./build-aux/config.guess)
make
make DESTDIR=$LFS install

Tar-1.35

tar xvf tar-1.35.tar.xz
cd Tar-1.35
./configure --prefix=/usr                     \
            --host=$LFS_TGT                   \
            --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install

Xz-5.6.4

tar xvf xz-5.6.4.tar.xz
cd Xz-5.6.4
./configure --prefix=/usr                     \
            --host=$LFS_TGT                   \
            --build=$(build-aux/config.guess) \
            --disable-static                  \
            --docdir=/usr/share/doc/xz-5.6.4
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/liblzma.la

Binutils-2.44 - 第二遍

tar Jxvf binutils-2.44.tar.xz
cd binutils-2.44
sed '6031s/$add_dir//' -i ltmain.sh
mkdir -v build
cd  build
../configure                   \
    --prefix=/usr              \
    --build=$(../config.guess) \
    --host=$LFS_TGT            \
    --disable-nls              \
    --enable-shared            \
    --enable-gprofng=no        \
    --disable-werror           \
    --enable-64-bit-bfd        \
    --enable-new-dtags         \
    --enable-default-hash-style=gnu
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la}

GCC-14.2.0 - 第二遍

tar xvf gcc-14.2.0.tar.xz
cd gcc-14.2.0
tar -xf ../mpfr-4.2.1.tar.xz
mv -v mpfr-4.2.1 mpfr
tar -xf ../gmp-6.3.0.tar.xz
mv -v gmp-6.3.0 gmp
tar -xf ../mpc-1.3.1.tar.gz
mv -v mpc-1.3.1 mpc

case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
  ;;
esac

sed '/thread_header =/s/@.*@/gthr-posix.h/' \
    -i libgcc/Makefile.in libstdc++-v3/include/Makefile.in

mkdir -v build
cd  build
../configure                                       \
    --build=$(../config.guess)                     \
    --host=$LFS_TGT                                \
    --target=$LFS_TGT                              \
    LDFLAGS_FOR_TARGET=-L$PWD/$LFS_TGT/libgcc      \
    --prefix=/usr                                  \
    --with-build-sysroot=$LFS                      \
    --enable-default-pie                           \
    --enable-default-ssp                           \
    --disable-nls                                  \
    --disable-multilib                             \
    --disable-libatomic                            \
    --disable-libgomp                              \
    --disable-libquadmath                          \
    --disable-libsanitizer                         \
    --disable-libssp                               \
    --disable-libvtv                               \
    --enable-languages=c,c++
make
make DESTDIR=$LFS install


  • 无标签