Linux from Scratch 编译笔记
久闻大名,然而真的编译了几圈下来,和想象中的不太一样。照着手册一步一步来并不难,但是特别繁琐。其实我更建议去看一看Alpine等更精简的Linux的构建过程。哦,对了,我等编译的时候通关了蔚蓝a面
LFS的主要目的是教你打造一个你自己的发行版,所以它特别繁琐。如果你想自己做一个优麒麟去骗钱那不妨看看。如果想了解一下Linux的依赖和编译过程,想看看一个特别精简版的Linux长什么样子,请试试Alpine而不是LFS
感觉Alpine更适合作为一个 玩具来学习,而LFS更适合作为正经用途。 大家不知为何都反着来。
推荐阅读:不要在生产环境中使用alpine基础镜像 – 容器基础镜像的选择
之前觉得就是一个安装超麻烦版的Arch/Gentoo,就没试过。最近终于试了一下,学到的东西倒不是很多,没有当时第一次完整安装Arch时的收获大。
这个东西告诉你linux里面glibc之类的依赖关系是什么样的。这个东西就像单片机最小系统一样,告诉你。你可以从头开始看一看系统是怎么从源码构建的,glibc那一堆依赖又是怎么鸡生蛋、蛋生鸡的。推荐想了解系统构建依赖的Linux用户看一看这个东西。
闲着没事的人最适合玩一玩这个了,不过不太推荐日常使用。虽然还是是有一些人真的把这个当日用主力的,比如fcitx输入法初代目鱼王(Yuking)就是在LFS上面写了早期的fcitx输入法。
LFS is free if your time is free.
更新
最近找资料的时候无意间又看到了一本书,,是在找《深度探索嵌入式操作系统 从零开始设计、架构和开发》的时候看到的,名字叫《深度探索Linux操作系统 系统构建和原理解析》,这本书和LFS比起来多了一些原理的讲解。13年出版的,里面的很多内容相比LFS有点老了,我挑了3、4、5章的内容翻了翻,感觉还可以。这本书后面还讲了x window和桌面图形渲染那些,不太感兴趣没看。这本书貌似也没有出后续的再版,而且穿插着操作和讲原理有点乱。中间那些initramfs、vmlinuz和根文件系统讲的还算详细,其他的感觉交叉编译和链接那些不如看别的书, 比如《程序员的自我修养》,后面那些图形界面和渲染感觉不如直接去玩玩Unity之类的东西,x window那些感觉不如自己整个dwm玩。
这种东西感觉不太适合写书,像LFS做成小册子那样持续更新比较好,如果想真的编译一个还是推荐LFS,或者操作和原理分开写。
准备工作
首先去找一个好一点的机器用来编译。你要有一个宿主机,一般用Ubuntu 20的比较多一点,我用的Arch, 暂时没遇到什么大问题。
然后下载LFS的手册和源码,我用的是最新的r11.0-92这个版本:https://www.linuxfromscratch.org/lfs/downloads/development/
手册说的wget-list没有说在哪,wget-list 可以用香港的镜像: https://lfs-hk.koddos.net/lfs/view/r11.0-92/wget-list
如果想稳一点可以用stable版本,喜欢systemd可以用systemd版本(最近对systemd全家桶有点怨念,就不上systemd了)。
编译流程
这里面绝大部分编译都是make那一套流程。
1 | ./configure |
个人的改动
其实不太建议第一次就用dev版本还加上一大堆自己的改动。我自己乱改,前面几次都没有开机成功,反复编译了四五次才成功开机。
我和手册有些出入的地方
手册里面要求使用bash,我在宿主机一直都用的zsh,好在没出什么大问题(主要是想接着用我习惯的那几个插件和语法,反正这个东西兼容sh,问题不大)(不要学我,坑特别多)
chroot之后用的是bash,然而看到那个没有自动补全和色彩高亮的bash, 我不能接受,于是配了半天的
分区我只分了一个100G的/
分区,swap和boot都是和Arch共用的。(我懒)
一些手册上有但我没编译和安装的东西
现在看文档基本都在浏览器上面搜了,很少看本地目录的文档,那些doc之类的东西我基本上都没装。没用默认的vim,参考BLFS的手册装了一个我习惯的neovim
Meson这个包编译报错了,这个是systemd和BLFS需要的,我就没管
1 | (lfs chroot) root:/sources/meson-0.60.2# python3 setup.py build |
加快速度
多核编译
通常可以直接拉满,比如我的宿主机最多能-j20
那就export MAKEFLAGS='-j20'
。
需要注意的是有的时候必须用-j1
参数,比如编译binutils
多核压缩解压
xz压缩格式,使用最新版的tar看起来默认就是多核的。加上参数之后XZ_OPT='-T0' tar -xf linux-5.15.2.tar.xz
和直接tar -xf linux-5.15.2.tar.xz
没有区别。
有几个gz后缀的使用pizg
应该会快一点,但是这几个文件太小了,几乎没区别。
备份
第七章结尾会教你tar -cJpf $HOME/lfs-temp-tools-r11.0.92.tar.xz .
进行备份,这个备份速度很慢,比上面那些解压慢不少。
我推荐使用Btrfs snapshot,在每次重要的make都建立一个snapshot,这样不用从头开始,而且备份和恢复的速度也很快。
其他的一些小问题
i和l
Iana-etc
这里是大写的i
,不是小写的L
,另一个叫Inetutils
的也是。
chroot的时候PTY allocation request failed
我是ssh连的另一台电脑编译的(本地和远程都是Arch),结果有一天突然PTY allocation request failed
我以为是chroot或者ssh的问题,穷尽毕生所学调试了半个小时,结果发现是那台服务器的校园网账户欠费了。
一些编译报错
编译findutils报错,但是装上去能用。
1 | /sources/findutils-4.8.0/find/pred.c:751: undefined reference to `rpl_fnmatch' |
编译gzip时报错:
1 | In file included from ./lib/getopt.h:84, |
执行make clean
后错误消失。
make check
失败一项:FAIL: help-version
,这个影响不大,忽略。
在编译Patch的时候发生了同样的报错,重新编译后成功。
1 | In file included from ../lib/getopt.h:84, |
怀疑是多线程编译的问题,采用make -j1
和make -j20
分别编译了10次,发现这个问题确实是在-j20
多线程编译时才会发生。
编译内核
接下来就是重头戏编译内核了。编译内核这个gentoo用户应该很熟悉了。可以自己选择编译参数,没有什么特殊喜好就默认吧。
编译速度比想象中的快,我从下午2:49编译到3:17,大概半个小时左右。
魔改编译参数请量力而行。我前面几次都自己改了很多参数,编译虽然没报错,但是启动的时候CapsLock和ScrollLock同时闪烁,只能重新编译。
编译时make clean和make mrproper的区别
make mrproper
相比make clean
多删除了config文件。
启动引导设置
设置Grub的时候记得备份你宿主机的grub!
本来我是想用Arch的os-prober
自动识别grub-mkconfig -o /boot/grub/grub.cfg
,但是不行。这样会识别成Arch Linux, with Linux 5.15.2.-lfs-r11.0.92
在Archlinux宿主机中编辑Grub,加上:
1 | menuentry "GNU/Linux, Linux 5.15.2-lfs-r11.0-92" { |
Fly Bitch!
到这里我已经累了,BLFS已经不打算再弄了,没啥意思。Nvidia驱动,折腾了好几次,想用dkms装驱动结果都失败了。最后我把Nvidia独显拆了,整个世界都美好了。
试图整个KDE桌面上去,结果一堆依赖没成功,结果发现最容易的反而是dwm。。。
小结
终于记住了tar命令解压时候哪个参数是压缩哪个是解压。
不过sed还是不太会用,已经被sd惯坏了。
发现了starship这个不错的prompt,bash上很舒服,体验接近powerlevel10k。
LFS的企鹅LOGO真的好丑啊,见过的最丑的企鹅。
bash里+h
关闭hash查找。这个参数的意思是不使用当前hash表里面存放的路径,精确的使用现在给出的路径。使用set +h
关闭hash,使用set -h
启用hash。(我总觉得+h
才是开启hash, 真是令人迷惑)
断断续续折腾了四五天,等编译期的间隙里蔚蓝从3a跳到了到7a登顶。
编译时无聊发现的其他东西
这几天在等编译的时候闲着没事发现了其他一些有意思的东西。
编译
https://github.com/dcjones/mk plan9的mk
bash和zsh的环境变量是怎么传递和继承的
login shell 和 nonlongin shell的读取环境变量方式不太一样
zsh里面的‘-’命令是干什么的
zsh的文档是这样说的:
1 | - |
看起来似乎它会在argv[0]
前面加上一个-
,可是这有什么用?
argv[0]你可以当作execve的第一个变量,通常是\bin\bash
这样的可执行路径。
再看一下exec这个命令,参数-l
的效果和zsh里面的-
是一致的
1 | exec [ -cl ] [ -a argv0 ] |
哦,就是把当前shell视为login shell,试了一下看起来的确是这样
1 | ❯ echo $0 |
链接
Linux from Scratch with Training Wheels
Alpine
What is the purpose of the hash command?