第4章 内核配置基础:menuconfig、Kconfig 与 .config

内核配置,说白了就是告诉编译器:哪些功能要编进去,哪些不要。我见过不少新手直接拿厂家给的 defconfig 一编译了事,结果调外设时发现驱动根本没编进去,又得从头来。这一章咱们就把配置的底子打牢。

本章核心脉络: menuconfig(交互界面)→ Kconfig(配置语法)→ .config(最终产物)。三者串起来,就是内核配置的完整链路。
内核配置核心链路 menuconfig 图形化交互界面 Kconfig 配置规则语法 .config 最终配置结果 各环节作用: • menuconfig:开发者通过界面选择/取消功能,背后读写 .config • Kconfig:定义每个选项的依赖、类型、默认值,menuconfig 按此渲染菜单 • .config:纯文本格式,记录所有选项的最终值,Makefile 直接读取它

4.1 menuconfig:你与内核的对话窗口

运行 make menuconfig 后,你会看到一个蓝底黄字的界面。嗯,这玩意儿看着复古,但效率极高。我个人习惯在修改驱动前,先跑一遍 menuconfig 确认当前配置状态。

界面操作其实就几个键:

  • 方向键:上下移动光标,左右切换底部按钮
  • Enter:进入子菜单 / 确认选择
  • Y / N / M:编入内核 / 不编 / 编译为模块
  • ?:查看选项的帮助信息——这个我经常用
  • /:搜索功能,按名字找选项
搜索技巧: 按 / 输入关键词,比如搜 "I2C",会列出所有含 I2C 的选项及其路径。我在 Rockchip 平台上调摄像头时,经常用这个快速定位驱动开关。

选项前面的标记有讲究:

标记含义说明
[ ]三态(未选)按 Y 编入,M 变模块,N 取消
[M]模块化编译为 .ko 文件,运行时加载
[*]编入内核直接链接到 zImage,启动时自带
{ }强制依赖父选项选中后,子选项自动固定

我曾经在调试 RK3588 的 PCIe 时,发现选项是 <M> 但死活加载不了。后来才发现父选项没开,导致子选项虽然选了 M,实际根本没编译。所以,检查依赖关系是排查配置问题的第一步。

4.2 Kconfig 语法:配置规则的“源代码”

每个驱动目录下都有 Kconfig 文件。menuconfig 的菜单结构,就是靠这些文件拼出来的。说白了,Kconfig 就是配置的“语法规则书”。

看一个 Rockchip 平台常见的例子:

config ROCKCHIP_I2S
    tristate "Rockchip I2S controller driver"
    depends on ARCH_ROCKCHIP
    select SND_SOC_GENERIC_DMAENGINE
    help
      Say Y here to enable Rockchip I2S controller driver.
      This driver supports I2S/PCM interface for audio.

逐行拆解:

  • config ROCKCHIP_I2S:选项名,最终在 .config 里变成 CONFIG_ROCKCHIP_I2S
  • tristate:三态(Y/N/M)。如果是 bool,就只有 Y/N,不能编模块
  • depends on:依赖条件。ARCH_ROCKCHIP 没选,这个选项根本看不见
  • select:反向依赖。选中这个选项时,自动强制选上 SND_SOC_GENERIC_DMAENGINE
  • help:帮助信息,menuconfig 里按 ? 看到的就是它
注意 depends on 和 select 的区别: depends on 是“被依赖”,父选项不满足,子选项隐藏;select 是“主动拉”,选中自己时强制拉别人进来。用错了会导致配置循环依赖,编译报错。

再来看一个带 choice 的写法,Rockchip 的 DDR 频率策略里常见:

choice
    prompt "DDR Frequency Scaling Governor"
    depends on ROCKCHIP_DDRFREQ

config DDR_GOVERNOR_PERFORMANCE
    bool "Performance"
    help
      Always run at max frequency.

config DDR_GOVERNOR_ONDEMAND
    bool "Ondemand"
    help
      Scale frequency based on load.

endchoice

choice 是单选组,里面只能选一个。我调 RK3566 的低功耗模式时,就踩过这个坑——选了 Performance 后功耗一直下不来,后来才发现是 choice 里默认选了它。

4.3 .config 文件结构:最终配置清单

运行完 menuconfig 并保存,根目录下会生成 .config。这文件就是内核编译的“购物清单”。

打开看看,格式很简单:

#
# Automatically generated file; DO NOT EDIT.
# Linux/arm64 6.1.0 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="aarch64-linux-gnu-gcc (Linaro) 7.5.0"
CONFIG_ARM64=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ROCKCHIP_I2S=m
CONFIG_I2C_ROCKCHIP=y
# CONFIG_ROCKCHIP_THERMAL is not set

关键点:

  • =y:编入内核
  • =m:编译为模块
  • is not set:没选,前面带 # 注释掉
  • 以 # 开头的行,除了注释,就是没选的选项

我有个习惯:每次改完配置,先 diff .config .config.old 看看改了啥。这能帮你快速定位是不是误操作了某个选项。

重要提醒: 不要手动编辑 .config!虽然它只是文本文件,但手动改容易破坏依赖关系。比如你手动把某个选项从 m 改成 y,但它依赖的模块没改,编译时就会报 undefined reference。老老实实用 menuconfig 或 scripts/config 脚本。

4.4 常用配置操作速查

操作命令说明
图形化配置make menuconfig最常用,依赖 ncurses 库
基于现有配置修改make menuconfig会自动读取当前 .config
使用默认配置make rockchip_linux_defconfig厂家提供的模板,在 arch/arm64/configs/ 下
保存当前配置menuconfig 内选 Save覆盖 .config
备份配置cp .config my_backup.config我每次调通一个新板子都会备份一份
命令行改单项scripts/config --enable CONFIG_XXX适合脚本批量修改
我的工作流: 拿到新 Rockchip 板子,先 make rockchip_linux_defconfig 生成基础配置,然后 make menuconfig 按需打开我要调试的驱动,最后 diff .config .config.old 确认改动。这套流程帮我省了不少排查时间。

嗯,内核配置这块儿,说白了就是三板斧:知道界面怎么操作,看得懂 Kconfig 语法,读得懂 .config 内容。把这章吃透了,后面调驱动时你就能快速定位“是配置没开”还是“代码本身有问题”。