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 本章知识结构图
下面这张图帮你理清内核配置的完整流程:
3.6 配置实战:从零开始配一个最小内核
光说不练假把式。咱们走一遍实际流程:
- 清理环境:
make distclean,确保没有残留配置 - 生成默认配置:
make defconfig,基于当前架构生成基础配置 - 打开菜单:
make menuconfig - 搜索目标:按
/,输入EXT4,找到文件系统支持 - 调整选项:把不需要的驱动设为 N,需要的设为 Y 或 M
- 保存退出:选择 Save,覆盖 .config
- 检查依赖:
make olddefconfig,自动补全未设置的依赖项
我的习惯:配置完成后,执行
make savedefconfig 生成一个精简版的 defconfig 文件。这个文件只包含非默认值的配置项,方便版本管理和后续复用。
嗯,到这里,内核配置的基础你就掌握了。记住:配置不是一次性的,随着硬件变化、功能增减,你会反复进出 menuconfig。熟练使用搜索和依赖检查,能帮你省下大量时间。