3. 内核配置基础:make menuconfig 图形化配置、配置项搜索技巧、.config 文件结构解析

内核配置,说白了就是告诉 Linux 内核:你要支持哪些硬件?要开启哪些功能?要编译成模块还是直接编进内核?

我刚开始学内核配置时,面对几千个配置项,说实话有点懵。后来摸清了门道,发现其实就三件事:怎么配、怎么搜、怎么看结果。这一章咱们就把这三件事彻底讲透。

3.1 make menuconfig:最常用的配置界面

在 Linux 内核源码根目录下,执行:

make menuconfig

就会弹出一个基于 ncurses 的图形化配置界面。为什么推荐它?因为它在终端里就能跑,不需要图形桌面环境,服务器、开发板都能用。

界面操作其实很简单:

操作 按键 说明
上下移动 ↑ / ↓ 在菜单项之间切换
进入子菜单 Enter 选中带箭头 → 的项
返回上级 Esc + Esc 或者按 / 再选 Exit
切换状态 Y / N / M Y=编译进内核,M=编译为模块,N=不编译
搜索 / 输入关键词查找配置项
保存退出 → 选中 Save / Exit 保存为 .config 文件
我的习惯:每次配置前,先执行 make defconfig 生成一个默认配置,再在此基础上修改。这样不会漏掉架构依赖的基础选项。

3.2 配置项搜索技巧:别再翻菜单了

几千个配置项,一个个翻菜单找?那太慢了。我教你们一个高效方法——搜索功能。

在 menuconfig 界面按 / 键,输入关键词,比如 USB,就会列出所有包含 USB 的配置项。搜索结果长这样:

Symbol: CONFIG_USB [=y]
Type  : bool
Prompt: Support for Host-side USB
  Location:
    -> Device Drivers
      -> USB support (USB_SUPPORT [=y])
  Defined at drivers/usb/Kconfig:123
  Depends on: USB_ARCH_HAS_HCD [=y] && HAS_IOMEM [=y]

这里的信息非常关键:

  • Symbol:配置项的内核宏名称,比如 CONFIG_USB
  • Type:类型,bool 表示开关,tristate 表示三态(Y/M/N)
  • Prompt:菜单里显示的文字
  • Location:这个配置项在菜单树里的路径
  • Depends on:依赖条件,必须满足才能看到或选中
我曾经踩过的坑:搜索到一个配置项,明明选了 Y,保存后重新打开又变回 N。后来才发现是 Depends on 条件没满足,父选项没开启,子选项选了也白选。

另外,搜索支持正则表达式。比如搜 I2C.*DRV 可以找到所有 I2C 驱动相关的配置项。这个技巧在调试特定硬件时特别有用。

3.3 .config 文件结构解析

配置完成后,所有选择都保存在源码根目录下的 .config 文件里。这个文件是纯文本,结构非常清晰。

来看一个典型的 .config 片段:

#
# Automatically generated file; DO NOT EDIT.
# Linux/arm 5.10.0 Kernel Configuration
#

CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Linaro) 7.5.0"
CONFIG_ARM=y
CONFIG_ARM_HAS_SG_CHAIN=y

# 开关选项
CONFIG_USB=y
CONFIG_USB_STORAGE=m
CONFIG_USB_NET_DRIVER=n

# 字符串选项
CONFIG_DEFAULT_HOSTNAME="myboard"

# 整数选项
CONFIG_HZ=100

# 未设置选项(注释形式)
# CONFIG_DEBUG_FS is not set

我来拆解一下:

格式 含义 示例
CONFIG_XXX=y 编译进内核 CONFIG_USB=y
CONFIG_XXX=m 编译为可加载模块 CONFIG_USB_STORAGE=m
CONFIG_XXX=n 不编译 CONFIG_USB_NET_DRIVER=n
CONFIG_XXX="string" 字符串值 CONFIG_DEFAULT_HOSTNAME="myboard"
CONFIG_XXX=123 整数值 CONFIG_HZ=100
# CONFIG_XXX is not set 明确未选中 # CONFIG_DEBUG_FS is not set
核心原则:.config 文件是内核编译的唯一配置依据。不要手动编辑它!手动改容易导致依赖不一致,编译时各种报错。改配置请用 make menuconfig 或 make savedefconfig。

3.4 配置依赖与自动修正

内核配置项之间不是独立的。你选了一个选项,它可能会自动帮你选上依赖项,也可能因为依赖不满足而自动取消。

举个例子:

  • 你选了 CONFIG_USB_STORAGE=m
  • 它依赖 CONFIG_USB=y 或 CONFIG_USB=m
  • 如果你没选 CONFIG_USB,menuconfig 会自动帮你选上,或者提示你

这种机制叫 select 和 depends on。简单说:

  • depends on:依赖项必须存在,否则本选项不可见
  • select:选中本选项时,自动强制选中另一个选项
避坑指南:我曾经在配置网卡驱动时,选了 CONFIG_E1000,但忘了选 CONFIG_PCI。结果编译出来的内核没有 PCI 支持,网卡驱动根本加载不了。所以配置完一定要检查依赖链。

3.5 本章知识结构图

下面这张图帮你理清内核配置的完整流程:

内核配置流程与文件结构 内核配置流程与 .config 文件结构 make menuconfig 配置操作 Y / M / N 切换 / 键搜索配置项 保存 → .config 文件 .config 文件结构 CONFIG_USB=y CONFIG_USB_STORAGE=m CONFIG_DEFAULT_HOSTNAME="myboard" # CONFIG_DEBUG_FS is not set → 编译进内核 → 编译为模块 → 字符串值 → 未选中 依赖自动修正 depends on / select

3.6 配置实战:从零开始配一个最小内核

光说不练假把式。咱们走一遍实际流程:

  1. 清理环境:make distclean,确保没有残留配置
  2. 生成默认配置:make defconfig,基于当前架构生成基础配置
  3. 打开菜单:make menuconfig
  4. 搜索目标:按 /,输入 EXT4,找到文件系统支持
  5. 调整选项:把不需要的驱动设为 N,需要的设为 Y 或 M
  6. 保存退出:选择 Save,覆盖 .config
  7. 检查依赖:make olddefconfig,自动补全未设置的依赖项
我的习惯:配置完成后,执行 make savedefconfig 生成一个精简版的 defconfig 文件。这个文件只包含非默认值的配置项,方便版本管理和后续复用。

嗯,到这里,内核配置的基础你就掌握了。记住:配置不是一次性的,随着硬件变化、功能增减,你会反复进出 menuconfig。熟练使用搜索和依赖检查,能帮你省下大量时间。