3. 内核源码结构:下载、理解与配置
好,咱们正式开始接触内核源码。说实话,很多初学者一看到 Linux 内核那几万个文件就头皮发麻。我当年也一样,第一次解压完源码,ls 了一下,直接愣住了——这从哪儿看起?
别急。这一章我就带你走一遍标准流程:下载源码 → 看懂目录树 → 用 menuconfig 配置内核。这三步走顺了,后面写驱动才有根基。
3.1 下载 Linux 内核源码
先说说怎么拿到源码。我个人习惯直接从 kernel.org 下载,这是官方发布渠道,最干净。
推荐下载方式:
- 官网:
https://www.kernel.org→ 选一个长期支持版(LTS) - 命令行:
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.76.tar.xz - 解压:
tar -xf linux-6.1.76.tar.xz
为什么强调 LTS 版本?我在项目里吃过亏——用了一个非稳定版内核,驱动调得好好的,升级内核小版本后 API 变了,编译直接报错。从那以后,我选内核版本就一个原则:不追新,只追稳。
小技巧:如果你在嵌入式板子上开发,板子厂商通常会提供一份 .config 文件。下载对应版本的内核后,直接把这份配置拷过来,能省大量时间。
3.2 理解内核目录树
解压完,咱们看看顶层目录长什么样。你执行 ls -l 会看到类似这样的结构:
arch/ — 体系结构相关代码(ARM、x86、RISC-V 等)
block/ — 块设备层
crypto/ — 加密子系统
Documentation/ — 内核文档(别忽略它)
drivers/ — 驱动代码(咱们的主战场)
fs/ — 文件系统(ext4、btrfs、proc 等)
include/ — 内核头文件
init/ — 内核初始化代码
ipc/ — 进程间通信
kernel/ — 核心内核代码(调度、信号等)
lib/ — 内核工具函数库
mm/ — 内存管理
net/ — 网络协议栈
scripts/ — 编译和配置脚本
security/ — 安全模块
sound/ — 音频子系统
tools/ — 用户态工具
usr/ — 初始 ramfs 相关
嗯,这里我要多说一句:drivers/ 目录是我们驱动工程师待得最久的地方。它下面又按子系统分了无数子目录:drivers/i2c/、drivers/spi/、drivers/gpio/、drivers/net/……你写什么类型的驱动,就去对应的子目录里找参考。
举个例子,我当年写第一个 I2C 触摸屏驱动,就是先跑到 drivers/input/touchscreen/ 里翻了一遍,找到一个类似的芯片驱动,照着它的框架改出来的。说白了,内核源码就是最好的参考手册。
注意:不要试图一次性读完所有目录。内核源码有几千万行,没人能全看完。我的建议是:先搞懂你需要的子系统目录,其他的用到再查。
下面这张图帮你理清内核源码的核心层次关系:
3.3 配置内核:menuconfig
源码下载好了,目录结构也了解了,下一步就是配置内核。配置内核说白了就是告诉编译器:哪些功能要编进内核,哪些编成模块,哪些干脆不要。
最常用的配置工具是 menuconfig。执行命令:
make menuconfig
你会看到一个基于 ncurses 的图形菜单。界面虽然简陋,但功能很强大。我来拆解一下常用操作:
| 操作 | 按键 | 说明 |
|---|---|---|
| 上下移动 | ↑ / ↓ | 在菜单项之间移动 |
| 进入子菜单 | Enter | 选中 ---> 标记的项 |
| 选中/取消 | 空格 / Y / N | Y=编入内核,M=编译为模块,N=不编译 |
| 搜索 | / | 按符号名搜索配置项(我最常用的功能) |
| 退出 | ESC + ESC | 返回上一级或退出 |
搜索功能一定要会用。比如你想配 I2C 驱动,直接按 / 输入 I2C,所有相关的配置项就列出来了。我曾经花半小时翻菜单找不到一个选项,后来发现搜索一秒搞定——嗯,从那以后我再也不硬翻了。
3.4 配置项的三态与依赖
每个配置项有三种状态,用 <*>、<M>、< > 表示。但这里有个坑:配置项之间有依赖关系。
举个例子,你想把某个 SPI 驱动编成模块,但它的父选项 SPI 子系统本身没打开,那这个驱动选项根本不会出现。这就是所谓的 depends on 机制。
我在调试一块 SPI 屏幕时遇到过这问题——折腾了半天,发现是 SPI 核心没开。所以我的建议是:先确保子系统打开,再去找具体驱动。
避坑指南:我曾经在配置内核时,为了省空间把 CONFIG_FW_LOADER 关了,结果固件加载子系统直接罢工,所有需要固件的驱动都报错。这种基础选项,不确定就别动。
3.5 保存配置与编译
配置完成后,选择 Save,配置会写入 .config 文件。这个文件是纯文本的,你也可以直接编辑它——但我个人不推荐手动改,容易搞乱依赖关系。
保存后,执行编译:
make -j$(nproc)
-j 参数指定并行编译的线程数,$(nproc) 会自动获取你的 CPU 核心数。我第一次编译内核时不知道这个参数,单线程编译等了快两个小时……后来加了 -j8,十几分钟就搞定了。
3.6 本章小结
这一章我们做了三件事:下载内核源码 → 看懂目录树 → 用 menuconfig 配置内核。这三步是驱动开发的起点,也是你后续调试的基础。
记住几个关键点:
- 源码从 kernel.org 下 LTS 版本
- drivers/ 目录是驱动主战场
- menuconfig 搜索功能是效率神器
- 配置依赖关系搞不清楚时,先查
Kconfig文件