3. Kconfig 依赖与选择:depends on、select 与 choice

在嵌入式 Linux 内核的 Kconfig 体系中,配置项之间并非孤立存在。硬件平台限制、功能依赖关系、资源互斥等现实约束,必须通过 Kconfig 的依赖与选择机制精确表达。本章深入剖析三种核心结构:depends on(依赖)、select(反向选择)与 choice(互斥选择),帮助你在配置中建立正确的逻辑关系。

核心认知:depends on 是“被动等待”,select 是“主动拉取”,choice 是“排他锁定”。三者组合使用,可以构建从简单到复杂的任意配置拓扑。

3.1 depends on:被动依赖机制

depends on 是最基础的依赖表达方式。它表示当前配置项的可见性与可设置性,完全取决于其依赖的表达式是否为真。如果依赖不满足,该配置项在 menuconfig 中不可见,且其值强制为默认值(通常是 n)。

3.1.1 语法与语义

config FEATURE_A
    bool "Enable Feature A"

config FEATURE_B
    bool "Enable Feature B"
    depends on FEATURE_A

上述代码中,FEATURE_B 只有在 FEATURE_A 被选中(值为 y)时才会出现在配置界面中。如果 FEATURE_A 为 n,则 FEATURE_B 不可见且强制为 n。

3.1.2 多依赖与复合表达式

depends on 支持多个依赖项,可以使用逻辑运算符组合:

config DRV_SENSOR
    tristate "Sensor Driver"
    depends on I2C && (ARCH_ARM || ARCH_RISCV)
    help
      需要 I2C 总线支持,且仅适用于 ARM 或 RISC-V 架构。
运算符 含义 示例
&& 逻辑与 depends on A && B
|| 逻辑或 depends on A || B
! 逻辑非 depends on !A
= 值比较 depends on A = "value"
常见陷阱:depends on 只控制“可见性”,不自动设置依赖项的值。如果依赖项本身未选中,当前配置项会直接隐藏,而不是自动帮你打开依赖。

3.1.3 depends on 依赖关系图

下图展示了 depends on 的被动依赖链:

depends on 被动依赖关系 PLATFORM_SUPPORT I2C_CONTROLLER SENSOR_DRIVER 依赖传递规则 SENSOR_DRIVER depends on I2C I2C depends on PLATFORM → 链式传递生效

3.2 select:主动反向选择

select 是 depends on 的逆操作。当一个配置项被选中时,它可以强制将另一个配置项也设置为 y(或 m)。这种机制常用于“功能 A 需要功能 B 才能工作,且不希望用户手动去打开 B”的场景。

3.2.1 基本用法

config USB_STORAGE
    tristate "USB Storage support"
    select SCSI
    help
      选中此项会自动启用 SCSI 子系统支持。

当用户将 USB_STORAGE 设置为 y 或 m 时,SCSI 会被自动设置为 y(如果 USB_STORAGE 是 y)或自动跟随为 m(如果 USB_STORAGE 是 m)。

3.2.2 select 与 depends on 的对比

特性 depends on select
方向 被依赖项控制当前项 当前项控制被依赖项
用户可见性 依赖不满足时隐藏 始终可见(除非另有依赖)
自动设置 不自动设置依赖项 强制设置被选中的项
典型场景 硬件平台限制 功能依赖的子系统
风险 配置项可能意外隐藏 可能造成循环 select

3.2.3 select 的副作用与注意事项

  • 循环 select:A select B,B select A 会导致 Kconfig 解析死循环,必须避免。
  • select 不传递依赖:select 只设置目标项的值,不会自动设置目标项自身的 depends on 依赖。
  • tristate 传播规则:如果当前项是 m,select 的目标项也会被设为 m(如果目标支持 tristate)。
最佳实践:select 只应用于“硬依赖”——即功能 B 是功能 A 的不可分割的组成部分。对于“软依赖”,应使用 depends on 让用户自行决策。

3.2.4 select 主动拉取示意图

select 主动反向选择 NETWORK_FS CRYPTO select CRYPTO select 行为说明 • 用户选中 NETWORK_FS → CRYPTO 自动被设为 y/m • 用户取消 NETWORK_FS → CRYPTO 不受影响(需手动取消)

3.3 choice:互斥选择结构

choice 用于定义一组互斥的配置选项。在给定的 choice 范围内,用户只能且必须选择一个选项。这在硬件接口选择、传输协议选择、启动模式选择等场景中极为常见。

3.3.1 基本语法

choice
    prompt "Boot Mode"
    default BOOT_FROM_SPI

config BOOT_FROM_SPI
    bool "SPI Flash"
    help
      从 SPI Flash 启动系统。

config BOOT_FROM_NAND
    bool "NAND Flash"
    help
      从 NAND Flash 启动系统。

config BOOT_FROM_EMMC
    bool "eMMC"
    help
      从 eMMC 启动系统。

endchoice

3.3.2 choice 的关键属性

属性 作用 示例
prompt choice 块的显示标题 prompt "Select Interface"
default 指定默认选中项 default BOOT_FROM_SPI
optional 允许一个都不选(罕见) choice optional
depends on 整个 choice 块的依赖 depends on ARCH_ARM

3.3.3 choice 与 depends on 的嵌套

choice 内部每个选项也可以有自己的 depends on,用于进一步细化可见性:

choice
    prompt "Display Interface"
    default HDMI_OUTPUT

config HDMI_OUTPUT
    bool "HDMI"
    depends on HDMI_HARDWARE

config LVDS_OUTPUT
    bool "LVDS"
    depends on LVDS_HARDWARE

config MIPI_DSI_OUTPUT
    bool "MIPI DSI"
    depends on MIPI_DSI_HARDWARE

endchoice

如果某个选项的依赖不满足,该选项在 choice 列表中不可见,但 choice 仍然强制用户从可见选项中选择一个。

注意:如果 choice 中所有选项都因 depends on 而不可见,整个 choice 块将退化为不可见状态,此时不会强制选择任何选项。

3.3.4 choice 互斥结构图

choice 互斥选择结构 choice "Boot Mode" BOOT_FROM_SPI BOOT_FROM_NAND BOOT_FROM_EMMC 互斥规则 • 三选一 • 默认 SPI • 选中一个后 其他自动取消 • 不可多选

3.4 三种机制的协同使用

在实际的嵌入式内核配置中,depends on、select 和 choice 经常组合出现,形成复杂的配置拓扑。以下是一个综合示例:

choice
    prompt "Storage Interface"
    default STORAGE_SDIO
    depends on MMC_SUPPORT

config STORAGE_SDIO
    bool "SDIO Card"
    select MMC_BLOCK
    help
      使用 SDIO 接口的存储卡。

config STORAGE_SPI_NAND
    bool "SPI NAND"
    depends on SPI_MASTER
    select MTD_SPI_NAND
    help
      使用 SPI 接口的 NAND Flash。

config STORAGE_EMMC
    bool "eMMC"
    depends on MMC_SUPPORT
    select MMC_BLOCK
    help
      板载 eMMC 芯片。

endchoice

在这个例子中:

  • choice 确保三种存储接口互斥,只能选其一。
  • depends on 控制每个选项的硬件前提(如 SPI_MASTER、MMC_SUPPORT)。
  • select 在选中某个选项时,自动拉取所需的底层驱动(如 MMC_BLOCK、MTD_SPI_NAND)。
设计原则:choice 负责“排他”,depends on 负责“可见性过滤”,select 负责“依赖自动补全”。三者各司其职,共同构建健壮的配置体系。

3.5 常见错误与调试方法

错误现象 可能原因 解决方案
配置项在 menuconfig 中消失 depends on 依赖不满足 检查依赖链,确保所有父依赖已启用
Kconfig 解析报错“recursive dependency” 循环 select 或循环 depends on 使用 make menuconfig 查看错误提示,打破循环
choice 中所有选项都不可见 choice 或所有选项的 depends on 不满足 检查 choice 块的 depends on 条件
select 未生效 目标项有 depends on 限制 select 只设值,不绕过 depends on;需同时满足依赖

调试 Kconfig 依赖问题时,推荐使用以下命令:

# 查看配置项的依赖树
make menuconfig
# 在界面中按 / 键搜索配置项,查看其依赖关系

# 使用脚本检查 Kconfig 语法
scripts/kconfig/conf --syncconfig Kconfig

# 查看 .config 中自动生成的依赖
grep -E "CONFIG_(USB_STORAGE|SCSI)" .config