目录
0、本文约定
0.0. 参考内容
特别感谢“Linux 中国 - LCTT - LFS 翻译小组”翻译的LFS手册,该小组官网地址为https://lctt.github.io,LFS手册网址为https://lctt.github.io/LFS-BOOK。
本文使用的LFS手册为该小组翻译的Linux From Scratch (简体中文版)- 9.0 - SysV HTML版。
强烈建议操作过程参考HTML版的LFS手册,原因见本文1.1.节。
0.1. 输入输出样式
在Linux环境中输入的命令及输出的结果使用如下样式表示(内容与终端显示的一致):
lfs@lfs-VirtualBox:~$ echo "hello world"
0.2. 注意事项
使用如下样式表示:
这里是注意事项、
0.3. 宿主机配置
本文使用的物理机器为:
HP ZHAN 66 Pro 14 G3
CPU:i7-10510U
内存:16GB
操作系统:Windows10-64
LFS编译环境:
VirualBox-6.1 & Ubuntu20.04
LFS编译环境中的各软件版本:
bash, version 5.0.17(1)-release
/bin/sh -> /usr/bin/bash
Binutils: GNU ld (GNU Binutils for Ubuntu) 2.34
bison (GNU Bison) 3.5.1
/usr/bin/yacc -> /usr/bin/bison.yacc
bzip2, Version 1.0.8, 13-Jul-2019.
Coreutils: 8.30
diff (GNU diffutils) 3.7
find (GNU findutils) 4.7.0
GNU Awk 5.0.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.2.0)
/usr/bin/awk -> /usr/bin/gawk
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
(Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
grep (GNU grep) 3.4
gzip 1.10
Linux version 5.4.0-42-generic (buildd@lgw01-amd64-038) (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)) #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020
m4 (GNU M4) 1.4.18
GNU Make 4.2.1
GNU patch 2.7.6
Perl version=‘5.30.0’;
Python 3.8.5
sed (GNU sed) 4.7
tar (GNU tar) 1.30
texi2any (GNU texinfo) 6.7
xz (XZ Utils) 5.2.4
g++ compilation OK
1、对LFS的一点理解
1.0. 关于LFS交叉编译环境
本质上是在宿主机操作系统中,编译出另一套可以在其它机器上使用的操作系统,也就是交叉编译。
复杂的地方是,需要避免编译结果受宿主机环境变量,软件版本的影响,造成编译结果的链接、环境变量等指向到宿主机,从而导致编译结果无法在其它机器上正常使用。
为了避免发生这种情况(环境污染),LFS手册所有的操作,实际上分三步走:
- 第一步,先小心翼翼的(严格的设置了它们的符号链接、编译参数等)构建了一套工具。
- 第二步,用这套不会造成环境污染的工具,来编译一个基本的交叉编译环境。
- 第三步,当基本的交叉编译环境构建好了以后,LFS手册指导我们,通过chroot命令,切换到该环境中,使用该环境中最基本的编译工具,自己来编译自己所需要的其它软件。
上个图来方便理解:
1.1. 关于操作步骤
LFS手册中的shell代码部分(如下图),原样复制粘贴过去执行即可。但是一定要注意,如果你参考的LFS手册是PDF版的,下面的代码部分可能不带有换行符号(既linux中的\n,或Windows中的\r\n),或者某些符号无法复制(如某些章节里英文的 - 符号)。再次强烈建议操作过程参考html版的LFS手册。
关于LFS手册的整个操作流程,大概理解为下图:
2、LFS手册中要注意的几个地方
2.0. 关于软件版本检查
在LFS手册的《2.2. 宿主系统要求》章节中,给出的软件版本检查脚本不能正确的在ubuntu20.04下显示Binutils的版本,需要修改其脚本内容,删掉下图中黄色荧光笔标注部分即可(即,删除原文的 | cut -d" " -f3- )。否则输出的Binutils版本为:“Binutils: GNU”,修改后输出的版本为:“Binutils: GNU ld (GNU Binutils for Ubuntu) 2.34”。
2.1. 关于分区
在LFS手册的《2.4. 创建新分区》章节中,对于构建LFS系统建议使用新的分区,并建议创建交换分区、/boot分区等分区,本文并未如此操作,而是挂载了一块50GB的新硬盘/dev/sdb,并为其创建了一整个主分区/dev/sdb1,然后使用ext4格式将其格式化。
2.2. 关于编译安装软件包
特别强调
-
编译安装软件包时,需要先进入$LFS/sources目录下。
-
每次编译软件时,先使用tar命令将目标软件解压缩(xz文件使用tar -xf,bz2文件使用tar -jxf,gz文件使用tar -zxf)。
-
然后使用cd命令进入该软件源代码目录。
-
然后按照LFS提示进行操作。
-
最后,待操作完成后,使用cd …或cd …/…命令返回$LFS/sources目录,使用rm -rf 命令移除该软件源代码目录(若LFS手册没有明示需要保留的情况下)。
-
clear命令清除屏幕显示(实操过程中编译到第六章时,疑似因为内容太多导致Terminal崩溃)
-
LFS手册翻页
-
从《6.7. Linux-5.2.8 API 头文件》章节开始,请使用cd命令进入$LFS/sources目录下进行操作
-
已知《6.80. 清理》章节的如下命令无法正确执行
logout
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
这是因为本文使用的是ubuntu-desktop的desktop系统登录,然后在桌面系统中打开了一个Terminal来执行命令,当前执行命令的shell不是一个登录shell,所以会报错,退出失败进一步导致找不到$LFS环境变量及其对应的目录:
(lfs chroot) root:/usr/lib# logout
bash: logout: not login shell: use `exit'
(lfs chroot) root:/usr/lib#
(lfs chroot) root:/usr/lib# 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
chroot: cannot change root directory to '': No such file or directory
所以我们需要使用“exit”命令来代替logout命令。修改后的命令如下:
exit
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
2.3. 关于安装linux头文件
在LFS手册原文中的《5.6. Linux-5.2.8 API 头文件》和《6.7. Linux-5.2.8 API 头文件》章节里,并未描写准备操作步骤(如下图)。
其实此处和本文2.2.节相同,先解压linux内核源码包,然后进入其中,再执行即可。代码如下:
lfs@lfs-VirtualBox:/mnt/lfs/sources$ tar -xf linux-5.2.8.tar.xz
lfs@lfs-VirtualBox:/mnt/lfs/sources$ cd linux-5.2.8
2.5. 关于《7.7. Bash Shell 启动文件》章节本地字符集支持
使用以下命令可以查看支持的字符集:
locale -a
本文只能查看到zh_CN.gb18030,故,LFS手册原文创建/etc/profile的脚本修改如下:
cat > /etc/profile << "EOF"
# Begin /etc/profile
export LANG=zh_CN.gb18030
# End /etc/profile
EOF
2.6. 《8.2. 创建 /etc/fstab 文件》章节创建fstab文件
由于本文使用单个分区,故8.2.章节中创建fstab文件的脚本修改为如下:
cat > /etc/fstab << "EOF"
# Begin /etc/fstab
# file system mount-point type options dump fsck
# order
/dev/sdb1 / <fff> defaults 1 1
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
2.7. 《8.4. 使用 GRUB 设置启动过程》章节启动设置
根据LFS手册描述(如下图)
本文中使用的/dev/sdb1,应该在grub中设置为(hd1,1),并且root指向/dev/sdb1。
原文创建/boot/grub/grub.cfg文件的脚本修改如下:
cat > /boot/grub/grub.cfg << "EOF"
# Begin /boot/grub/grub.cfg
set default=0
set timeout=5
insmod ext2
set root=(hd1,1)
menuentry "GNU/Linux, Linux 5.2.8-lfs-9.0" {
linux /boot/vmlinuz-5.2.8-lfs-9.0 root=/dev/sdb1 ro
}
EOF
2.8. 关于测试套件失败的情况
2.8.1. 《6.9. Glibc-2.30》章节
参照本文进行LFS编译,在LFS手册《6.9. Glibc-2.30》章节操作时,会发现LFS中描述的已知测试失败项目inet/tst-idna_name_classify和misc/tst-ttyname,并同时出现了LFS手册中没有描述到的测试失败nptl/tst-mutex10 。但在后续实际操作时,并未产生致命影响,此处提出,以观后效。
具体测试结果输出如下:
UNSUPPORTED: elf/tst-audit10
UNSUPPORTED: elf/tst-avx512
UNSUPPORTED: elf/tst-ldconfig-bad-aux-cache
UNSUPPORTED: elf/tst-pldd
XPASS: elf/tst-protected1a
XPASS: elf/tst-protected1b
FAIL: inet/tst-idna_name_classify
UNSUPPORTED: math/test-double-libmvec-alias-avx512
UNSUPPORTED: math/test-double-libmvec-alias-avx512-main
UNSUPPORTED: math/test-double-libmvec-sincos-avx512
UNSUPPORTED: math/test-float-libmvec-alias-avx512
UNSUPPORTED: math/test-float-libmvec-alias-avx512-main
UNSUPPORTED: math/test-float-libmvec-sincosf-avx512
UNSUPPORTED: misc/tst-pkey
FAIL: misc/tst-ttyname
UNSUPPORTED: nptl/test-cond-printers
UNSUPPORTED: nptl/test-condattr-printers
UNSUPPORTED: nptl/test-mutex-printers
UNSUPPORTED: nptl/test-mutexattr-printers
UNSUPPORTED: nptl/test-rwlock-printers
UNSUPPORTED: nptl/test-rwlockattr-printers
FAIL: nptl/tst-mutex10
UNSUPPORTED: nss/tst-nss-db-endgrent
UNSUPPORTED: nss/tst-nss-db-endpwent
UNSUPPORTED: nss/tst-nss-files-hosts-long
UNSUPPORTED: nss/tst-nss-test3
UNSUPPORTED: resolv/tst-resolv-ai_idn
UNSUPPORTED: resolv/tst-resolv-ai_idn-latin1
Summary of test results:
3 FAIL
6070 PASS
23 UNSUPPORTED
17 XFAIL
2 XPASS
make[1]: *** [Makefile:412: tests] Error 1
make[1]: Leaving directory '/sources/glibc-2.30'
make: *** [Makefile:9: check] Error 2
2.8.2. 《6.21. GCC-9.2.0》章节
LFS手册《6.21. GCC-9.2.0》章节中描述已知6处失败,本文出现8处失败,但是在后续的验证中得到了正确的验证结果[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2],根据LFS的描述及其它的一些信息来看,这些失败可能是由于语言环境,时间问题,CPU指令集问题等原因造成的所以暂不追究这个问题。另外,本章节总计用时4小时,需要耐心等待。测试报告如下:
(lfs chroot) root:/sources/gcc-9.2.0/build# ../contrib/test_summary
gawk: cmd. line:36: warning: regexp escape sequence `\=' is not a known regexp operator
cat <<'EOF' |
LAST_UPDATED: Obtained from SVN: tags/gcc_9_2_0_release revision 274275
Native configuration is x86_64-pc-linux-gnu
=== g++ tests ===
Running target unix
=== g++ Summary ===
# of expected passes 134787
# of expected failures 527
# of unsupported tests 5921
/sources/gcc-9.2.0/build/gcc/xg++ version 9.2.0 (GCC)
=== gcc tests ===
Running target unix
FAIL: gcc.target/i386/pr57193.c scan-assembler-times movdqa 2
FAIL: gcc.target/i386/pr90178.c scan-assembler-times xorl[\\\\t ]*\\\\%eax,[\\\\t ]*%eax 1
=== gcc Summary ===
# of expected passes 139439
# of unexpected failures 2
# of expected failures 527
# of unsupported tests 2151
/sources/gcc-9.2.0/build/gcc/xgcc version 9.2.0 (GCC)
=== libatomic tests ===
Running target unix
=== libatomic Summary ===
# of expected passes 54
=== libgomp tests ===
Running target unix
=== libgomp Summary ===
# of expected passes 2316
# of expected failures 2
# of unsupported tests 210
=== libitm tests ===
Running target unix
=== libitm Summary ===
# of expected passes 42
# of expected failures 3
# of unsupported tests 1
=== libstdc++ tests ===
Running target unix
FAIL: 22_locale/time_get/get_time/char/2.cc execution test
FAIL: 22_locale/time_get/get_time/char/wrapped_env.cc execution test
FAIL: 22_locale/time_get/get_time/char/wrapped_locale.cc execution test
FAIL: 22_locale/time_get/get_time/wchar_t/2.cc execution test
FAIL: 22_locale/time_get/get_time/wchar_t/wrapped_env.cc execution test
FAIL: 22_locale/time_get/get_time/wchar_t/wrapped_locale.cc execution test
FAIL: experimental/net/internet/resolver/ops/lookup.cc execution test
FAIL: experimental/net/internet/resolver/ops/reverse.cc execution test
=== libstdc++ Summary ===
# of expected passes 12892
# of unexpected failures 8
# of expected failures 78
# of unsupported tests 380
Compiler version: 9.2.0 (GCC)
Platform: x86_64-pc-linux-gnu
configure flags: --prefix=/usr --enable-languages=c,c++ --disable-multilib --disable-bootstrap --with-system-zlib
EOF
Mail -s "Results for 9.2.0 (GCC) testsuite on x86_64-pc-linux-gnu" gcc-testresults@gcc.gnu.org &&
mv /sources/gcc-9.2.0/build/./gcc/testsuite/g++/g++.sum /sources/gcc-9.2.0/build/./gcc/testsuite/g++/g++.sum.sent &&
mv /sources/gcc-9.2.0/build/./gcc/testsuite/gcc/gcc.sum /sources/gcc-9.2.0/build/./gcc/testsuite/gcc/gcc.sum.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum.sent &&
mv /sources/gcc-9.2.0/build/./gcc/testsuite/g++/g++.log /sources/gcc-9.2.0/build/./gcc/testsuite/g++/g++.log.sent &&
mv /sources/gcc-9.2.0/build/./gcc/testsuite/gcc/gcc.log /sources/gcc-9.2.0/build/./gcc/testsuite/gcc/gcc.log.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.log /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.log.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.log /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.log.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.log /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.log.sent &&
mv /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.log /sources/gcc-9.2.0/build/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.log.sent &&
true
验证结果如下:
(lfs chroot) root:/sources/gcc-9.2.0/build# echo 'int main(){}' > dummy.c
(lfs chroot) root:/sources/gcc-9.2.0/build# cc dummy.c -v -Wl,--verbose &> dummy.log
(lfs chroot) root:/sources/gcc-9.2.0/build# readelf -l a.out | grep ': /lib'
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
3、实操环境的搭建及注意事项
3.0. 虚拟机操作系统安装
- 安装Oracle VitrualBox
- 下载ubuntu20.04-desktop的ISO文件
- VXBOX添加新虚拟机ubuntu20.04,内存设置8GB,CPU4核,第一块硬盘10GB,第二块硬盘50GB
- 选择英文安装(避免后续可能出现的一切关于语言的系统错误)
- 选择最小化安装(尽量避免非要的软件带来系统错误)
- 系统安装到10G硬盘(/dev/sda)
- ubuntu安装完成
- fdisk -l查看可用硬盘(50GB硬盘当为/dev/sdb,且此时不存在文件系统)
- fdisk /dev/sdb 创建分区(n回车,一路默认值回车,完成后w回车保存退出)
- mkfs.ext4 /dev/sdb1 格式化分区
- 创建/mnt/lfs目录
- 修改/etc/fstab文件,添加挂载信息,50G硬盘/dev/sdb1挂载到/mnt/lfs
- 安装gcc,make,perl等安装VXBOX增强功能必须的依赖软件
- 安装VXBOX增强功能(必须装,使用虚拟终端可能会出现各种不可知的情况,本文将在虚拟机中直接操作编译过程,确保无重启、无tty断连等干扰情况。同时,LFS手册在物理主机中打开,并使用VXBOX的增强功能,将物理主机中的命令粘贴到虚拟机的Terminal中)
- 物理机控制面板->硬件和声音->电源选项->更改计划设置->接通电源->从不关闭显示器,从不睡眠 -> 更改高级电源设置 ->电源按钮和盖子 ->合上盖子的操作 ->接通电源 ->不采取任何操作 -> 确定 -> 保存修改
- ubuntu虚拟机->Settings ->Privacy-> Screen Lock ->Blank Screen Delay -> Never
- 如果临时有事需要暂停编译,请等待当前软件包编译或安装的步骤结束后,使用VXbox的镜像功能,先备份一个当前镜像,然后在ubuntu虚拟机右上角点关闭按钮,弹出的确认页面选择挂起功能,以避免重启可能会带来的失败风险。
3.0. 虚拟机备份
建议在如下章节完成后,使用vxbox的快照功能对当前编译环境进行备份:
- 《2.2. 宿主系统要求》章节的要求通过以后
- 《5.10. GCC-9.2.0 - 第 2 遍》章节完成以后
- 《5.36. 改变属主》章节完成以后
- 《6.21. GCC-9.2.0》章节完成以后
- 《6.77. Eudev-3.2.8》章节完成以后
4、LFS操作过程记录
在LFS手册中,CTRL+C
切换至ubuntu环境下,CTRL+V
然后,结果如下: