标签:
内核源码树的目录下都有两个文件Kconfig(2.4版本是Config.in)和Makefile。分布到各目录的 Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。在内核配置make menuconfig(或xconfig等)时,从Kconfig中读出菜单,用户选择后保存到.config的内核配置文件中。在内核编译时,主 Makefile调用这个.config,就知道了用户的选择。
上面的内容说明了,Kconfig就是对应着内核的配置菜单。如果要想添加新的驱动到内核的源码中,可以修改Kconfig,这样就可以选择这个驱动,如果想使这个驱动被编译,要修改Makefile。
对于kconfig的语法在https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt中做了详细的说明,在这里给出kconfig-language.txt的中文版。
在配置数据库的配置选项是以树的形式组织的:
+- Code maturity level options
| +- Prompt for development and/or incomplete code/drivers
+- General setup
| +- Networking support
| +- System V IPC
| +- BSD Process Accounting
| +- Sysctl support
+- Loadable module support
| +- Enable loadable module support
| +- Set version information on all module symbols
| +- Kernel module loader
+- ...
+- 代码成熟级别选项
| +- 对于开发和/或不完整的代码/驱动 的提示
+-通用配置
| +- 网络支持
| +- System V 进程通信机制
| +- BSD 程序计数器
| +- Sysctl支持
+-可装载模块支持
| +- 使能可装载模块支持
| +- 在所有模块标记上设置版本信息
| +- 内核模块装载
+-...
每个选项都有其自己的依赖关系。这些依赖关系决定了选项是否是可见的。父选项可见,子选项才能可见。
1. Menu entries
大多数的entry都定义了一个config选项,其它entry帮助组织它们。一个配置选项定义可以是下面的形式:
config MODVERSIONS
bool "Set version information on all module symbols"
depends MODULES
help
Usually, modules have to be recompiled whenever you switch to a new
kernel. ...
每行都是以关键字开始,并可以接多个参数。"config" 为定义了一新的配置entry。下面的几行定义了该entity选项的属性。属性可以是该配置选项的类型,输入提示(input prompt),依赖关系,帮助信息和默认值。一配置选项可以用相同的名字定义多次,但每个定义只能有一个输入提示并且类型还不能冲突。
2. Menu attributes
一菜单选项可以有多个属性。并不要求这些属性可以用在任何地方(见语法)。
- 类型定义:"bool"/"tristate"/"string"/"hex"/"int"
每个配置选项都必须指定类型。有两个基本类型:tristate 和 string,其他类型都是基于这两个基本类型。类型定义可以用输入提示,所以下面的两个例子是等价的:
(1)bool "Networking support"
(2)bool
prompt "Networking support"
- 输入提示: "prompt" <prompt> ["if" <expr>]
每个菜单入口最多只能有一个展示给用户看的输入提示,可以使用“if”来表示输入提示的依赖性,这个依赖性是可选的。
- 默认值:"default" <expr> ["if" <expr>]
一个配置选项可以有任意多个默认值。如果存在多个默认值,只有第一个定义的默认值才是有效的。默认值可以定义在菜单入口的任何位置。这就意味着默认值可以在配置选项的其它地方再定义或者被之前的默认值定义给覆盖。
如果用户没有设置(通过上面的输入提示),配置选项的值就是默认值。如果可以显示输入提示的话,就会把默认值显示给用户,并可以让用户进行修改。
与输入提示一样,可以使用“if”来表示默认值的依赖性,这个依赖性是可选的。
- type definition + default value: "def_bool"/"def_tristate" <expr> ["if" <expr>]
这是一个类型定义加上一个默认值的速记符号。
如果使用依赖性,可以使用“if”来表示
- dependencies: “depends on” <expr>
为菜单选项定义一个依赖关系。如果有多个依赖关系,可使用&&隔开。依赖关系也可以应用到该菜单中所有的其它选项(同样接受if表达式),所以下面的两个例子是等价的:
bool "foo" if BAR
default y if BAR
and
depends on BAR
bool "foo"
default y
- reverse dependencies: “select <symbol>” [“if” <expr>]
一个正常的依赖项可以降低symbol的上限值,而反向依赖项则用来给一个symbol限定一个下限值。当前菜单symbol的值是当前可以设定的<symbol>最小值。如果<symbol>被选择了多次,那么它的值限定为最大的那一个。
只有boolean和tristate类型的symbol可以使用反向依赖。
注:应该非常小心使用反向依赖。反向依赖会给symbol强制赋一个值而不受正常依赖项的限制。滥用反向依赖会导致一个symbolF00被选择,即使F00的依赖项BAR没有被设置。一般情况下只有不可见的symbol和没有正向依赖项的symbol才使用反向依赖项。虽然这样限制了反向依赖的用途,但是从另一方面来说,这样阻止了大量的非法配置。
- limiting menu display: “visible if” <expr>
该属性只用在menu block中,如果条件为false,menu block不显示给用户(尽管这样,其中包含的symbol仍可被其他symbol选择)。它类似与单个菜单entry的条件提示属性。默认visible为true。
- numerical ranges: “range” <symbol> <symbol> [“if” <expr>]
为int和hex类型的选项设置可能的输入值范围。用户只能输入大于等于第一个symbol,小于等于第二个symbol的值。
- help text: “help” or “---help---”
这个属性定义了一个帮助文本。帮助文本的结尾是根据缩进级别来决定的,这就意味着如果帮助文本中某一行相对于第一行有更小的缩进,那么这一行就是帮助文档的最后一行。
"---help---" 和 "help" 在实现的作用上没有区别,"---help---" 有助于将文件中的配置逻辑与给开发人员的提示分开。
- misc options: “option” <symbol>[=<value>]
各种不常见的选项的通过这个选项来定义,比如修改菜单入口的行为和配置symbol。下面这些配置当前是允许的:
-"defconfig_list"
这个选项定义了一系列默认入口,当使用默认配置时可以从这里寻找(当主.config文件不存在时会使用)
- “modules”
定义该symbol为MODULES symbol,开启了所有配置symbol的第三种模块化状态。最多只有一个symbol可能设置“modules”选项。
- “env”=<value>
这个选项导入了一个环境变量到Kconfig中。环境变量就像是Kconfig中的一个默认值,但是它是从外部环境中导入的。正因为它从外部环境导入,所以赋值的这个时候它相对于正常的默认值来说是没有定义的。这个symbol当前没有导出到构建环境中(如果想要这样的话,可以通过另一个symbol导出)
- “allnoconfig_y”
当使用“allnoconfig”是,该symbol的值应该为y。用于隐藏其他symbol的symbol。
3. Menu dependencies
依赖关系决定了菜单选项是否可见,也可以减少tristate的输入范围。tristate逻辑比boolean逻辑在表达式中用更多的状态(state)来表示模块的状态。依赖关系表达式的语法如下:
<expr> ::= <symbol> (1)
<symbol> ‘=‘ <symbol> (2)
<symbol> ‘!=‘ <symbol> (3)
‘(‘ <expr> ‘)‘ (4)
‘!‘ <expr> (5)
<expr> ‘&&‘ <expr> (6)
<expr> ‘||‘ <expr> (7)
表达式是以优先级的降序列出的。
(1)将一个symbol转换成表达式。Boolean和tristate symbol简单地转换成相应的表达式值。其它类型的symbol就赋值‘n’。
(2)如果两个symbol的值相等,返回y,否则返回n。
(3)如果两个symbol的值相等,返回n,否则返回y。
(4)返回表达式的值,用于覆盖优先级。
(5)返回 (2-/expr/) 的结果。
(6)返回 min(/expr/,/expr/) 的结果。
(7)返回 max(/expr/,/expr/) 的结果。
一个表达式的值可以是‘n‘,‘m‘或‘y‘(或者是计算的结果 0,1,2)。当表达式的值为‘m‘或‘y‘的时候,菜单项才是可见的。
symbol有两种类型:不可变的和可变的。不可变的symbol是最普通的,由‘config‘语句定义。可变symbol由字母和下划线组成。
不可变的symbol只是表达式的一部分。经常用单引号或双引号括起来。在引号中,可以使用任何字符,使用引号要用转义字符‘\‘。
4. Menu structure
菜单entry的位置在结构树中的定义有两种方式。第一种方式是明确地进行指定:
menu "Network device support"
depends on NET
config NETDEVICES
...
endmenu
在“menu”到“endmenu”块中的所有entry都是"Network device support"的子菜单。所有的子菜单选项都继承了父菜单的依赖关系,比如,"NET"的依赖关系就被加到了配置选项NETDEVICES的依赖列表中。
另一种就是通过分析依赖关系生成菜单的结构。如果菜单entry在一定程度上依赖于前面的entry,它就能成为该entry的子菜单。首先,前面的(父)symbol必须是依赖列表中的一部分并且它们中必须满足下面两个条件之一:
- 如果父选项为‘n‘,子选项必须不可见。
- 如果父选项可见,子选项才能可见。
config MODULES
bool "Enable loadable module support"
config MODVERSIONS
bool "Set version information on all module symbols"
depends on MODULES
comment "module support disabled"
depends on !MODULES
MODVERSIONS 直接依赖于 MODULES,这意味着它只有当MODULES的值不是’n’的时候才是可见的。如果MODULES是可见的,那么comment也是可见的(MODULES的依赖关系也是comment依赖项的一部分)。
5. Kconfig syntax
这个配置文件描述了一系列的菜单entry,文件中的每一行都以一个关键字开头(除了帮助文本)。下面的关键字用来结束一个菜单entry:
- config
- menuconfig
- choice/endchoice
- comment
- menu/endmenu
- if/endif
- source
前面5个也用来开始一个菜单entry的定义。
config:
"config" <symbol>
<config options>
定义一个配置symbol<symbol>,并且接受上面所说的任何属性作为选项。
menuconfig:
"menuconfig" <symbol>
<config options>
这个类似于上面所说的简单config entry,但是它给了前端一个提示:所有的子选项都应该作为一个单独的选项列表显示出来。
choices:
“choice” [symbol]
<choice options>
<choice block>
“endchoice”
该关键字定义了一组选择项,并且选项可以是前面描述的任何属性。选择只能是bool类型或tristate类型,并且布尔选择只允许一个单一的配置项被选中,三态选择还允许任何配置项被设置为“M”。这可以用在下面的情况:如果一个硬件存在多个驱动程序,并且只有一个驱动程序可以编译/加载到内核中,但所有的驱动程序可以编译成模块。
一个choice接受另外一个选项“optional”,允许将值设为’n’,并且不需要选择entry。
如果一个choice没有关联的symbol,你就不能对该choice进行多重定义。如果一个symbol和choice关联,那么你可以在其他地方定义相同的choice。
comment:
“comment” <prompt>
<comment options>
这定义了一条在用户配置过程中显示的注释,同时会写入导出文件。它的选项options只能是依赖项。
menu:
"menu" <prompt>
<menu options>
<menu block>
"endmenu"
这定义了一个菜单块,具体情况请查看之前的“Menu structure”。它的选项options只能是依赖项并有“visible”属性。
if:
"if" <expr>
<if block>
"endif"
这定义了一个if块。依赖表达式<expr>将会追加到所有在if ... endif 中的菜单选项中。
source:
"source" <prompt>
这个选项读取特定配置文件,配置文件经常会被解析。
mainmenu:
"mainmenu" <prompt>
如果配置程序选择使用该项,那么它将会设置配置程序的标题栏。它应该放在配置的最顶端。
6. Kconfig hints
这是一个Kconfig提示的集合,大部分在初次看时都不是很明显,但确实很多Kconfig文件中的常用提示。
Adding common features and make the usage configurable
它是一个常见用法开实现和一些架构相关的功能。
推荐做法是:使用一个名字为HAVE_*的配置变量,该变量定义在一些常见的Kconfig文件中,并且被相关的架构选择。
一个典型的例子是通用IOMAP功能的实现:
我们将会在lib/Kconfig文件中看到:
# Generic IOMAP is used to ...
config HAVE_GENERIC_IOMAP
config GENERIC_IOMAP
depends on HAVE_GENERIC_IOMAP && FOO
在lib/Makefile中,我们将看到:
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
对于每个使用通用IOMAP功能的架构,我们将看到:
config X86
select ...
select HAVE_GENERIC_IOMAP
select ...
注:我们使用已经存在的配置选项并且避免创建一个新的配置变量来选择HAVE_GENERIC_IOMAP。
注:内部配置变量HAVE_GENERIC_IOMAP的使用是用来克服选择的限制的,选择限制将不管依赖关系强制配置选项值为y。
依赖关系移动到symbol GENERIC_IOMAP,我们避免配置选项被强制赋给’y’值。
Build as module only
为了限制一个组件只生成模块,限定它的配置选项为"depends on m".比如:
config FOO
depends on BAR && m
限制FOO生成一个模块 (=m) 或者关闭 (=n)
Kconfig recursive dependency limitations
如果你遇到了Kconfig error:“recursive dependency detected” 检测到依赖关系递归,即循环依赖。Kconfig工具需要确保kconfig文件符合特定的配置要求。Kconfig必须要确定所有kconfig symbol的可能值,如果在两个或多个kconfig symbol间有循环依赖关系的话,这是不可能实现的。更多细节可参考下面的“Simple Kconfig recursive issue”小节。Kconfig没有递归依赖分辨性,这对写kconfig的人有一些启示。我们先解释一下问题存在的原因,然后提供一个Kconfig开发者带来的技术限制例子。希望尝试解决该限制的开发者,需要阅读下一个小节。
Simple Kconfig recursive issue
Read: Documentation/kbuild/Kconfig.recursion-issue-01
Test with:
make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig
Cumulative Kconfig recursive issue
Read: Documentation/kbuild/Kconfig.recursion-issue-02
Test with:
make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig
Practical solutions to kconfig recursive issue
遇到kconfig recursive issue的开发者有三个处理方式:
(1)移除任何不必要的“select FOO”或者“depends on FOO”
(2)匹配依赖关系语义:
i. 交换所有“select foo”为“depends on foo”
ii. 交换所有“depends on foo”为“select foo”
Future kconfig work
Kconfig的工作在澄清语义和评估使用a full SAT solver这两个区域很受欢迎。在开启更复杂的依赖关系映射或查询上a full SAT solver是可取的,同时可能解决recursive dependency issues。
Semantics of Kconfig
Kconfig用途很广,Linux只是其中之一。研究表明kconfig在12个项目中使用到。
在工具在实际评估依赖关系时,良好定义的语义是非常有帮助的。
[0] http://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf
[1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
[2] http://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf
[3] http://gsd.uwaterloo.ca/sites/default/files/icse2011.pdf
Full SAT solver for Kconfig
感兴趣的开发者可访问: http://kernelnewbies.org/KernelProjects/kconfig-sat
[0] http://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf
[1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
[2] https://cados.cs.fau.de
[3] https://vamos.cs.fau.de
[4] https://undertaker.cs.fau.de
[5] https://www4.cs.fau.de/Publications/2011/tartler_11_eurosys.pdf
标签:
原文地址:http://blog.csdn.net/fickyou/article/details/51167098