4、内核配置基础:make menuconfig入门、配置界面导航(搜索、帮助、依赖关系)、保存与加载配置文件

说实话,很多刚接触内核裁剪的朋友,一上来就想着改代码、删文件。其实内核裁剪的第一步,是学会跟配置界面打交道。你连菜单都找不到,怎么知道哪些功能该关、哪些该留?

这一章,我就带你把这个基础打牢。学完之后,你至少能熟练操作 make menuconfig,知道怎么搜、怎么看帮助、怎么处理依赖关系,以及怎么把配置保存下来反复用。

4.1 启动 make menuconfig

先确认你已经配置好了交叉编译环境,并且进入了内核源码根目录。然后执行:

make menuconfig

如果提示缺少 ncurses 库,装一下就好:

sudo apt-get install libncurses-dev

启动之后,你会看到一个蓝底白字的菜单界面。别被它吓到,这玩意儿比很多图形界面都直观。

我的习惯:每次做新项目的内核配置,我都会先执行 make defconfig 生成一个默认配置,再在此基础上用 menuconfig 做裁剪。这样起点比较干净,不会把时间浪费在清理旧配置上。

4.2 界面导航基础

menuconfig 的操作逻辑很简单,记住几个键就行:

按键 功能
↑ ↓ 上下移动光标
Enter 进入子菜单 / 选中条目
Space 切换选项状态(Y / N / M)
Esc Esc 返回上一级 / 退出
? 查看帮助信息
/ 搜索功能

每个选项有三种状态:

  • Y —— 编译进内核(built-in)
  • M —— 编译成模块(module)
  • N —— 不编译

嗯,这里要注意:如果你做的是嵌入式系统,尤其是资源受限的设备,尽量把不用的功能设成 N,而不是 M。模块虽然可以动态加载,但模块本身也占空间,而且加载过程需要文件系统支持。

4.3 搜索功能:快速定位配置项

内核有几万个配置项,你不可能一个个翻。这时候搜索功能就派上用场了。

按 / 键,输入关键词,比如 USB,然后回车。你会看到所有包含 USB 的配置项列表,每个条目后面还标了路径和当前值。

搜索结果的解读:

搜索结果中,每个条目会显示:

  • Symbol —— 配置宏名称,比如 CONFIG_USB
  • Prompt —— 菜单里显示的文字
  • Location —— 在菜单树中的路径
  • Depends on —— 依赖条件

举个例子,你搜 CONFIG_USB,看到它依赖 !ARCH_S3C24XX,说明如果你选了三星那个老架构,USB 选项根本不会出现。这就是依赖关系在起作用。

避坑指南:我曾经在裁剪一个路由器内核时,搜到了 CONFIG_NETFILTER,直接设成 N,结果 iptables 相关的选项全消失了。后来才发现 NETFILTER 是很多网络功能的前置依赖。所以搜索时,不光要看结果,还要看它依赖什么、被什么依赖。

4.4 帮助信息:每个选项的说明书

选中一个配置项,按 ?,就能看到它的详细帮助。这里面包含:

  • 功能描述
  • 依赖关系
  • 反向依赖(哪些选项依赖它)
  • 推荐用法

我个人习惯是,遇到不认识的配置项,先按 ? 看一眼。很多选项的帮助里会直接告诉你「如果你不确定,选 Y」或者「大多数情况下选 M 即可」。这些信息比你自己猜要靠谱得多。

4.5 依赖关系:为什么有些选项是灰色的?

你在 menuconfig 里会看到一些选项是灰色的,无法选中。这通常是因为它的依赖条件没满足。

依赖关系用 depends on 表示。比如:

config USB_STORAGE
    depends on USB && SCSI

意思是,只有 USB 和 SCSI 都选中的时候,USB_STORAGE 才能被配置。如果 USB 是 N,那 USB_STORAGE 就是灰色的。

还有一种叫「反向依赖」,用 select 表示。比如:

config A
    select B

意思是,你选了 A,系统会自动帮你选上 B。这种机制常用于「A 必须依赖 B 才能工作」的场景。

注意:反向依赖有时候会带来麻烦。你选了 A,B 被自动选上了,但 B 可能又依赖 C,C 又依赖 D……最后你发现配置里多了一堆你根本不需要的东西。所以裁剪时,尽量从顶层需求往下推,不要盲目选大功能。

4.6 保存与加载配置文件

配置完成后,按 Esc Esc 退出,系统会问你是否保存。选 Yes,配置会写入 .config 文件。

但 .config 这个名字太普通了,你可能会同时维护多个项目的配置。所以我建议你养成好习惯:

  • 用 cp .config config_my_project 备份一份
  • 下次需要加载时,执行 cp config_my_project .config 再 make menuconfig

或者直接用:

make config_my_project

前提是你把配置文件放在内核源码根目录下,并且命名符合 config_* 模式。

我的做法:我会把每个项目的配置文件放在项目目录里,比如 ~/projects/router/kernel_config。然后在内核目录里建一个软链接:
ln -s ~/projects/router/kernel_config .config
这样既不会弄混,又方便版本管理。

4.7 配置文件的内部结构

如果你打开 .config 看一眼,会发现它其实就是一个文本文件,每行一个配置项:

CONFIG_USB=y
CONFIG_USB_STORAGE=m
# CONFIG_USB_NET_DRIVERS is not set

三种状态对应三种写法:

  • =y —— 编译进内核
  • =m —— 编译成模块
  • # ... is not set —— 不编译

你完全可以手动编辑这个文件。但我建议只在两种情况下手动改:

  1. 批量修改大量配置项时(用 sed 或脚本)
  2. 修复某个已知的依赖冲突时

其他时候,还是用 menuconfig 更安全,因为它会自动处理依赖关系。

4.8 本章知识体系

下面这张图帮你理清本章的核心逻辑:

内核配置基础:知识体系 make menuconfig 界面导航 搜索功能 帮助信息 依赖关系 保存与加载配置 Y / M / N 三种状态 Symbol / Prompt / Location 功能描述 / 依赖 / 推荐 depends on / select .config / 备份 / 软链接

从图上你能看出来,menuconfig 是入口,四个核心操作(导航、搜索、帮助、依赖)围绕它展开,最终落到保存与加载这个实操环节。每个环节都有对应的子知识点,你不需要一次全记住,用的时候回来查就行。

4.9 小结

这一章的内容其实不多,但很关键。你想想看,如果连配置界面都不会用,后面那些高级裁剪技巧根本施展不开。

记住几个要点:

  • 搜索是找配置项最快的方式
  • 帮助信息是你最好的老师
  • 依赖关系决定了选项能不能出现
  • 配置文件记得备份,别指望一次配好