第3章 内核配置基础:认识Kconfig体系、make menuconfig图形化配置界面操作、保存与加载配置文件(.config)、常用配置选项详解
好,咱们进入内核配置这一块。说实话,很多刚入行的朋友觉得配置内核就是跑个 make menuconfig,然后勾勾选选就完事了。其实不然。我在MTK项目上踩过不少坑,有一次因为漏配了一个DMA相关的选项,导致整个USB摄像头模组在Android系统里死活识别不出来。排查了整整两天,最后发现就是Kconfig里一个依赖没选上。
所以这一章,咱们把Kconfig体系彻底讲透。你想想看,搞懂了它,以后不管换什么平台,你都能快速上手。
3.1 Kconfig体系:内核配置的“语法规则”
Kconfig是什么?说白了,它就是一套描述配置选项的脚本语言。内核源码树里几乎每个目录下都有一个 Kconfig 文件,这些文件通过 source 语句层层嵌套,最终构成一棵完整的配置树。
我习惯把Kconfig比作“菜单的菜谱”。make menuconfig 是那个点菜界面,而Kconfig文件就是后厨写好的菜单规则——哪些菜能点、点了A就必须点B、C和D只能二选一,全写在里面。
核心概念:Kconfig定义的是“配置选项的依赖关系”,而不是配置值本身。配置值存在 .config 文件里。
来看一个典型的Kconfig条目:
config MTK_GPU_SUPPORT
bool "MTK GPU Support"
default y
depends on ARCH_MTK
help
Say Y here if you want to enable MTK GPU driver support.
If unsure, say N.
这里面每个字段都有讲究:
- config:定义了一个配置选项,名字是
MTK_GPU_SUPPORT。编译的时候会变成CONFIG_MTK_GPU_SUPPORT。 - bool:类型是布尔值,要么Y要么N。还有
tristate(三态:Y/M/N)、int、string等类型。 - default y:默认开启。我在项目中一般建议默认开启的选项尽量少,除非是平台必须的。
- depends on:依赖关系。只有
ARCH_MTK被选中,这个选项才会出现。 - help:帮助信息。写清楚这个选项是干什么的。
我的小技巧:写Kconfig时,help 信息一定要写清楚。我曾经接手过一个项目,前任工程师的Kconfig help全是“Enable this for support”,跟没写一样。后来我花了三天才搞清楚每个选项的用途。
3.2 make menuconfig:图形化配置界面操作
好,Kconfig文件写好了,怎么用呢?make menuconfig 就是那个“点菜界面”。
在MTK8678的源码根目录下,执行:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make menuconfig
界面就出来了。第一次用的时候别慌,操作很简单:
- 上下箭头:移动光标
- Enter:进入子菜单或选中选项
- 空格键:切换选项状态(Y/M/N)
- ? 键:查看当前选项的帮助信息
- / 键:搜索选项(这个我经常用,后面细说)
- Tab 键:切换到底部的按钮区域
嗯,这里要注意:Y 表示编译进内核,M 表示编译成模块,N 表示不编译。对于MTK平台,我建议驱动类的选项尽量用 Y,除非你明确知道要动态加载。
避坑指南:我曾经在配置MTK的ISP驱动时,不小心把某个核心驱动设成了M(模块),结果系统启动时模块加载顺序不对,摄像头一直黑屏。排查了很久才发现是这个问题。所以,不确定的驱动就选Y,至少不会因为加载顺序出问题。
3.3 保存与加载配置文件(.config)
配置完了,怎么保存?其实 make menuconfig 退出时会自动询问你是否保存。但我个人习惯手动操作:
# 保存当前配置
cp .config my_mtk8678_defconfig
# 加载已有配置
cp my_mtk8678_defconfig .config
make olddefconfig # 自动处理新选项的默认值
这里有个关键点:.config 文件里存的是最终的配置值。但如果你直接复制 .config 给别人用,可能会出问题——因为内核版本不同,有些选项可能已经变了。
所以,正规的做法是生成 defconfig 文件:
make savedefconfig
# 会生成一个精简的 defconfig 文件
defconfig 只保存非默认值的选项,这样跨版本兼容性更好。我在MTK项目里,每次发布BSP包时都会附带一个 mtk8678_defconfig 文件,方便客户快速复现我们的配置。
重要:每次修改配置后,一定要执行 make olddefconfig 或 make oldconfig。否则新内核版本新增的选项会使用默认值,可能不是你想要的。
3.4 常用配置选项详解
好了,理论讲完了,咱们来点实际的。在MTK8678平台上,有几个配置选项我几乎每次都要碰:
| 配置选项 | 路径 | 说明 | 我的建议 |
|---|---|---|---|
CONFIG_PREEMPT |
Kernel Features → Preemption Model | 抢占式内核,提高实时性 | MTK多媒体场景建议开启 |
CONFIG_HZ_1000 |
Kernel Features → Timer frequency | 系统时钟频率,1000Hz | 我一般选1000Hz,调度更精细 |
CONFIG_CMA |
Memory Management → Contiguous Memory Allocator | 连续内存分配器,摄像头/GPU必备 | 必须开启,大小根据产品定 |
CONFIG_DEVTMPFS |
Device Drivers → Generic Driver Options | 自动创建设备节点 | 建议开启,省去手动mknod的麻烦 |
CONFIG_EXT4_FS |
File systems → The Extended 4 (ext4) filesystem | ext4文件系统支持 | Android系统必须 |
除了这些,还有一个我特别想提的:搜索功能。在 make menuconfig 界面按 / 键,输入关键词,就能快速定位到选项。比如你想找DMA相关的配置,输入 DMA,所有包含DMA的选项就列出来了。这个功能我一天能用几十次。
我的习惯:每次拿到一个新的MTK平台,我会先执行 make menuconfig,然后按 / 搜索 MTK,把所有MTK相关的选项过一遍。这样能快速了解这个平台支持哪些功能,哪些是默认开启的,哪些需要手动打开。
3.5 实战:从零配置一个最小启动内核
最后,咱们动手做个小练习。假设你要为MTK8678配置一个能启动到shell的最小内核:
- 加载默认配置:
make ARCH=arm64 mtk8678_defconfig - 进入menuconfig:
make menuconfig - 关闭不需要的驱动:比如蓝牙、NFC、指纹等,按需求设为N
- 确保开启:
CONFIG_DEVTMPFS(设备节点)CONFIG_TMPFS(临时文件系统)CONFIG_INITRAMFS_SOURCE(指定initramfs路径)
- 保存退出,然后
make savedefconfig生成精简配置
这样配出来的内核,大概只有几百KB,启动飞快。我在做早期原型验证时经常这么干——先跑起来,再慢慢加功能。
好了,这一章的内容就到这儿。Kconfig和menuconfig是内核开发的入门基本功,但也是很多人容易忽略的地方。记住一句话:配置错了,后面编译、调试全是白费功夫。下一章咱们开始讲真正的编译流程,到时候你会感谢今天认真学配置的自己。