记一次如何手动编译一个linux内核
记一次记一次如何手动编译一个linux内核并从 QEMU 测试到替换宿主内核
#### 特别声明与警告
⚠️ 警告:本文涉及修改和替换系统的核心组件(内核)。此操作具有一定风险,可能导致系统无法启动。
实验环境: 整个过程必须在虚拟机(如 VMware Workstation 或 VirtualBox)中进行。虚拟机提供的“沙盒”环境,可以大胆尝试而无需担心损坏物理主机系统。本文所有操作均在 VMware Workstation 17 Pro 中完成。
备份: 在进行替换内核操作前,务必为你的虚拟机创建一个快照。如果操作失误,你可以快速回滚到之前的状态。
适用范围: 本文旨在用于学习和测试目的。请不要在生产环境或你无法承担风险的机器上直接操作。
使用以下命令查询当前系统内核版本:
1
uname -r

实验目标
- 在 Ubuntu 24.04 中从国内镜像站下载并编译 Linux 内核源码(版本 6.16.7)。
- 使用 QEMU 模拟器测试新编译的内核和初始内存磁盘(initramfs),确保其能正常启动。
- 将经过测试的内核安装到宿主 Ubuntu 系统中,并使其成为默认启动选项。
第一步:安装必要的编译工具和依赖库
打开终端 (Ctrl+Alt+T),执行以下命令来安装所有必要的工具:
1 | sudo apt update && sudo apt upgrade -y |
第二步:从清华大学镜像站下载 Linux 内核源码
为了避免网络问题,我们使用 wget 从国内镜像站下载压缩包。本文使用清华大学镜像源。
1 | # 先回到当前用户的目录 |

第三步:配置内核 - 关键步骤:确保驱动支持
这是最关键的一步,这一步我们不仅要生成默认配置,还要确保内核支持从 initramfs 启动,这是现代 Linux 系统启动的标配
生成默认配置:
1
2
3
4
5# 首先进入源码目录 (注意目录名已变为 linux-6.16.7)
cd linux-6.16.7
# 随后生成默认配置
make defconfig
深入配置以启用必需驱动:
运行make menuconfig进行更详细的检查。我们需要确保以下选项被启用:1
make menuconfig
在打开的界面中,逐项检查并确认以下选项:
General setup —>
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support**【这是非常关键的一项,必须为 】*
Device Drivers —>
- Block devices —>
<*> RAM block device support【确保编译进内核,而不是 M】(65536) Default RAM disk size (kbytes)【保持默认或调整,64MB 通常足够】
- Block devices —>
[*] The Extended 4 (ext4) filesystem【与宿主系统保持一致,通常是 ext4,如果是Btrfs或者其他的请自行更改】[*] Second extended fs support【保留 ext2/ext3 支持,这里注意,第一次切换是[M]而不是[*]】
SCSI device support —>
<*> SCSI disk support【QEMU 的虚拟硬盘通常是 SCSI 或 VirtIO】

Miscellaneous filesystems —>
[*] SquashFS 4.0 - Squashed file system support【initramfs 中可能用到】
使用空格键切换选择状态:
*是编译进内核,M是编译为模块。对于启动最核心的驱动(如 RAM disk, ext4),建议直接编译进内核(*),以避免模块加载问题。配置完成后,保存并退出。
第四步:开始编译内核
使用多线程编译以节省时间。这里的 $(nproc) 会自动获取你 CPU 的核心数。
1 | make -j$(nproc) |


这个过程的长短取决于你的CPU性能,如果你给虚拟机分配的核心数比较少可能会导致虚拟机卡顿,但是完成后应该就好了,中途如果有warning可以忽略,如果出现error请自行回头检查是否遗漏或者多选了哪些选项导致,如果完全安装本教程来的我也不知道怎么办了,反正人和代码有一个能跑就行,完成后核心产物是 arch/x86/boot/bzImage

第五步:使用 BusyBox 制作简易根文件系统 (initramfs)
我们需要一个最小的根文件系统来在 QEMU 中测试内核。
下载并编译 BusyBox:
1
2
3
4
5
6cd ~
# 下载 BusyBox (可能需要魔法,没有魔法的话也可以寻找国内镜像源或者试多几次)
wget https://busybox.net/downloads/busybox-1.37.0.tar.bz2
tar -xvf busybox-1.37.0.tar.bz2
cd busybox-1.37.0
make menuconfig进入 Settings —>,选中
[*] Build static binary (no shared libs),然后退出并保存
这里有一个坑,因为 BusyBox 1.37.0 版本与当前系统的内核头文件不兼容,特别是网络工具
tc(Traffic Control) 相关的代码,这个会导致编译时报错,解决方法是禁用tc,这是最快最简单的解决方案,因为我们只是用 BusyBox 制作一个简单的 initramfs,并不需要 TC 功能Networking Utilities —>
[ ] tc
然后又开始漫长的编译环节
1
make -j$(nproc) && make install
设置初始化脚本和打包:
1
cd _install
进入该目录后输入
ls命令你应该能看到这几个文件:binlinuxrcsbinusr1
mkdir -p proc sys dev etc
创建并编辑初始化脚本
init,内容可以自行更改,但是尽量不要出现中文:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20cat > init << EOF
#!/bin/sh
echo "This is the Linux kernel compiled by feng."
echo "Mounting proc, sys, dev..."
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
# 创建控制台设备并设置权限
mknod -m 660 /dev/console c 5 1
mknod -m 660 /dev/tty0 c 4 0
mknod -m 660 /dev/ttyS0 c 4 64
echo "Booting completed successfully."
# 使用 setsid 启动 shell 以确保它有控制终端
exec setsid /bin/sh -c 'exec /bin/sh </dev/ttyS0 >/dev/ttyS0 2>&1'
EOF赋予执行权限并打包:
1
2
3chmod +x init
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
cd ~
第六步:在 QEMU 中测试内核
这是验证我们编译的内核是否成功的重要一步。如果 QEMU 都无法启动,绝不能安装到宿主机。
1 | qemu-system-x86_64 \ |
注意 -append 参数使用了 rdinit=/init,这是专门指定 initramfs 中的初始化脚本。路径已更新为 linux-6.16.7。
如果成功看到 shell 提示符 / #,说明内核编译和 initramfs 制作成功,输入uname -r可以看到linux内核的版本,右边是ubuntu的内核版本:

可以看到前三行是自定义的init脚本的输出内容,表明内核成功启动并挂载了必要的文件系统。
最后一行 /bin/sh: can't access tty; job control turned off 是正常的,特别是在这种简单的 initramfs 环境中
输入 poweroff 或按 Ctrl+A 然后 X 退出 QEMU。
这里多嘴提一句,在make menuconfig时我们是可以自定义可以通过内核配置界面设置本地版本:
运行
make menuconfig导航到:
1
2General setup --->
() Local version - append to kernel release在其中输入你的自定义后缀,比如我这里:
-feng-compiled保存配置并重新编译内核即可

注意事项
- 修改
EXTRAVERSION会影响内核模块的命名,所有内核模块也会带有这个后缀。 - 如果你已经安装了之前编译的内核到宿主机,你需要重新安装新编译的内核包。
- 确保你的自定义后缀不包含空格或特殊字符,最好只使用字母、数字和连字符。
完成这些步骤后,你的自定义内核就会显示你想要的版本名称了
第七步:编译并安装内核到宿主机系统
大家可以尝试使用QEMU进行冒烟测试,这样就可以放心地将内核安装到宿主机了,真机也可以,这里时间问题就不进行测试了,我们直接安装到宿主机中
编译内核并生成 Debian 安装包:
回到内核源码目录,使用以下命令来生成便于安装和管理的.deb包。1
2
3
4
5cd ~/linux-6.16.7
# 清理之前的编译结果(可选)
make clean
# 重新编译并打包
make -j$(nproc) bindeb-pkg这一步可能会报错提示缺少默默依赖包,解决方法是他说缺哪个我们就去安装哪个,直到可以编译为止:


这个过程结束后,会在内核源码目录的上一级目录(即
~/)生成几个.deb文件,例如linux-image-6.16.7_6.16.7-1_amd64.deb。
安装编译好的内核包:
使用dpkg命令安装生成的包,我们需要安装以下两个核心包(版本号会根据你的实际编译结果变化):1
2cd ~
sudo dpkg -i linux-image-6.16.7-feng-compiled_6.16.7-5_amd64.deb linux-headers-6.16.7-feng-compiled_6.16.7-5_amd64.deb`linux-image-*`: 包含内核本体和 initramfs 镜像。linux-headers-*: 包含内核头文件,用于编译外部内核模块(如 NVIDIA 驱动)
安装程序
dpkg会自动调用update-grub,将新内核添加到 GRUB 启动菜单中不出意外的话应该会如图所示:

第八步:重启并进入新内核
重启系统:
1
sudo systemctl reboot
选择新内核启动:
在 GRUB 启动菜单出现时,迅速按下Shift键(对于 BIOS 启动)或Esc键(对于 UEFI 启动)以显示菜单选项。
选择 “Advanced options for Ubuntu”,然后选择你刚编译的 “Ubuntu, with Linux 6.16.7” 启动项。


验证:
系统启动后,打开终端,输入:1
uname -r
如果输出显示
6.16.7,那么恭喜你!你已经成功使用自己手动编译的 Linux 内核了!
故障排除与回滚
如果新内核无法启动: 别担心,这正是我们做快照的原因。
重启虚拟机,在 GRUB 菜单中选择之前默认的旧内核启动(例如
6.14.0-xx-generic)。启动成功后,你可以卸载有问题的自定义内核:
1
2
3# 请使用实际安装的包名,可以通过 dpkg -l | grep linux-image 查看
sudo apt remove linux-image-6.16.7 linux-headers-6.16.7
sudo update-grub或者,最推荐的方式:直接使用 VMware 的快照功能回滚到安装前的状态,这是最干净、最安全的方式。
总结
本次实验我们成功完成了既定目标:
- 安全环境:在 VMware 虚拟机中操作,风险可控
- 获取与配置:下载源码,并重点配置了 RAM disk 和 initramfs 等关键驱动
- 初步验证:使用 QEMU 模拟器进行“冒烟测试”,确保内核基本功能正常
- 生产安装:通过生成
.deb包的方式,将测试通过的内核成功地安装到宿主机 Ubuntu 系统中


