第二章:内核源码获取与编译

好,咱们正式开始动手了。这一章要讲的是怎么把内核源码搞到手,然后配置、编译、安装,最后管理那些内核模块。说白了,就是让你从零开始,自己造一个能跑的内核。

我刚开始学内核编译那会儿,总觉得这玩意儿特别神秘。后来发现,其实流程就那么几步,但每一步都有坑。今天我就把这些坑一个一个指给你看。

2.1 从 kernel.org 获取源码

源码从哪来?当然是 kernel.org。这是官方唯一指定下载点。别去其他地方乱下,我见过有人从第三方站点下载的源码里被植入了后门,那可不是闹着玩的。

我个人习惯用 wget 直接拉取:

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.1.tar.xz

下载完记得校验签名。这一步很多人跳过,但我建议你别省。用 gpg 验证一下:

gpg --verify linux-6.6.1.tar.sign

如果提示 Good signature,那就放心了。我曾经有一次下载的包校验失败,重新下载后发现是网络传输中出了错。嗯,这种事概率不高,但碰上一次就够你折腾半天。

小技巧: 国内用户如果下载慢,可以用清华或中科大的镜像站。速度能快好几倍。

2.2 解压与准备工作

解压没什么好说的:

tar -xvf linux-6.6.1.tar.xz
cd linux-6.6.1

但这里有个细节——不要在 /root 下直接操作。我建议放在 /usr/src 或者 /home 下。为什么?因为编译过程中会产生大量临时文件,万一磁盘空间不够,你连删都费劲。

另外,确保你装了必要的工具链:

sudo apt-get install build-essential libncurses-dev bison flex libssl-dev libelf-dev

这些包缺一不可。我见过有人漏了 libncurses-dev,结果 make menuconfig 直接报错。说白了,就是准备工作没做到位。

2.3 配置内核选项:make menuconfig

这是整个流程里最核心的一步。内核配置说白了就是决定「我的内核要支持哪些功能」。功能越多,内核越大,启动越慢。功能太少,硬件可能不识别。

运行:

make menuconfig

你会看到一个蓝底白字的菜单界面。别慌,这东西看着复杂,其实逻辑很清楚:

  • Y:把这个功能编译进内核(直接内置)
  • M:编译成模块(按需加载)
  • N:不编译(不要这个功能)

我个人习惯是:能编成模块的就编成模块。比如文件系统驱动、网卡驱动这些,用 M 就好。只有那些必须随内核启动的功能,比如进程调度、内存管理,才用 Y

核心原则: 内核要小,模块要全。启动时只加载必要的,运行时按需加载模块。

你想想看,如果你把所有驱动都编进内核,那内核体积轻松超过 50MB。启动慢不说,还浪费内存。我做过一个嵌入式项目,Flash 只有 16MB,内核必须控制在 5MB 以内。那时候我真是把每个选项都抠了一遍。

2.4 编译与安装内核

配置好了,接下来就是编译。直接跑:

make -j$(nproc)

-j 参数指定并行编译的线程数。我一般用 $(nproc) 自动获取 CPU 核心数。比如你的机器是 4 核 8 线程,那就用 -j8

编译时间取决于你的机器配置。我见过最快的——一台 128 核的服务器,编译 6.6 内核只用了 3 分钟。也见过最慢的——一块 ARM 开发板,编译了整整 18 个小时。嗯,那滋味,谁等谁知道。

编译完成后,安装模块和内核:

sudo make modules_install
sudo make install

modules_install 会把模块安装到 /lib/modules/ 下。make install 会把内核镜像和 System.map 复制到 /boot 目录,同时更新 GRUB 配置。

注意: 如果你是在生产环境上操作,一定要保留旧内核。万一新内核起不来,你还能回滚。我曾经手贱删了旧内核,结果新内核有 bug,系统直接挂了。那叫一个后悔。

2.5 模块管理

内核模块这东西,说白了就是「按需加载的驱动」。你插个 U 盘,系统自动加载 USB 存储模块。你接个网线,网卡驱动模块就自动挂上。

常用的模块管理命令:

命令 作用
lsmod 列出当前已加载的模块
modinfo <模块名> 查看模块详细信息
modprobe <模块名> 加载模块(自动处理依赖)
modprobe -r <模块名> 卸载模块
depmod 生成模块依赖关系

举个例子,你想加载一个叫 usb-storage 的模块:

sudo modprobe usb-storage

它会自动把依赖的 usbcorescsi_mod 等模块一并加载。这就是 modprobeinsmod 高明的地方。

我建议你编译完内核后,先跑一遍 depmod

sudo depmod -a

这样模块依赖关系就更新了。否则你加载模块时可能会报 Unknown symbol 的错误。嗯,这个坑我踩过不止一次。

2.6 本章知识体系

下面这张图把整个流程串起来了,你可以对照着看:

内核源码获取与编译流程 获取源码 kernel.org 下载 配置内核 make menuconfig 编译内核 make -j$(nproc) 安装 make install 安装后分为两条线 模块管理 lsmod / modprobe / depmod 启动管理 GRUB 更新 / 内核选择 关键配置选项说明 Y = 编译进内核(内置) M = 编译成模块(按需加载) N = 不编译(禁用) 建议:驱动用 M,核心功能用 Y ⚠ 生产环境务必保留旧内核,新内核出问题可回滚 编译前确保磁盘空间充足(建议至少 10GB 空闲)

这张图把整个流程分成了四个阶段:获取源码 → 配置内核 → 编译 → 安装。安装后又分两条线:模块管理和启动管理。你照着这个流程走,基本不会出大问题。

好了,这一章的内容就到这儿。源码获取、配置、编译、安装、模块管理,这几步你多练几遍,熟能生巧。下一章我们会深入内核配置的细节,讲讲那些你必须要知道的选项。


专注资料整理