4. 内核配置与编译:从Kconfig到设备树
内核配置与编译,说白了就是给RK3568量身定制一套操作系统内核。你想想看,一个通用Linux内核有几万种驱动,但你的板子只需要其中一小部分。怎么把不需要的砍掉,把需要的加进来?这就是本章要解决的问题。
我个人习惯把内核配置比作「点菜」——Kconfig是菜单,menuconfig是点菜界面,defconfig是套餐,编译就是后厨炒菜。咱们一个一个来聊。
4.1 Kconfig体系:内核的「菜单」是怎么写的
Kconfig不是配置文件,它是一种脚本语言。每个驱动目录下都有一个Kconfig文件,描述了这个驱动有哪些配置选项、依赖什么其他选项、默认值是什么。
举个例子,RK3568的GMAC以太网驱动,它的Kconfig片段长这样:
config RK_GMAC
tristate "Rockchip GMAC Ethernet support"
depends on ARCH_ROCKCHIP
select MII
select PHYLIB
help
This driver supports the Rockchip GMAC ethernet controller.
Say Y here if you need ethernet support.
这里有几个关键字段:
- tristate:三态选项——Y(编入内核)、M(编译成模块)、N(不编译)
- depends on:依赖关系,ARCH_ROCKCHIP没选,这个选项就不显示
- select:反向依赖,选了GMAC就自动选上MII和PHYLIB
- help:帮助信息,menuconfig里按H键能看到
4.2 menuconfig图形化配置:可视化点菜
在源码根目录执行 make menuconfig,就能看到那个经典的蓝白界面。它本质上是把Kconfig解析成树形菜单,让你用方向键和空格键来配置。
常用操作键:
| 按键 | 功能 |
|---|---|
| ↑ ↓ | 移动光标 |
| Space | 切换选项(N→M→Y→N循环) |
| Y / N / M | 直接设置 |
| / | 搜索(按名字找选项) |
| Z | 显示所有选项(包括被依赖隐藏的) |
搜索功能特别实用。比如你想找RK3568的I2C驱动,按/输入I2C_RK3X,它会告诉你这个选项在哪个菜单路径下,当前是什么状态。
.config文件里。这个文件是纯文本,你也可以直接编辑,但不建议——格式很严格,手写容易出错。我见过有人手改.config导致编译到一半崩溃的。
4.3 defconfig:官方「套餐」与定制
每个芯片厂商都会提供一个默认配置,放在arch/arm64/configs/目录下。RK3568的官方defconfig叫rockchip_linux_defconfig。
使用方式很简单:
make ARCH=arm64 rockchip_linux_defconfig
这条命令会把rockchip_linux_defconfig复制为.config。之后你再跑make menuconfig做微调。
我建议的工作流是这样的:
make rockchip_linux_defconfig—— 用官方套餐打底make menuconfig—— 按需增删驱动make savedefconfig—— 生成精简后的defconfig- 把生成的
defconfig重命名,保存到版本管理里
.config里有很多默认值选项,体积很大。savedefconfig只保留你修改过的选项,方便代码审查和版本管理。
我曾经在一个项目里,团队五个人各自改.config,结果合代码时冲突不断。后来强制用savedefconfig + 统一defconfig,问题就解决了。
4.4 编译内核与设备树
配置搞定后,编译就相对机械了。RK3568是ARM64架构,编译命令如下:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make -j$(nproc) Image
make -j$(nproc) dtbs
make -j$(nproc) modules
解释一下:
- Image:内核镜像,启动时由uboot加载
- dtbs:设备树二进制文件,描述硬件拓扑
- modules:内核模块,按需加载的驱动
编译产物在arch/arm64/boot/目录下:
| 文件 | 说明 |
|---|---|
| Image | 未压缩的内核镜像 |
| Image.gz | gzip压缩的内核镜像(更小,uboot支持解压) |
| dts/ | 设备树源文件(.dts/.dtsi) |
| dts/rockchip/ | RK平台设备树源文件 |
设备树编译是自动的——你改了.dts文件,跑make dtbs就会重新生成对应的.dtb。RK3568的设备树文件是rk3568-evb.dts或rk3568-rock-3a.dts,具体看你用的板子。
V=1能看到完整编译命令,方便排查头文件路径、链接顺序等问题。我调试一个PCIe驱动时,就是靠V=1发现少了-I路径。
4.5 知识体系总览
下面这张图把整个配置编译流程串起来了:
这张图把整个流程分成了五层:输入文件 → 配置工具 → 中间产物 → 编译 → 最终输出。你跟着这个流程走,基本不会出错。
4.6 常见问题与避坑
编译过程中我遇到过不少坑,挑几个典型的说说:
- 编译报错说找不到头文件:多半是交叉编译链没装对,或者
CROSS_COMPILE环境变量没设。检查aarch64-linux-gnu-gcc --version能不能跑。 - menuconfig里找不到某个选项:先确认
depends on的依赖选项有没有打开。按/搜索,看它被什么依赖隐藏了。 - 设备树编译报语法错误:DTS对分号和花括号很敏感,少一个分号就报错。我习惯用
dtc -I dts -O dtb -o /dev/null test.dts做语法检查。 - 编译出来的内核启动卡住:大概率是.config里砍掉了某个必要驱动。比如串口驱动没编进去,你连内核日志都看不到。
CONFIG_DEVTMPFS关了。结果系统启动后/dev目录是空的,所有设备节点都没有。折腾了半天才发现是这个问题。所以,不熟悉的选项不要乱改,先查文档。
嗯,内核配置编译这块内容就这些。你只要把Kconfig、menuconfig、defconfig这三者的关系理清楚,再记住编译命令,剩下的就是多练。每个板子的defconfig可能不一样,但套路是一样的。