Kconfig 描述构建 Linux 内核配置时可选的选择。内核开发者编辑 Kconfig 文件来定义符号及其关系;用户通过 make menuconfig、make nconfig、make xconfig 等前端,或 olddefconfig 等非交互目标选择值。
生成的 .config 是 Kbuild 的输入,而不是完整的构建脚本。配置同步会生成供 Make 和 C 使用的文件,包括 include/config/auto.conf 和 include/generated/autoconf.h。
从根文件到一个配置 #
解析从顶层 Kconfig 开始。其 source 语句包含子系统文件,架构选择会引入
arch/$(SRCARCH)/Kconfig。其他包含形式有:
rsource,其路径相对于包含文件;osource,忽略缺失文件;orsource,组合相对路径和可选行为。
mainmenu 设置前端标题。menu/endmenu、if/endif、choice/endchoice、comment、config 和 menuconfig 构建条目结构。
同一符号可以在多个被包含文件中定义。Kconfig 会合并该符号的属性;它不会创建架构局部变量。定义必须使用一致的类型,依赖子句会累积,默认值顺序仍然重要。因此,公共文件可以声明不可见的能力,而架构定义可以选择它。
# lib/Kconfig
config HAVE_FAST_CHECKSUM
bool
config FAST_CHECKSUM
bool "Use the generic fast checksum implementation"
depends on HAVE_FAST_CHECKSUM
# arch/example/Kconfig
config EXAMPLE
bool
select HAVE_FAST_CHECKSUMHAVE_* 符号表示实现能力。面向用户的功能随后依赖该能力,从而避免使用 select 绕过功能的实际依赖。
宏和预处理器层 #
Kconfig 会在菜单条目语言处理一行之前执行文本展开。其变量语法类似 Make:
immediate := $(ARCH)
deferred = $(ARCH)
message = architecture $(1), compiler $(2)
$(info,configuring $(immediate))
label := $(message,$(ARCH),$(CC))
:=立即展开右侧。=存储递归展开的值。+=根据变量现有的展开风格追加。$(name)展开变量。$(name,arg1,arg2)展开参数化变量,其中$(1)、$(2)等是位置参数。
与 Make 不同,参数化 Kconfig 变量直接调用,不存在 $(call ...)。逗号分隔函数参数。内置函数包括 shell、info、warning-if、error-if、filename 和 lineno。内核还通过 Kconfig 函数机制增加了编译器选项探测等函数。
宏展开是文本处理,因此引号和空白对接收结果的语言仍然重要。应将预处理用于小型重复表达式和功能探测,而不是生成庞大且难以审计的菜单片段。
符号、类型和提示 #
config NAME 定义名为 NAME 的符号;.config 和 C 将其暴露为 CONFIG_NAME。
menuconfig 定义相同类型的符号,但会告知兼容前端该条目旨在包含子菜单。
有五种符号类型:
| 类型 | .config 中的示例 | 生成的 C 形式 |
|---|---|---|
bool | CONFIG_FOO=y 或 # CONFIG_FOO is not set | #define CONFIG_FOO 1 或不存在 |
tristate | CONFIG_FOO=y、CONFIG_FOO=m 或未设置 | CONFIG_FOO、CONFIG_FOO_MODULE 或二者都没有 |
string | CONFIG_FOO="value" | 带引号的字符串宏 |
int | CONFIG_FOO=42 | 整数宏 |
hex | CONFIG_FOO=0x2a | 十六进制整数宏 |
bool "Enable foo" 和 tristate "Build foo" 将类型与 prompt 结合。没有可见提示的符号不能在配置前端中编辑,但默认值、select 或其他表达式仍可以为其赋值。
config FOO
tristate "Foo transport"
depends on NET
default m if MODULES
help
Build support for the Foo transport.def_bool EXPR 和 def_tristate EXPR 是类型加 default EXPR 的简写。当可选条件为真时,range MIN MAX 限制 int 或 hex 符号。
三态表达式 #
逻辑 Kconfig 表达式使用有序值 n = 0、m = 1 和 y = 2。因此:
A && B是两个值的最小值;A || B是最大值;!A是2 - A。
比较会产生三态结果。括号控制分组,带引号的字面量表示字符串值。bool 不能保留
m;模块相关表达式会根据符号类型及是否启用模块进行折叠。
直接依赖施加上限:
config USB_WIDGET
tristate "USB widget"
depends on USB && HAS_IOMEM如果 USB=m,USB_WIDGET 不能变为 y。提示上的可选条件影响提示是否可见,而符号的直接依赖无论前端如何呈现,都会限制其值。
默认值、反向依赖和可见性 #
属性解决不同问题:
default VALUE if CONDITION仅在用户尚未设置值时提供值。如果有多个默认值可见,则第一个可见默认值生效。默认值不会覆盖现有.config中保留的值。depends on EXPR限制符号的最大值和提示可见性。select TARGET if CONDITION创建反向依赖,并将TARGET提高到至少选择表达式的值。它不会遵守TARGET自身的直接依赖,因此只应选择前提已得到保证的简单不可见符号。imply TARGET if CONDITION是弱反向依赖。它提供一个仍可被可见用户选择降低的下限,同时目标的直接依赖继续限制结果。visible if EXPR限制menu块的可见性,而不改变其中符号的值。
例如:
config DRIVER_FOO
tristate "Foo device"
depends on PCI
select CRC32
imply FW_LOADERCRC32 应是没有未满足依赖的内部辅助符号。FW_LOADER 只是被鼓励启用,因为驱动没有它仍可运行。用 select 修复依赖循环是错误的,因为 Kconfig 会拒绝递归依赖,也不会使用 SAT 求解器推断首选方案。
菜单位置不是依赖图 #
源代码顺序和显式容器决定了大部分显示位置:
menu "Network drivers"
visible if NET
config NET_VENDOR_EXAMPLE
bool "Example devices"
if NET_VENDOR_EXAMPLE
source "drivers/net/ethernet/example/Kconfig"
endif
endmenu前端还会在后续条目足够强地依赖前一条目时推断隐式子菜单,使子条目只有在父条目可见时才能显示。语言文档描述了精确的提示依赖规则。
除此之外,依赖不会重新定位条目。符号可以依赖显示在不同部分的另一个符号,select 也不会使目标显示在选择器下方。因此,菜单布局传达导航,而依赖表达式传达有效值。将前者当作后者的渲染结果,会产生令人困惑的 Kconfig 文件。
生成的配置产物 #
前端写入 .config 后,Kbuild 会同步生成的输入。重要表示形式为:
.config
include/config/auto.conf
include/generated/autoconf.h.config 是持久化的面向用户的赋值文件。auto.conf 将赋值提供给 Make,因此规则可以使用如下表达式:
obj-$(CONFIG_USB_WIDGET) += usb-widget.o
autoconf.h 将启用的符号提供给 C 预处理。内核 C 代码应包含正常的内核头文件,而不是直接包含 autoconf.h。诸如 IS_ENABLED(CONFIG_FOO) 的辅助宏可以处理内建和模块形式,而不必手写每种预处理器组合。
配置更新可以添加较新源码树引入的符号。make oldconfig 会询问新的选择,而
make olddefconfig 接受其默认值。make savedefconfig 会相对于默认值写入最小
defconfig;它不能替代归档完整的 .config。
评论
在 GitHub 上阅读或评论(发表评论需要登录)