3. 内核编译实战:从源码到可运行内核的完整流程
说实话,很多做驱动的朋友一开始就卡在编译这一步。不是缺工具链,就是配置选项选错,折腾半天连个内核都跑不起来。今天我就带你走一遍完整的流程——下载、配置、编译、安装,每一步我都会告诉你哪些坑我踩过。
3.1 下载内核源码
内核源码的获取方式有好几种,我个人最推荐去 kernel.org 下载主线版本。为什么?因为干净、稳定,没有发行版自己打的补丁。
常用下载方式:
- 官网直接下载:
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.tar.xz - git 克隆:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git - 发行版源码包:
apt-get source linux-image-$(uname -r)(Ubuntu/Debian)
解压也很简单:
tar -xf linux-6.1.tar.xz
cd linux-6.1
我的习惯:源码目录我一般放在 /home/<user>/kernel/ 下,而不是 /usr/src/。因为普通用户权限就能操作,避免每次都要 sudo,省心不少。
3.2 配置内核:三种方式,各有千秋
配置内核说白了就是告诉编译器:哪些功能要编译进内核,哪些编译成模块,哪些干脆不要。内核的配置选项有上万个,手动一个个选会疯掉。好在有几种工具帮我们搞定。
3.2.1 make menuconfig —— 最常用,没有之一
这是基于 ncurses 的文本界面配置工具。你想想看,在服务器上没图形界面,它就是你最好的朋友。
make menuconfig
界面操作很简单:
- 方向键:上下移动光标
- Enter:进入子菜单
- Y:编译进内核(
<*>) - M:编译为模块(
<M>) - N:不编译
- ?:查看帮助
- 空格:循环切换 Y/M/N
我曾经犯过的错:有一次我配置完直接退出,没保存。结果 .config 文件还是旧的,编译出来的内核跟预期完全不一样。记住:退出时选 Yes 保存,别手快按了 No。
3.2.2 make xconfig —— 图形界面,直观清晰
如果你有桌面环境,make xconfig 会打开一个基于 Qt 的图形配置界面。搜索功能特别方便,按 Ctrl+F 就能搜配置项。
make xconfig
我个人觉得 xconfig 的搜索比 menuconfig 好用,但前提是你得有 X11 环境。远程 SSH 连的服务器就别想了。
3.2.3 make oldconfig —— 升级内核时的救命稻草
这个命令特别适合你从旧版本升级到新版本时使用。它会拿你现有的 .config 文件,然后逐项询问新增的配置选项。
make oldconfig
它会问你类似这样的问题:
Enable new feature XYZ (NEW_XYZ) [Y/n/?] (NEW)
你直接回车就用默认值,或者输入 Y/N 选择。嗯,这里要注意:如果你不确定,就选默认值,一般不会出大问题。
3.3 配置策略:从零开始还是基于现有配置?
配置内核最怕的就是漏掉关键驱动。我建议你按这个优先级来:
| 场景 | 推荐做法 | 说明 |
|---|---|---|
| 全新配置 | make defconfig |
生成默认配置,然后手动调整 |
| 基于当前系统 | make localmodconfig |
只编译当前系统已加载的模块,省时间 |
| 升级内核版本 | make oldconfig |
保留旧配置,只处理新增项 |
| 发行版兼容 | 复制 /boot/config-* |
用当前内核的配置作为起点 |
我的建议:如果你是第一次编译,用 make localmodconfig 最省事。它会扫描你当前系统加载了哪些模块,然后只把这些模块的配置打开。编译时间能缩短 70% 以上。
3.4 编译内核:make -jN 的学问
配置搞定后,就该编译了。命令很简单:
make -j$(nproc)
-jN 里的 N 是并行编译的线程数。一般设为 CPU 核心数的 1.5 到 2 倍。比如 4 核 CPU,可以设 -j6 或 -j8。
避坑指南:我曾经在 2 核的虚拟机上用 -j8,结果内存爆了,编译到一半直接 OOM。建议内存小于 4GB 时,-j 值不要超过核心数。
编译过程大概分几步:
- 编译内核镜像:生成
vmlinux和arch/x86/boot/bzImage - 编译内核模块:所有标记为
<M>的驱动会编译成.ko文件 - 编译设备树(ARM/嵌入式平台):生成
.dtb文件
编译时间取决于你的机器配置。我见过最快的——128 核服务器,5 分钟搞定。也见过最慢的——树莓派 Zero,编译了整整 8 个小时。
3.5 安装内核模块与内核镜像
编译完成后,需要把生成的文件安装到系统里。
3.5.1 安装内核模块
sudo make modules_install
这个命令会把所有 .ko 文件复制到 /lib/modules/<内核版本>/ 目录下。比如:
/lib/modules/6.1.0-custom/
├── kernel/
│ ├── drivers/
│ ├── fs/
│ └── net/
├── modules.dep
├── modules.alias
└── modules.symbols
注意:如果你之前安装过同版本的内核模块,modules_install 会直接覆盖。建议每次编译前先 make clean,避免旧文件残留。
3.5.2 安装内核镜像
sudo make install
这个命令会:
- 把
arch/x86/boot/bzImage复制到/boot/vmlinuz-<版本> - 生成
/boot/initramfs-<版本>.img(如果配置了) - 更新 GRUB 引导配置
安装完成后,重启就能看到新的内核选项了:
sudo reboot
启动时在 GRUB 菜单里选择新内核。如果没看到,手动更新一下:
sudo update-grub
3.6 完整流程一览
我把整个流程画成了一张图,方便你对照操作:
3.7 验证安装是否成功
重启后,用这几个命令确认新内核是否正常工作:
uname -r
lsmod
cat /proc/version
如果显示的内核版本跟你编译的一致,恭喜你,成功了!
最后说一句:第一次编译内核,失败是正常的。别灰心,检查一下配置选项,看看是不是漏了某个关键驱动。我当年第一次编译,重启后直接黑屏,后来发现是文件系统驱动没编进去。嗯,这种错误犯过一次就不会再犯了。