相关版本

VMware15 pro
openEuler 20.03 LTS SP1
LFS book 10.0

已安装完系统

检查软件

当前软件如下:
在这里插入图片描述
LFS book要求如下:
在这里插入图片描述
可以看到
Gzip版本低(不知道怎么更新)
Perl版本低(不知道怎么更新)
没有texinfo

使用如下命令安装texinfo

yum install texinfo

创建新分区

分配磁盘

在虚拟机设置中添加磁盘硬件,使用SCSI,创建新的虚拟磁盘,推荐10GB的LFS分区和2GB的交换区,所以分配的磁盘大小为12GB。

使用reboot重启

分区

使用命令

cfdisk /dev/sdb

进行分区
UI比较友好,分完后选择write输入yes然后退出
在这里插入图片描述

建立文件系统

使用命令

mkfs -v -t ext4 /dev/sdb1
mkswap /dev/sdb2

设置环境变量

export LFS=/mnt/lfs

挂载分区

建立目录

mkdir -pv $LFS

挂载

mount -v -t ext4 /dev/sdb1 $LFS

编辑/etc/fstab,加入
/dev/sdb1 /mnt/lfs ext4 defaults 1 1
避免重启重新挂载

启用swap分区

/sbin/swapon -v /dev/sdb2

下载软件包

新建目录

mkdir -v $LFS/sources

写入权限和sticky标志

chmod -v a+wt $LFS/sources

进入sources目录

cd $LFS/sources

先去兰州大学镜像站获得wget-list文件

wget https://mirror.bjtu.edu.cn/lfs/lfs-packages/10.0/wget-list

然后下载软件包(大概20分钟)

wget --input-file=wget-list --continue --directory-prefix=$LFS/sources

获得check.sh文件

wget https://mirror.bjtu.edu.cn/lfs/lfs-packages/10.0/check.sh

运行检查缺少的软件包

bash check.sh

如下所示:
在这里插入图片描述
缺少4个软件包,在下面命令后面加上对应的软件包下载

wget https://mirror.bjtu.edu.cn/lfs/lfs-packages/10.0/

最后准备工作

使用如下命令创建所需的目录布局

mkdir -pv $LFS/{bin,etc,lib,sbin,usr,var}
case $(uname -m) in
x86_64) mkdir -pv $LFS/lib64 ;;
esac

为交叉编译器和其他程序分离建立目录

mkdir -pv $LFS/tools

以非特权用户来编译软件包
创建新用户

groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs

设置密码

passwd lfs

给权限

chown -v lfs $LFS/{usr,lib,var,etc,bin,sbin,tools}
case $(uname -m) in
x86_64) chown -v lfs $LFS/lib64 ;;
esac
chown -v lfs $LFS/sources

切换用户

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
export LFS LC_ALL LFS_TGT PATH
EOF

保证lfs用户环境的纯净

[ ! -e /etc/bash.bashrc ] || mv -v /etc/bash.bashrc /etc/bash.bashrc.NOUSE

读取配置文件

source ~/.bash_profile

在这里插入图片描述

编译交叉工具链

Binutils-2.35 - 第⼀遍

解压

tar -xvf binutils-2.35.tar.xz

进入目录

cd binutils-2.35

在一个专门的目录中构建

mkdir -v build
cd build

准备编译

../configure --prefix=$LFS/tools \
--with-sysroot=$LFS \
--target=$LFS_TGT \
--disable-nls \
--disable-werror

编译

make

结束
在这里插入图片描述

安装

make install

结束
在这里插入图片描述
删除中间文件

rm -rf binutils-2.35
GCC-10.2.0 - 第⼀遍

解压

tar -xvf gcc-10.2.0.tar.xz

进入相应目录

cd gcc-10.2.0

GCC 依赖于 GMP、MPFR 和 MPC 这三个包,安装这三个包(中文版书中这里mpc版本错误)

tar -xf ../mpfr-4.1.0.tar.xz
mv -v mpfr-4.1.0 mpfr
tar -xf ../gmp-6.2.0.tar.xz
mv -v gmp-6.2.0 gmp
tar -xf ../mpc-1.1.0.tar.gz
mv -v mpc-1.1.0 mpc

对于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 \
--target=$LFS_TGT \
--prefix=$LFS/tools \
--with-glibc-version=2.11 \
--with-sysroot=$LFS \
--with-newlib \
--without-headers \
--enable-initfini-array \
--disable-nls \
--disable-shared \
--disable-multilib \
--disable-decimal-float \
--disable-threads \
--disable-libatomic \
--disable-libgomp \
--disable-libquadmath \
--disable-libssp \
--disable-libvtv \
--disable-libstdcxx \
--enable-languages=c,c++

编译(这一过程要好久,我进行了1个半小时)

make

结束
在这里插入图片描述

安装

make install

结束
在这里插入图片描述
此时GCC安装的内部头文件不完整,使用下面命令创建一个完整的内部头文件

cd ..
cat gcc/limitx.h gcc/glimits.h gcc/limity.h > \
`dirname $($LFS_TGT-gcc -print-libgcc-file-name)`/install-tools/include/limits.h

返回上级目录

cd ..

删除中间目录

rm -rf gcc-10.2.0
Linux-5.8.5 API 头⽂件

解压

tar -xvf linux-5.8.3.tar.xz

进入目录

cd linux-5.8.3

确保软件包中没有遗留陈旧的文件

make mrproper

提取用户可见的头文件

make headers
find usr/include -name '.*' -delete
rm usr/include/Makefile
cp -rv usr/include $LFS/usr

返回上级目录

cd ..

删除中间文件

rm -rf linux-5.8.3
Glibc-2.32

解压

tar -xvf glibc-2.32.tar.xz

进入目录

cd glibc-2.32

创建符号链接

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.32-fhs-1.patch

建一个专门的目录来构建glibc

mkdir -v build
cd build

准备编译

../configure \
--prefix=/usr \
--host=$LFS_TGT \
--build=$(../scripts/config.guess) \
--enable-kernel=3.2 \
--with-headers=$LFS/usr/include \
libc_cv_slibdir=/lib

编译

make

结束
在这里插入图片描述
安装

make DESTDIR=$LFS install

结束
在这里插入图片描述
返回上级目录

cd ..
cd ..

删除中间目录

rm -rf glibc-2.32
检查工具链
echo 'int main(){}' > dummy.c
$LFS_TGT-gcc dummy.c
readelf -l a.out | grep '/ld-linux'

如果正常输出应该如下所示

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

清理测试文件

rm -v dummy.c a.out

至此交叉工具链构建完成,可以完成limits.h头文件的安装。运行

$LFS/tools/libexec/gcc/$LFS_TGT/10.2.0/install-tools/mkheaders
GCC-10.2.0 中的 Libstdc++,第⼀遍

解压

tar -xvf gcc-10.2.0.tar.xz

进入目录

cd gcc-10.2.0

创建一个单独的构建目录

mkdir -v build
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++/10.2.0

编译

make

结束

在这里插入图片描述
安装

make DESTDIR=$LFS install

结束

在这里插入图片描述
返回sources

cd ../..

删除中间目录

rm -rf gcc-10.2.0

交叉编译临时⼯具

现在用刚刚构建的交叉工具链对基本工具进行交叉编译

M4-1.4.18

解压

tar -xvf m4-1.4.18.tar.xz

进入目录

cd m4-1.4.18

进行glibc-2.28要求的一些修补

sed -i 's/IO_ftrylockfile/IO_EOF_SEEN/' lib/*.c
echo "#define _IO_IN_BACKUP 0x100" >> lib/stdio-impl.h

准备编译

./configure --prefix=/usr \
--host=$LFS_TGT \
--build=$(build-aux/config.guess)

编译

make

结束
在这里插入图片描述
安装

make DESTDIR=$LFS install

结束
在这里插入图片描述
返回上级目录并删除中间目录

cd ..
rm -rf m4-1.4.18
Ncurses-6.2

解压

tar -xvf ncurses-6.2.tar.gz

进入目录

cd ncurses-6.2

保证在配置时优先查找gawk命令

sed -i s/mawk// configure

在宿主机构建 ”tic“ 程序

mkdir build
pushd build
../configure
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-debug \
--without-ada \
--without-normal \
--enable-widec

编译

make

结束
在这里插入图片描述
安装

make DESTDIR=$LFS TIC_PATH=$(pwd)/build/progs/tic install
echo "INPUT(-lncursesw)" > $LFS/usr/lib/libncurses.so

结束
在这里插入图片描述
将共享库移动到/lib目录中

mv -v $LFS/usr/lib/libncursesw.so.6* $LFS/lib

重新生成一个失效的符号链接

ln -sfv ../../lib/$(readlink $LFS/usr/lib/libncursesw.so) $LFS/usr/lib/libncursesw.so

返回上级目录并删除中间目录

cd ..
rm -rf ncurses-6.2
Bash-5.0

解压并进入目录

tar -xvf bash-5.0.tar.gz
cd bash-5.0

准备编译

./configure --prefix=/usr \
--build=$(support/config.guess) \
--host=$LFS_TGT \
--without-bash-malloc

编译

make

结束
在这里插入图片描述

安装

make DESTDIR=$LFS install

结束
在这里插入图片描述

将可执⾏⽂件移动到正确位置

mv $LFS/usr/bin/bash $LFS/bin/bash

创建链接

ln -sv bash $LFS/bin/sh

返回上级目录并删除中间目录

cd ..
rm -rf bash-5.0

后面应该都差不多了,暂时不再记录(太多了,懒)

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

进入chroot

这个比较简单,确认$LFS的值后直接复制粘贴命令就结束了
在这里插入图片描述

创建目录和必要的文件、符号链接

同上,复制粘贴就行

GCC-10.2.0 中的 Libstdc++,第⼆遍

进入sources目录、解压文件、进入目录

cd sources

tar -xvf gcc-10.2.0.tar.xz

cd gcc-10.2.0

创建⼀个符号链接,允许在 GCC 源码树中构建 Libstdc++:

ln -s gthr-posix.h libgcc/gthr-default.h

新建并进入单独的构建目录

mkdir -v build
cd build

准备编译

../libstdc++-v3/configure \
CXXFLAGS="-g -O2 -D_GNU_SOURCE" \
--prefix=/usr \
--disable-multilib \
--disable-nls \
--host=$(uname -m)-lfs-linux-gnu \
--disable-libstdcxx-pch

编译

make

结束
在这里插入图片描述
安装

make install

结束
在这里插入图片描述
返回sources目录并删除中间文件

cd ../..
rm -rf gcc-10.2.0

重复解压编译安装几个软件,不再记录

清理和备份临时系统

照着说明复制粘贴…
然后根据说明,查看磁盘剩余可用空间,要求至少5G,如果要备份还需要600MB的空间

备份命令(要好久)

cd $LFS &&
tar -cJpf $HOME/lfs-temp-tools-SVN-20200901.tar.xz .

还原命令

cd $LFS &&
rm -rf ./* &&
tar -xpf $HOME/lfs-temp-tools-SVN-20200901.tar.xz

其中$HOME可以替换成其他目录

构建 LFS 系统

LFS变量如果未定义

export LFS=/mnt/lfs

重新进入chroot

mkdir -pv $LFS/{dev,proc,sys,run}

mknod -m 600 $LFS/dev/console c 5 1
mknod -m 666 $LFS/dev/null c 1 3

mount -v --bind /dev $LFS/dev

mount -v --bind /dev/pts $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run

if [ -h $LFS/dev/shm ]; then
mkdir -pv $LFS/$(readlink $LFS/dev/shm)
fi

chroot "$LFS" /usr/bin/env -i \
HOME=/root \
TERM="$TERM" \
PS1='(lfs chroot) \u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/bin/bash --login +h

退出chroot

exit
umount $LFS/dev{/pts,}
umount $LFS/{sys,proc,run}

必须处于chroot环境下!
重后需要重新设置$LFS变量并重新进入chroot

然后继续解压、复制粘贴命令安装…

glibc check

在这里插入图片描述
BOOK中说可能会出现一些错误,暂时忽略

binutils check

在执行make -k check检查编译的时候出现了如下的错误
在这里插入图片描述
但是在后续的安装中没有出现错误,故暂时忽略

attr check

在make check 的时候出现了fail,如下所示
在这里插入图片描述
未解决,先跳过去,直接安装没有报错

GCC check结果

摘要如下
在这里插入图片描述
在这里插入图片描述
继续忽略。。。
安装后各种测试结果显示也正常
在这里插入图片描述

清理系统

清理遗留文件

rm -rf /tmp/*

从现在之后重新进入chroot环境的bash不再使用+h选项
新的重新进入chroot命令如下:

mkdir -pv $LFS/{dev,proc,sys,run}

mknod -m 600 $LFS/dev/console c 5 1
mknod -m 666 $LFS/dev/null c 1 3

mount -v --bind /dev $LFS/dev

mount -v --bind /dev/pts $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run

if [ -h $LFS/dev/shm ]; then
mkdir -pv $LFS/$(readlink $LFS/dev/shm)
fi

chroot "$LFS" /usr/bin/env -i \
HOME=/root TERM="$TERM" \
PS1='(lfs chroot) \u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/bin/bash --login

清除一些静态库

rm -f /usr/lib/lib{bfd,opcodes}.a
rm -f /usr/lib/libctf{,-nobfd}.a
rm -f /usr/lib/libbz2.a
rm -f /usr/lib/lib{com_err,e2p,ext2fs,ss}.a
rm -f /usr/lib/libltdl.a
rm -f /usr/lib/libfl.a
rm -f /usr/lib/libz.a

删除一些“libtool档案"文件

find /usr/lib /usr/libexec -name \*.la -delete

删除一些没有存在意义的之前构建的编译器

find /usr -depth -name $(uname -m)-lfs-linux-gnu\* | xargs rm -rf

删除/tools获得更多可用空间

rm -rf /tools

移除临时‘tester’用户账户

userdel -r tester

系统配置

LFS-Bootscripts-20200818

直接解压、make install安装即可

设备管理

生成初始规则

bash /lib/udev/init-net-rules.sh

检查⽂件 /etc/udev/rules.d/70-persistent-net.rules,确认⽹络设备与命名的对应关系

cat /etc/udev/rules.d/70-persistent-net.rules

但是我的系统里没有70-persistent-net.rules这个文件…

一般网络配置

创建/etc/resolv.conf文件

cat > /etc/resolv.conf << "EOF"
# Begin /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
# End /etc/resolv.conf
EOF

配置系统主机名

echo "<lfs>" > /etc/hostname

<lfs> 需要被替换为赋予该计算机的名称

自定义/etc/hosts文件

cat > /etc/hosts << "EOF"
# Begin /etc/hosts
127.0.0.1 localhost.localdomain localhost
127.0.1.1 <FQDN> <HOSTNAME>
<192.168.1.1> <FQDN> <HOSTNAME> [alias1] [alias2 ...]
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# End /etc/hosts
EOF

其中 <192.168.0.2>,<FQDN>,以及<主机名> 的值需要为特定使⽤环境和需求进⾏修改,可以跳过别名 (alias),它们不是必要的。

在这里我的输入如下:

cat > /etc/hosts << "EOF"
# Begin /etc/hosts
127.0.0.1 localhost.localdomain localhost
192.168.1.1 localhost.localdomain lfs
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# End /etc/hosts
EOF
System V 引导脚本使⽤与配置

配置Sysvinit

cat > /etc/inittab << "EOF"
# Begin /etc/inittab

id:3:initdefault:

si::sysinit:/etc/rc.d/init.d/rc S

l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

su:S016:once:/sbin/sulogin

1:2345:respawn:/sbin/agetty --noclear tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600

# End /etc/inittab
EOF
配置系统时钟

先通过下列命令判断硬件时钟是否设置为UTC

hwclock --localtime --show

然后创建新的/etc/sysconfig/clock文件,如果没有设置为UTC,则下面的UTC变量改为0

cat > /etc/sysconfig/clock << "EOF"
# Begin /etc/sysconfig/clock
UTC=1
# Set this to any options you might need to give to hwclock,
# such as machine hardware clock type for Alphas.
CLOCKPARAMS=
# End /etc/sysconfig/clock
EOF
配置Linux控制台

中文好像怎么配置都不可能正常显示,直接忽略

自定义引导和关机脚本

通过编辑/etc/sysconfig/rc.site来实现,我不太懂,先不管

Bash Shell启动文件

我的配置如下:

cat > /etc/profile << "EOF"
# Begin /etc/profile
export LANG=en_US.UTF-8
# End /etc/profile
EOF
创建/etc/inputrc文件

直接复制粘贴默认配置

cat > /etc/inputrc << "EOF"
# Begin /etc/inputrc
# Modified by Chris Lynn <roryo@roryo.dynup.net>

# Allow the command prompt to wrap to the next line
set horizontal-scroll-mode Off

# Enable 8bit input
set meta-flag On
set input-meta On

# Turns off 8th bit stripping
set convert-meta Off

# Keep the 8th bit for display
set output-meta On

# none, visible or audible
set bell-style none

# All of the following map the escape sequence of the value
# contained in the 1st argument to the readline specific functions
"\eOd": backward-word
"\eOc": forward-word

# for linux console
"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[3~": delete-char
"\e[2~": quoted-insert

# for xterm
"\eOH": beginning-of-line
"\eOF": end-of-line

# for Konsole
"\e[H": beginning-of-line
"\e[F": end-of-line

# End /etc/inputrc
EOF
创建/etc/shells文件

继续复制粘贴

cat > /etc/shells << "EOF"
# Begin /etc/shells
/bin/sh
/bin/bash
# End /etc/shells
EOF

内核构建

在配置内核选项时将下面网站中的选项都选上

http://www.linuxfromscratch.org/~krejzi/basic-kernel.txt

然后正常地照着手册走

使LFS系统可引导

创建/etc/fstab文件

根据说明略作修改(有中文粘贴不进去,我就把中文注释删了)

cat > /etc/fstab << "EOF"
# Begin /etc/fstab

/dev/sdb1 / ext4 defaults 1 1
/dev/sdb2 swap swap pri=1 0 0
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /run tmpfs defaults 0 0
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0

# End /etc/fstab
EOF
配置GRUB

问了大佬后完成了…

使用如下命令

grub-install --force /dev/sdb

再自动生成grub.cfg

grub-mkconfig -o /boot/grub/grub.cfg

退出chroot,将刚刚生成的$LFS/boot/grub/grub.cfg中用

### BEGIN /etc/grub.d/10_linux ###
### END /etc/grub.d/10_linux ###

中间部分的内容复制到/boot/grub2/grub.cfg中相同的位置下面

完成

重启后的界面如下所示
在这里插入图片描述
选择GNU/Linux进入后顺利进入LFS系统
在这里插入图片描述

可能的错误

在解压的时候出现了一个错误,提示

gzip: stdin: invalid compressed data–format violated

在stackoverflow上查到是因为压缩包被污染了,重新下载解决

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐