2. 开发环境搭建:选择合适的Linux发行版、安装内核头文件、配置编译器、使用QEMU搭建测试虚拟机
说实话,内核模块开发的门槛并不高。但很多人一开始就栽在了环境搭建上。我见过不少朋友,兴致勃勃地写了第一行代码,结果编译都过不了——不是头文件找不到,就是编译器版本不对。嗯,这章我们就来把这摊事理顺。
2.1 选择合适的Linux发行版
先聊聊发行版的选择。我个人习惯用 Ubuntu LTS 或 Debian 做开发。为什么?因为社区活跃,遇到问题搜一下就有答案。你想想看,搞内核开发本来就够烧脑了,没必要在环境上再给自己添堵。
如果你问我推荐哪个版本:
- Ubuntu 22.04 LTS 或 24.04 LTS —— 稳定,包管理方便,内核头文件直接 apt 就能装
- Debian 12 —— 更纯粹,适合喜欢干净系统的朋友
- Fedora —— 内核更新快,但有时候太新反而容易踩坑
2.2 安装内核头文件
内核模块开发,说白了就是跟内核 API 打交道。而这些 API 的声明都在内核头文件里。没有头文件,你连 printk 都用不了。
安装方法很简单:
# 先看看当前内核版本
uname -r
# 安装对应版本的头文件
sudo apt update
sudo apt install linux-headers-$(uname -r)
# 或者直接装所有头文件(省事)
sudo apt install linux-headers-generic
装完之后,头文件会放在 /usr/src/linux-headers-$(uname -r)/ 目录下。你可以进去看看,里面有个 include/linux 文件夹,我们常用的 module.h、kernel.h 都在里面。
2.3 配置编译器
内核模块的编译器和普通应用程序不太一样。我们用的是 交叉编译工具链 吗?不,大多数情况下直接用本机的 gcc 就行。但有几个关键点要注意:
- gcc 版本不能太老 —— 建议 8.0 以上
- 必须安装 make —— 内核模块用 Makefile 来编译
- 需要 build-essential 包 —— 它包含了编译所需的基本工具
sudo apt install build-essential
gcc --version
make --version
这里有个小坑:有些发行版默认的 gcc 版本可能比较旧。你可以用 update-alternatives 来切换版本。我个人习惯装两个版本,一个稳定版,一个最新版,根据项目需求切换。
2.4 使用QEMU搭建测试虚拟机
为什么要用虚拟机?因为内核模块一旦写崩了,轻则 kernel panic,重则把整个系统搞挂。在物理机上调试?风险太大。我刚开始学的时候就在自己的笔记本上直接 insmod,结果系统直接死机,连保存文档的机会都没有。
QEMU 是个好东西。它轻量、快速,而且支持 GDB 调试。下面是我常用的搭建步骤:
2.4.1 安装 QEMU
sudo apt install qemu-system-x86 qemu-utils
2.4.2 准备内核和根文件系统
你可以用发行版自带的内核,也可以自己编译。我建议初学者先用现成的:
# 下载一个最小的根文件系统(比如 Alpine Linux)
wget https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.0-x86_64.iso
# 或者用 busybox 自己做一个(更轻量)
# 这个我们后面章节会详细讲
2.4.3 启动虚拟机
qemu-system-x86_64 \
-kernel /boot/vmlinuz-$(uname -r) \
-initrd /boot/initrd.img-$(uname -r) \
-hda alpine-virt-3.19.0-x86_64.iso \
-append "console=ttyS0" \
-nographic
启动之后,你就有了一个干净的内核环境。把编译好的 .ko 文件传进去,用 insmod 加载测试。就算崩了,重启虚拟机也就几秒钟的事。
2.5 本章知识体系
下面这张图帮你理清整个环境搭建的逻辑:
2.6 验证环境是否就绪
最后,写一个最简单的模块来验证环境:
// hello.c
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void) {
printk(KERN_INFO "Hello, Kernel Module!\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye, Kernel Module!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple test module");
# Makefile
obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
编译:
make
如果生成了 hello.ko 文件,恭喜你,环境搭建成功了!
公众号:蓝海资料掘金营,微信deep3321