3.2 配置语言
1) 顶层菜单
mainmenu_name /prompt/ /prompt/ 是用'或"包围的字符串,'与"的区别是'…'中可使用$引用变量的值。mainmenu_name 设置最高层菜单的名字,它只在 make xconfig 时才会显示。
2) 询问语句
bool /prompt/ /symbol/ hex /prompt/ /symbol/ /word/ int /prompt/ /symbol/ /word/ string /prompt/ /symbol/ /word/ tristate /prompt/ /symbol/
询问语句首先显示一串提示符 /prompt/,等待用户输入,并把输入的结果赋给 /symbol/ 所代表的配置变量。不同的询问语句的区别在于它们接受的输入数据类型不同,比如 bool 接受布尔类型( y 或 n ),hex 接受 16 进制数据。有些询问语句还有第三个参数 /word/,用来给出缺省值。
3) 定义语句
define_bool /symbol/ /word/ define_hex /symbol/ /word/ define_int /symbol/ /word/ define_string /symbol/ /word/ define_tristate /symbol/ /word/
不同于询问语句等待用户输入,定义语句显式的给配置变量 /symbol/ 赋值 /word/。
4) 依赖语句
dep_bool /prompt/ /symbol/ /dep/ ... dep_mbool /prompt/ /symbol/ /dep/ ... dep_hex /prompt/ /symbol/ /word/ /dep/ ... dep_int /prompt/ /symbol/ /word/ /dep/ ... dep_string /prompt/ /symbol/ /word/ /dep/ ... dep_tristate /prompt/ /symbol/ /dep/ ...
与询问语句类似,依赖语句也是定义新的配置变量。不同的是,配置变量/symbol/的取值范围将依赖于配置变量列表/dep/ …。这就意味着:被定义的配置变量所对应功能的取舍取决于依赖列表所对应功能的选择。以dep_bool为例,如果/dep/ …列表的所有配置变量都取值y,则显示/prompt/,用户可输入任意的值给配置变量/symbol/,但是只要有一个配置变量的取值为n,则 /symbol/被强制成n。
不同依赖语句的区别在于它们由依赖条件所产生的取值范围不同。
5) 选择语句
choice /prompt/ /word/ /word/
choice 语句首先给出一串选择列表,供用户选择其中一种。比如 Linux for ARM 支持多种基于 ARM core 的 CPU,Linux 使用 choice 语句提供一个 CPU 列表,供用户选择:
choice 'ARM system type' \ "Anakin CONFIG_ARCH_ANAKIN \ Archimedes/A5000 CONFIG_ARCH_ARCA5K \ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ …… SA1100-based CONFIG_ARCH_SA1100 \ Shark CONFIG_ARCH_SHARK" RiscPC
Choice 首先显示 /prompt/,然后将 /word/ 分解成前后两个部分,前部分为对应选择的提示符,后部分是对应选择的配置变量。用户选择的配置变量为 y,其余的都为 n。
6) if语句
if [ /expr/ ] ; then /statement/ ... fi if [ /expr/ ] ; then /statement/ ... else /statement/ ... fi
if 语句对配置变量(或配置变量的组合)进行判断,并作出不同的处理。判断条件 /expr/ 可以是单个配置变量或字符串,也可以是带操作符的表达式。操作符有:=,!=,-o,-a 等。
7) 菜单块(menu block)语句
mainmenu_option next_commentcomment '…..'…endmenu
引入新的菜单。在向内核增加新的功能后,需要相应的增加新的菜单,并在新菜单下给出此项功能的配置选项。Comment 后带的注释就是新菜单的名称。所有归属于此菜单的配置选项语句都写在 comment 和 endmenu 之间。
8) Source 语句
source /word/
/word/ 是文件名,source 的作用是调入新的文件。
3.3 缺省配置
Linux 内核支持非常多的硬件平台,对于具体的硬件平台而言,有些配置就是必需的,有些配置就不是必需的。另外,新增加功能的正常运行往往也需要一定的先决条件,针对新功能,必须作相应的配置。因此,特定硬件平台能够正常运行对应着一个最小的基本配置,这就是缺省配置。
Linux 内核中针对每个 ARCH 都会有一个缺省配置。在向内核代码增加了新的功能后,如果新功能对于这个 ARCH 是必需的,就要修改此 ARCH 的缺省配置。修改方法如下(在 Linux 内核根目录下):
备份 .config 文件
cp arch/arm/deconfig .config
修改 .config
cp .config arch/arm/deconfig
恢复 .config
如果新增的功能适用于许多的 ARCH,只要针对具体的 ARCH,重复上面的步骤就可以了。
3.4 help file
大家都有这样的经验,在配置 Linux 内核时,遇到不懂含义的配置选项,可以查看它的帮助,从中可得到选择的建议。下面我们就看看如何给给一个配置选项增加帮助信息。
所有配置选项的帮助信息都在 Documentation/Configure.help 中,它的格式为:
<description><variable name><help file>
<description> 给出本配置选项的名称,<variable name> 对应配置变量,<help file> 对应配置帮助信息。在帮助信息中,首先简单描述此功能,其次说明选择了此功能后会有什么效果,不选择又有什么效果,最后,不要忘了写上"如果不清楚,选择 N(或者)Y",给不知所措的用户以提示。
回页首
4. 实例
对于一个开发者来说,将自己开发的内核代码加入到 Linux 内核中,需要有三个步骤。首先确定把自己开发代码放入到内核的位置;其次,把自己开发的功能增加到 Linux 内核的配置选项中,使用户能够选择此功能;最后,构建子目录 Makefile,根据用户的选择,将相应的代码编译到最终生成的 Linux 内核中去。下面,我们就通过一个简单的例子--test driver,结合前面学到的知识,来说明如何向 Linux 内核中增加新的功能。
4.1 目录结构
test driver 放置在 drivers/test/ 目录下:
$cd drivers/test$tree.|-- Config.in|-- Makefile|-- cpu| |-- Makefile| `-- cpu.c|-- test.c|-- test_client.c|-- test_ioctl.c|-- test_proc.c|-- test_queue.c`-- test |-- Makefile `-- test.c
4.2 配置文件
1) drivers/test/Config.in
## TEST driver configuration#mainmenu_option next_commentcomment 'TEST Driver'bool 'TEST support' CONFIG_TESTif [ "$CONFIG_TEST" = "y" ]; then tristate 'TEST user-space interface' CONFIG_TEST_USER bool 'TEST CPU ' CONFIG_TEST_CPUfiendmenu
由于 test driver 对于内核来说是新的功能,所以首先创建一个菜单 TEST Driver。然后,显示 "TEST support",等待用户选择;接下来判断用户是否选择了 TEST Driver,如果是(CONFIG_TEST=y),则进一步显示子功能:用户接口与 CPU 功能支持;由于用户接口功能可以被编译成内核模块,所以这里的询问语句使用了 tristate(因为 tristate 的取值范围包括 y、n 和 m,m 就是对应着模块)。
2) arch/arm/config.in
在文件的最后加入:source drivers/test/Config.in,将 TEST Driver 子功能的配置纳入到 Linux 内核的配置中。
4.3 Makefile
1)drivers/test/Makefile
# drivers/test/Makefile## Makefile for the TEST.#SUB_DIRS :=MOD_SUB_DIRS := $(SUB_DIRS)ALL_SUB_DIRS := $(SUB_DIRS) cpuL_TARGET := test.aexport-objs := test.o test_client.oobj-$(CONFIG_TEST) += test.o test_queue.o test_client.oobj-$(CONFIG_TEST_USER) += test_ioctl.oobj-$(CONFIG_PROC_FS) += test_proc.osubdir-$(CONFIG_TEST_CPU) += cpuinclude $(TOPDIR)/Rules.makeclean: for dir in $(ALL_SUB_DIRS); do make -C $$dir clean; done rm -f *.[oa] .*.flags
drivers/test 目录下最终生成的目标文件是 test.a。在 test.c 和 test-client.c 中使用了 EXPORT_SYMBOL 输出符号,所以 test.o 和 test-client.o 位于 export-objs 列表中。然后,根据用户的选择(具体来说,就是配置变量的取值),构建各自对应的 obj-* 列表。由于 TEST Driver 中包一个子目录 cpu,当 CONFIG_TEST_CPU=y(即用户选择了此功能)时,需要将 cpu 目录加入到 subdir-y 列表中。
2)drivers/test/cpu/Makefile
# drivers/test/test/Makefile## Makefile for the TEST CPU #SUB_DIRS :=MOD_SUB_DIRS := $(SUB_DIRS)ALL_SUB_DIRS := $(SUB_DIRS)L_TARGET := test_cpu.aobj-$(CONFIG_test_CPU) += cpu.oinclude $(TOPDIR)/Rules.makeclean: rm -f *.[oa] .*.flags
3)drivers/Makefile
……subdir-$(CONFIG_TEST) += test……include $(TOPDIR)/Rules.make
在 drivers/Makefile 中加入 subdir-$(CONFIG_TEST)+= test,使得在用户选择 TEST Driver 功能后,内核编译时能够进入 test 目录。
