diff --git a/memo/lfs.md b/memo/lfs.md index 0201023..52f1b50 100644 --- a/memo/lfs.md +++ b/memo/lfs.md @@ -2,9 +2,7 @@ > [!IMPORTANT] > -> 本文中的 LFS 仅指代 12.4 SysV 版本. -> -> EDIT: 现在也适用于 13.0 Systemd 版本. +> 本文中的 LFS 仅指代 12.4 SysV 和 13.0 Systemd 版本. ## LFS @@ -20,13 +18,13 @@ ### 4.5. About SBUs -SBU 只提供大概的预期耗时范围, 误差是很大的, 尤其对于 BLFS 书中的一些编译时间很长的包 (如 Qt, Firefox) 来说. +SBU 只提供大概的预期耗时范围, 误差是很大的, 尤其对于 BLFS 书中的一些编译时间很长的包 (如 Qt, WebKitGtk, Firefox) 来说. ### 5. Compiling a Cross-Toolchain #### targo -从这一章开始将会手动编译大量的包, 其中有不少操作是重复的, 例如 `tar -xf`, `cd`, `rm -rf` 等, 为此可以写一个小脚本 targo 节省时间: +从这一章开始将会手动编译大量的包, 其中有不少操作是重复的, 例如 `tar -xf`, `cd`, `rm -rf` 等, 为此可以写一个小脚本节省时间: ```bash #!/bin/bash @@ -72,17 +70,17 @@ echo "Spawning shell. Type 'exit' to finish and cleanup." bash ``` -它的作用是解压一个只含有一个顶层目录的 tarball, cd 进入解压后得到的目录, 生成一个 shell, 并在这个 shell 退出时清理先前解压得到的文件. 在此基础上可做如下改进: +它的作用是解压一个只含有一个顶层目录的 tarball, cd 进入解压后得到的目录, 生成一个 shell, 并在这个 shell 退出时清理先前解压得到的文件. #### tmpfs 先在目标位置挂载 tmpfs 再解压文件. 编译期间会进行高频的硬盘 IO, 将此过程放到内存上可以减少硬盘损耗也可以稍稍加速. 不过有几点需要注意: -- 部分包(不在少数)的部分测试会依赖文件系统特性. 如 [Python-3.14.3](https://www.linuxfromscratch.org/lfs/view/stable-systemd/chapter08/Python.html) 的 `test_file` 测试, 如果构建目录为 tmpfs, 则会因为缓冲区大小与预期不符而出现 `AssertionError` 断言错误, 而缓冲区大小通常由底层文件系统的块大小决定, 因此是 tmpfs 导致的环境差异导致测试失败. +- 部分包(不在少数)的部分测试会依赖文件系统特性. 如 [Python-3.14.3](https://www.linuxfromscratch.org/lfs/view/stable-systemd/chapter08/Python.html) 的 `test_file` 测试, 如果构建目录为 tmpfs, 则会因为缓冲区大小与预期不符而出现 `AssertionError` 断言错误, 而缓冲区大小由底层文件系统的块大小决定, 因此 tmpfs 的环境差异会导致测试失败. -- 谨防 OOM. 多核编译本就需要耗费大量内存, 例如 [Gentoo 手册](https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Stage)中建议为每个 job 至少预留 2 GiB 内存, 而复杂的包的构建目录体积也会随着构建过程而膨胀, 二者共同作用更显内存紧张, 而如果真的触及上限, 如果有 swap 则会使用到硬盘, 这和使用 tmpfs 最初的目的相背; 如果触发 OOM Killer 更是会导致编译失败. 因此编译大包时还是建议老老实实用硬盘. +- OOM. 多核编译本就需要耗费大量内存, 例如 [Gentoo 手册](https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Stage)中建议为每个 job 预留至少 2 GiB 内存, 而复杂的包的构建目录体积也会随着构建过程膨胀, 二者共同作用更显内存紧张. 倘若真的触及上限, 如果有 swap 则会使用到硬盘, 这和使用 tmpfs 最初的目的相背; 如果触发 OOM Killer 更是会直接导致编译失败. 因此编译大包时还是建议老老实实用硬盘. -- tmpfs 造成的环境差异也会导致少数包在 configure 阶段就出现问题. 这属于少数特例, 不过多说明~~主要是忘了具体是哪个包了:/~~ +- tmpfs 的环境差异也会导致少数包在 configure 阶段就出现问题. 这属于少数特例, 不过多说明~~主要是忘了具体是哪个包了:/~~ #### 通用建议 (同样适用于其他书如 BLFS) @@ -113,6 +111,8 @@ bash [ -z "$LFS" ] && exit 1 +set -euo pipefail + # mount virtual file systems mkdir -pv $LFS/{dev,proc,sys,run} @@ -152,17 +152,17 @@ chroot "$LFS" /usr/bin/env -i \ /bin/bash --login ``` -它的作用是自动挂载一系列虚拟文件系统, 同时在退出 chroot 时自动清理. +它的作用是自动挂载一系列虚拟文件系统, 并在退出 chroot 时自动清理. 自动挂载, 自动chroot, 自动清理, 如果手动安装过 archlinux 或 Gentoo 的话可能会很快联想到 arch-install-scripts 提供的 `arch-chroot` 脚本. 但此处并不推荐用此方法偷懒, 原因有三: - `arch-chroot` 挂载 `/dev` 的方式为 `mount -t devtmpfs` 而非 `mount --bind`, 这会导致 `/dev/fd` 等核心软链接消失从而诱发很多问题, 例如交叉编译的工具链完全不可用. -- `arch-chroot` 并未清空环境变量, 这会对环境隔离造成影响. 同时 `arch-chroot` 也没有设置 `MAKEFLAGS`, `TESTSUITEFLAGS` 等关键的环境变量, 后续在别的地方设置. +- 默认 offline mode 不会像 LFS 书里那样用 env -i 构造最小环境, 这会对环境隔离造成影响. 同时 `arch-chroot` 也没有设置 `MAKEFLAGS`, `TESTSUITEFLAGS` 等环境变量, chroot后需要在别处设置. - `arch-chroot` 会将 Host 的 `/run` 通过绑定的方式挂载, 这也会对环境隔离造成影响. -另外再多说一嘴, 将 `$LFS/dev/pts` 挂载为全新的 tmpfs 会导致 TTY 上下文丢失, 进而导致非 root 用户执行 su 时遇到 `su: must be run from a terminal` 错误. 有两个解决方向: +另外再多说一嘴, 将 `$LFS/dev/pts` 挂载为全新的 devpts 会导致 TTY 上下文丢失, 进而导致非 root 用户执行 su 时遇到 `su: must be run from a terminal` 错误. 有两个解决方向: - 使用 `mount --bind` 挂载 `$LFS/dev/pts` 从而保留 TTY 上下文. @@ -181,7 +181,7 @@ chroot "$LFS" /usr/bin/env -i \ ### 10.2. Creating the /etc/fstab File -可以使用 `arch-install-scripts` 提供的 `genfstab` 偷懒. +可以使用 `arch-install-scripts` 提供的 `genfstab` 生成 `/etc/fstab` 作为起点, 但仍需手动检查. > [!IMPORTANT] > @@ -189,24 +189,22 @@ chroot "$LFS" /usr/bin/env -i \ ### 10.3. Linux -正如书中所说, - > Building the linux kernel for the first time is one of the most challenging tasks in LFS. -内核配置是整本 LFS 书中最具有挑战的环节. 对此我可以总结出几点建议: +确实如此. 对此我可以总结出几点建议: - initramfs LFS 本书并未涉及这部分内容, 而现代成熟发行版几乎无一例外都使用 initramfs 进行引导. 有无 initramfs 对内核配置的影响是巨大的, 例如: - 挂载 RootFS 所需驱动如 `CONFIG_EXT4_FS`, `CONFIG_BTRFS_FS` 必须内置, 否则即使 Bootloader 认识 RootFS, 内核也不认识; - - 需要外部固件支持的驱动程序 (如 `i915`) 在没有 initramfs 时必须编译为模块, 否则如果提前加载将找不到对应的固件; + - 在 RootFS 可用之前就请求固件的内核模块在没有 initramfs 时需要编译为模块或将固件也嵌入内核中. 如果不急于验收的话可以暂时搁置 LFS 本书的后续章节, 先推进 BLFS 直到 [About Initramfs](https://www.linuxfromscratch.org/blfs/view/stable-systemd/postlfs/initramfs.html) 了解相关内容后再回来构建内核. 不过我其实更推荐使用 [Dracut](https://github.com/dracut-ng/dracut-ng/) 构建 initramfs, 比起 BLFS 书中的脚本要省心不少. - 内核版本 - 内核版本其实并没有那么重要. 更新内核版本几乎不会对系统造成什么兼容性问题 (除了树外模块如 NVIDIA 专有驱动, 之后再提). 使用和 Host 相同版本的驱动可以很方便地复用配置, 当前 Host 加载的模块信息也能为内核配置提供参考. + 内核版本其实并没有那么重要. 更新内核版本几乎不会对系统造成什么兼容性问题 (除了树外模块如 NVIDIA 专有驱动, 之后会细说). 使用和 Host 相同版本的驱动可以很方便地复用配置, 当前 Host 加载的模块信息也能为内核配置提供参考. - 复刻并裁剪现有配置 @@ -232,16 +230,16 @@ chroot "$LFS" /usr/bin/env -i \ make localmodconfig ``` - 如果内核版本不一致, 会在 `make localmodconfig` 时出现一些交互选项, 建议全部保持默认, 或使用 `make olddefconfig` 来自动处理. + 如果内核版本不一致, `make localmodconfig` 时会出现一些交互选项, 建议全部保持默认, 或使用 `make olddefconfig` 来自动处理. 在此之后, 仍建议 (或者说请务必) 按照 LFS 书中的指示检查和调整配置选项. - NVIDIA - NVIDIA 专有驱动的安装指引在 [GLFS 中](https://www.linuxfromscratch.org/glfs/view/stable/shareddeps/drivers-NVIDIA.html)有单独说明, 但其依赖众多, 在此之前需要安装很多 BLFS 和 GLFS 中的软件包, 因此不必心急, 可以先按需安装 BLFS 中的其他包, 等到需要 [Mesa](https://www.linuxfromscratch.org/blfs/view/stable-systemd/x/mesa.html) 作为依赖时再去 GLFS 中安装 NVIDIA 驱动, 这将会轻松不少. + NVIDIA 专有驱动的安装指引在 [GLFS 中](https://www.linuxfromscratch.org/glfs/view/stable/shareddeps/drivers-NVIDIA.html)有详细说明. 但其依赖众多, 其中包括很多 BLFS 和 GLFS 中的软件包. 因此不必心急, 可以先按需安装 BLFS 中的其他包, 等到需要 [Mesa](https://www.linuxfromscratch.org/blfs/view/stable-systemd/x/mesa.html) 作为依赖时再去 GLFS 中安装 NVIDIA 驱动, 这将会轻松不少. 关于其对内核配置的影响, 总结出来有以下两点: - - 禁用 nouveau. 除非显卡型号过于老旧, 否则不推荐使用内核中的 nouveau 驱动, 对应配置选项如 `CONFIG_DRM_NOUVEAU` `CONFIG_FB_NVIDIA` 等可留空. [GLFS 相关页面页脚](https://www.linuxfromscratch.org/glfs/view/stable/shareddeps/NVIDIA.html#ftn.idm139677630432800)有提到 + - 禁用 nouveau. 除非显卡型号过于老旧, 否则不推荐使用内核中的 nouveau 驱动, 对应配置选项如 `CONFIG_DRM_NOUVEAU` `CONFIG_FB_NVIDIA` 等可留空. [GLFS NVIDIA-590.48.01 页面页脚](https://www.linuxfromscratch.org/glfs/view/stable/shareddeps/NVIDIA.html#ftn.idm139677630432800)有提到 > NVIDIA's kernel modules will fail to compile with TTY support unless a graphics driver is included in the kernel. Nouveau is used here, though alternate graphics drivers may also work. @@ -251,9 +249,15 @@ chroot "$LFS" /usr/bin/env -i \ ### 10.4. Using GRUB to Set Up the Boot Process -强烈建议使用 PARTUUID 替代传统的 `/dev/sdXN` 设备路径以及 `(hdM,N)` 来指定 `/boot` 分区和根分区. 如果已经配置 initramfs, 则也可以使用文件系统 UUID 来指定根分区. + + +有两处需要指定分区: + +- 通过 `root=` 参数传递给内核的 RootFS 分区位置. 强烈建议使用 PARTUUID 而非 `/dev/sdXN` 这类不稳定的设备路径. 如果已经配置 initramfs, 则也可以使用文件系统 UUID 指定根分区. + +- 使用 `search` 指定的 `/boot` 所在分区位置. 强烈建议使用文件系统 UUID 即 `--fs-uuid` 而非 `(hdM, N)` 这类易受磁盘枚举顺序影响的设备记法. > [!NOTE] > @@ -299,12 +303,12 @@ meson setup build \ 其中: - `-D gallium-drivers=iris,llvmpipe`: - - `iris` 用于现代 Intel 显卡.对于较新 (Gen 8 及更新) 的硬件, `crocus` (适用于 Gen 4 到 Gen 7.5) 和 `i915` (更老) 用户态 OpenGL 驱动已被废弃, 不应再使用.注意此处的 `i915` 用户态驱动和内核中的 `i915` 模块是不同的东西; + - `iris` 用于较新的 (Gen 8 及更新) Intel 显卡. 与之对应的有 `crocus` (适用于 Gen 4 到 Gen 7.5) 和 `i915` (更老). 注意此处的 `i915` 用户态驱动和内核中的 `i915` 模块是不同的东西; - 启用 `llvmpipe` 用于 OpenGL 上下文中的软件渲染以防万一. - `-D vulkan-drivers=intel,swrast`: - 启用 Intel iGPU 的 Vulkan 支持; - - 启用 Vulkan 上下文中的软件渲染驱动“软件光栅化器” `swrast` 以防万一.注意这里的 `swrast` 实际指 `lavapipe`, 和被废弃的 gallium `swrast` 驱动是不同的东西. -- `-D glvnd=enabled`:启用 GLVND 支持. + - 启用 Vulkan 上下文中的软件渲染驱动“软件光栅化器” `swrast` 以防万一. 注意这里的 `swrast` 实际指 `lavapipe`, 和被废弃的 gallium `swrast` 驱动是不同的东西. +- `-D glvnd=enabled`: 启用 GLVND 支持. ### Better targo