> [!WARNING] > 当你开始定制内核的时候,你将会有大把时间用来浪(**xué**)费(**xí**)。 > > 本文后续会在 gentoo wiki 更新:https://wiki.gentoo.org/wiki/User:Douglarek/Streamlining_kernel 本文灵感来自 reddit[^0] 上一位使用 Gentoo 的老哥,根据他提供的链接一路追到了他在 Gentoo wiki 上的文章[^1],他这篇文章比较简洁,只是其中一些东西没说太清楚,而且也不太符合 Gentoo 本身的做法,另外文中的 gentoo-sources 似无必要,直接使用 Distribution Kernel[^9] 即可,这两个的唯一区别是如果你需要手动编译那么使用前者即可,如果是使用常规的 emerge 安装,并且享受系统安装带来的各种便利(如各种 portage 钩子),那么使用后者即可。 本文并不打算深入内核定制的细节(目前这方面我也是新手),主打一个清晰明了的流程走通,享受定制内核带来的编译时间的极大缩短(我的测试是大约能节省 2 倍左右的编译时间)。另外亦不介绍定制后内核的引导问题,毕竟这些无论是 Grub 还是 Systemd-boot 都有相关的 portage 钩子可做,假设你已经配置(否则需要手动处理)。 本文以 gentoo-kernel 为例(假设你当前安装的是 gentoo-kernel-bin 内核),分为以下几个步骤。 ### 构建内核配置 以 gentoo-kernel 6.11.9 为例: ``` (user)$: ebuild /var/db/repos/gentoo/sys-kernel/gentoo-kernel/gentoo-kernel-6.11.9.ebuild clean configure (root)$: cd /var/tmp/portage/sys-kernel/gentoo-kernel-6.11.9/work/modprep (root)$: make localmodconfig # 基于模块的构建,或者 make localyesconfig 直接编译进内核 ``` > [!TIP] > 该步的执行基于你当前加载的硬件信息,这里有一个弊端:可能会忽略某些硬件。比如移动硬盘在这之前没插入,那么这时候 USB 相关模块是不会收集的。那么有没有更好的方式收集呢,答案是 modprobed-db [^2]。那如果执行之前把所有的硬件都插上行不行呢,也可以,但是如果之后买来了新硬件需要不同的驱动,还是需要手动配置内核编译选项。modprobed-db 安装配置完之后可以每 6 个小时收集一次当前的硬件信息更新写入 modprobed.db 文件,那么自定义内核的时候使用 `make LSMOD=$HOME/.config/modprobed.db localmodconfig` 构建即可,一般建议 modprobed-db 在你的电脑上运行一段时间(比如 2 个月)后进行内核定制。 > > 即便不用 modprobed-db,通过 Gentoo wiki 相关条目也能手动执行 `make menuconfig` 进行内核项配置,比如这里[^3]以 USB 为例。 > [!IMPORTANT] > 以上的步骤不适合大版本之间的升级,比如 6.11.x 升级到 6.12.x ,一般这种升级会有内核选项的变化,跨版本是需要更新这个 .config 文件的。 > 一般来说两种方式: > 1. `make LSMOD=$HOME/.config/modprobed.db localmodconfig` 直接在新的内核上开启需要的模块外加自己的配置 > 2. `make olddefconfig`[^8] 将保留旧 .config 中的所有选项,并将新选项设置为推荐(即默认)值 ### 自定义配置编译 保存自定义配置以便每次新内核构建时使用自定义配置: ``` (root)$: mkdir -p /etc/portage/savedconfig/sys-kernel/ (root)$: cp /var/tmp/portage/sys-kernel/gentoo-kernel-6.11.9/work/modprep/.config /etc/portage/savedconfig/sys-kernel/gentoo-kernel ```` > [!IMPORTANT] > savedconfig 和其他 portage 选项一样,都有一致的配置方式,同样遵循配置文件某种形式的优先级,可以在 savedconfig wiki 条目[^4]中具体查看。 自定义 USE 使构建使用自定义配置: ``` (root)$: mkdir /etc/portage/package.use/ (root)$: echo 'sys-kernel/gentoo-kernel savedconfig' > /etc/portage/package.use/kernel ``` > [!TIP] > 启用 savedconfig USE flag 后,编译 gentoo-kernel 内核的时候将使用自定义配置,否则将使用通用编译配置。 ### 重新构建内核 ``` (root)$: emerge -W gentoo-kernel-bin (root)$: emerge -av gentoo-kernel (root)$: emerge -av @module-rebuild ``` > [!NOTE] > 1. 这里解释一下为什么要先取消选择 gentoo-kernel-bin 然后安装 gentoo-kernel 呢,首先这两个不能同时存在,有冲突的;其次 gentoo-kernel 是可编译内核,简单说就是 emerge 的时候会进行编译,而 gentoo-kernel-bin 不会,虽然后者也是带源码和 gentoo 补丁的。 > 2. 如果你是 N 卡用户,@module-rebuild 这一步几乎是必须的,如果你频繁定制同一版本的内核,很容易遗漏这一步;Dracut 只会在内核升级的时候触发 @module-rebuild。 ### 定制前后对比 构建时间[^5](`qlop -vHt gentoo-kernel`)[^6]: ``` 前:2024-11-15T21:26:12 >>> sys-kernel/gentoo-kernel-6.11.8: 40 minutes, 8 seconds 后:2024-11-15T23:33:06 >>> sys-kernel/gentoo-kernel-6.11.8: 11 minutes, 28 seconds ``` 安装大小[^7](`qsize gentoo-kernel`): ``` 前:sys-kernel/gentoo-kernel: 24177 files (24175 unique), 4500 non-files, 1.0G 后:sys-kernel/gentoo-kernel: 14565 files (14563 unique), 3550 non-files, 586.0M ```` ### QA #### 内核这样定制是最简了么 显然不是,即便是通过 `make localmodconfig` 精简后的内核依然有很大的精简空间(比如文件系统,网络等),精简内核一切尽在 `make menuconfig`。 #### 我编译完内核重启后无法进入桌面系统 这种情况是存在的,基本上两个方法:1. 看 tty 是否可以进 2. 通过 minimal cd 进入。然后通过 `emerge -W gentoo-kernel` 以及 `emerge -av gentoo-kernel-bin` 装回通用预编译内核即可。 [^0]: https://www.reddit.com/r/Gentoo/comments/updoaz/comment/i8k5kpl [^1]: https://wiki.gentoo.org/wiki/User:Flexibeast/guides/A_minimal_Gentoo_kernel_for_your_hardware [^2]: https://wiki.gentoo.org/wiki/Modprobed-db [^3]: https://wiki.gentoo.org/wiki/USB/Guide#Mounting_a_USB_mass_storage_device [^4]: https://wiki.gentoo.org/wiki/Savedconfig [^5]: `CPU: AMD Ryzen 5 5600X (12) @ 4.65 GHz`,`MAKEOPTS="--jobs 8 --load-average 9"` [^6]: qlop 可以使用 `emerge --ask app-portage/portage-utils` 安装,qsize 也属于该软件包,具体参见:[Q_applets](https://wiki.gentoo.org/wiki/Q_applets) [^7]: 这里的安装文件之所以这么大,原因是 gentoo-kernel 默认被开启了 debug,如果 -debug,那么尺寸还能更小(我本机是 `152.5M`) [^8]: https://wiki.gentoo.org/wiki/Kernel/Upgrade [^9]: https://wiki.gentoo.org/wiki/Project:Distribution_Kernel