前言

LFS(Linux From Scratch)是一本指导从源代码构建Linux系统的电子书。通过LFS,可以得到一个及其精简,完全适合特定硬件的Linux系统,同时对Linux系统的结构和软件编译过程有更深入的了解。

4年前曾尝试过LFS8.0,因为水平有限卡在了内核配置上,编译出的内核没进入用户空间就panic,于是烂尾,留下了遗憾。之后一直对LFS念念不忘,现在趁暑假有时间,再次尝试LFS。

使用的LFS版本是8.4 SysV,其它版本的LFS章节序号可能与本文不对应

准备工作

  • 宿主机系统
    宿主机系统需要能通过LFS手册提供的version-check.sh脚本的环境检查,gcc版本和内核版本越接近lfs所用的版本越好,可以降低出现玄学问题的概率
    理论上任何一个linux发行版都可以,不过根据LFS用户的反馈,Ubuntu很接近LFS环境要求,并且由于使用ubuntu进行LFS的人多一些,出现问题查找到解决方案的几率也更大,因此更容易成功。为了让这次进行LFS的过程顺利些,我用ubuntu 20.04 LTS作为宿主机环境

  • 划分出LFS分区
    不需要太大,如果不打算把完成的LFS系统拿来用,10G就够了,要用就视情况划分,可以单独划分分区给某些挂载点(/home,/boot等),就像安装普通的发行版一样

  • 梯子
    不是必须,但是出现问题时需要上google搜索。国内访问LFS官网和一些含有有用信息的网站有时会很慢

  • 准备好LFS-BOOK和源码包
    LFS提供了一个wgetlist来下载所有源代码包,使用的都是国外镜像站的地址,国内下载很慢甚至根本无法下载。幸好中科大镜像站的lfs源提供了所有软件源码包的打包,下载对应版本的tar包就行,它包含了所有源码包。

  • 可靠的电力供应
    如果电脑性能一般,gcc的编译时间可能会非常长。小心这个过程中不要断电了
    如果因为某些原因离开LFS编译环境(如重启),需要根据第2.3节恢复LFS环境

调整宿主机环境

首先运行一下LFS书提供的version-check.sh脚本,根据输出内容调整宿主机系统软件包
运行脚本之后,发现ubuntu20.04有这些问题:

  1. /bin/sh没有链接到bash
  2. bison命令为找到(缺少软件包)
  3. yacc未找到
  4. gawk未找到
  5. m4未找到
  6. makeinfo未找到

问题还真不少,一个一个来解决
ubuntu默认将/bin/sh链接到dash,而lfs构建要求链接到bash
执行sudo dpkg-reconfigure dash取消将dash设为默认shell
然后执行ll /bin/sh可以看到已经链接到bash了

命令未找到只需安装对应软件包即可
使用包管理安装bison,gawk,texinfo

再次运行脚本检查一下环境,没有问题了

之后跟着手册指导完成准备工作

构建工具链

挂载LFS分区,设置好环境变量
将中科大镜像站下载的源代码合集tar包解压到$LFS/sources下,然后开始构建工具链

第一个编译的软件包是Binutils,LFS手册以第一次编译它的时间作为SBU时间衡量单位,通过time make来对编译过程计时。这个时间用来估计后面每一个软件包的构建时间
整个LFS过程中编译耗时最久的地方是正式编译LFS系统的gcc,算上测试时间大约是92 SBU,也就是第一次编译Binutils的时间的92倍

我的CPU是Intel Xeon X5680,已经面世12年了,构建Binutils花费的时间是2分45秒

第五章的内容是构建工具链,这一章没有必要对编译后的软件进行测试,只要工具链基本功能正常(编译出dummy.c的二进制能正常链接)就可以放心继续。在第6.10节调整工具链中会在继续之前对工具链再次检查

5.30编译python有个坑,pdf格式的手册给出修改setup的命令会导致修改后的setup.py脚本缩进不正确从而导致编译失败,需要手动定位到第467行修正缩进

编译LFS系统

从第五章结尾的改变/tools目录所有者开始,需要一直使用root权限

从这一章开始LFS手册会建议对每个软件包进行测试,可以只做必要的测试(Binutils,glibc,gmp,mpfr,gcc),这样可以节约时间。如果编译套件没有问题,编译其它软件出现问题一般只是因为没有在编译前正确配置,或者是某个依赖没有正确安装,这种情况很好处理。如果编译套件的测试没有通过就是大麻烦了,这种问题有时难以定位其根源,可能在构建工具链时就出现了错误,在最坏的情况下需要从头开始构建工具链。

gcc的测试可能会因错误终止,如果之前的操作正确,一般可以认为是正常的错误,放心继续就好
我的gcc测试结果如下,有几百个错误,但最后还是成功完成了LFS

		=== g++ Summary ===

# of expected passes 125327
# of expected failures 504
# of unsupported tests 4931
/sources/gcc-8.2.0/build/gcc/xg++ version 8.2.0 (GCC)

=== gcc tests ===
--
=== gcc Summary ===

# of expected passes 130916
# of unexpected failures 1
# of expected failures 393
# of unsupported tests 2107
/sources/gcc-8.2.0/build/gcc/xgcc version 8.2.0 (GCC)

--
=== libatomic Summary ===

# of expected passes 54
=== libgomp tests ===


Running target unix

=== libgomp Summary ===

# of expected passes 1837
# of unsupported tests 192
=== libitm tests ===


Running target unix
--
=== libitm Summary ===

# of expected passes 42
# of expected failures 3
# of unsupported tests 1
=== libstdc++ tests ===


--
=== libstdc++ Summary ===

# of expected passes 12193
# of unexpected failures 6
# of expected failures 71
# of unsupported tests 306

Compiler version: 8.2.0 (GCC)

配置系统

这一步需要写几个配置文件,手册写得比较难懂,不过就算不太明白也能照着手册内容完成。即使一些非关键配置不正确,最后也能成功进入系统。

内核配置比较复杂,但如果只是为了尽快完成LFS,在内核配置上可以不那么较真,在make defconfig的基础上选上对应驱动和文件系统支持的内核一般就可以用。看不懂的选项保持默认值就好

安装好内核后,配置好引导加载器就该重启进入LFS系统了。LFS提供的grub可以不用,通过宿主系统的引导加载器添加LFS启动项就行

完成之后

到lfs官网去注册一下,看看你是第几个!
我的注册结果
如果有兴趣可以继续进行BLFS,把LFS打造成能够日常使用的系统

出现报错怎么办

LFS手册中的命令都是测试过了的,严格按照手册指导来进行LFS是不太可能出现重大错误的,除非从一开始宿主机环境就没有配置好。当出现编译错误时,应该首先检查一下是不是漏掉了某一步,或者是命令敲错了

如果在操作正确的情况下出现了一些非致命错误,应该先看手册中是否提到过错误可以忽略,如果没有,找到LFS8.4对应的build log看一下LFS的编者在构建过程中是否出现的同样的输出信息,如果有,则可以安全地忽略它,否则可能需要在继续编译之前进一步检查

当然,构建LFS的过程不一定有那么顺利,因为宿主机系统环境的不同,严格按照手册指导可能还是出现了意料之外的问题。这时候应该去网络上寻找答案了。一般提取报错信息的关键段并后面加上lfs的关键词到google上搜索可以找到相关帖子。大部分解决方案来自linuxquestions.org论坛的lfs板块。

如果这个问题没有人问过就只能自己发帖求助了。在LQ论坛上应该贴出LFS版本,宿主机系统,出现问题的章节,足够多的报错信息并且说明情况,最好附上version-check.sh的输出。

后记

LFS构建真的是体力活,需要耗费大量的时间,还需要有足够的耐心,在出现问题时能正确排查错误
至于收获?
收获最大的应该是敲键盘的手速吧
成果

LFS构建过程记录

2021-06-28 安装ubuntu用来编译LFS,调整宿主机环境
2021-07-01 开始编译,进行到第6.12节
2021-07-02 完成