1. menuconfig 和Kconfig 介绍
有过 linux 内核开发经验的人,对menuconfig 不会陌生。对于各类内核,只要是支持menuconfig 配置界面,都是使用Kconfig。
换言之:
- menuconfig:支持配置内核的图形化界面。
- Kconfig:生成menuconfig 界面的脚本语言。
故我们只要熟悉了Kconfig 的语法规则,就熟悉了 menuconfig的应用。这样对于基于menconfig 配置界面的各类内核都能得心应手了。
2. 配置界面
linux 内核的配置界面如下:
思考两个问题:
- 这个配置文件是如何组织和生成的?
- 各项配置又是如何被使用的?
2.1 界面生成和组织
熟悉内核的都知道, 配置内核的过程中只需要执行 make menconfig 界面就自动出来了。
那么,在执行make mneconfig 的过程中到底发生了什么?
Makefile scripts/kconfig/Makefile
- 顶层Makefile:依赖子makefile。这里MAKECMDGOALS 变量很重要。
- scripts/kconfig/Makefile。顶层makefile 执行
make menuconfig 过程:
- 首先执行顶层Makefile。
- 然后执行scripts/kconfig/Makefile
- 编译 kconfig 下相关工具。
- 生成mconf 工具
lxdialog:checklist/inputbox/menubox/texbox/yesno等图形显示组件mconf:menuconfig 读写解析应用
menu:菜单处理
conf:xxxdefconfig 解析
mconf 核心代码如下:
//script/kconfig/mconf.c int main(int ac, char **av) { char *mode; int res; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); signal(SIGINT, sig_handler); conf_parse(av[1]); conf_read(NULL); mode = getenv("MENUCONFIG_MODE"); if (mode) { if (!strcasecmp(mode, "single_menu")) single_menu_mode = 1; } if (init_dialog(NULL)) { fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); return 1; } set_config_filename(conf_get_configname()); conf_set_message_callback(conf_message_callback); do { conf(&rootmenu, NULL); res = handle_exit(); } while (res == KEY_ESC); return res; }
我们可以看到,干了三件事:
- 解析Kconfig:./mconf Kconfig
- 生成对话框:init_dialog
- 配置界面:conf
最终会将配置界面设置保存成 .config 文件。
2.2 .config 应用
我们在编译内核前通过有两种操作:
- make xxx_defconfig;make uImage;
- make xxx_defconfig; make menucnfig; make uImage;
make xxx_defconfig 操作会生成 conf 应用,并且解析xxx_defconfig。make menuconfig 操作会生成 mconf 应用,会将我们配置的选项保存成 .config
当我们在执行编译内核的时候,会自动将 .config 里面的配置 转换成相应的宏到 autoconf.h 里面。
2.2.1 .config 保存
//mconf // 对话框退出 main() handle_exit() conf_write() //script/kconf/confdata.c conf_message(_("configuration written to %s"), newname) // 配置后保存 main() conf() conf_save() conf_write() //script/kconf/confdata.c conf_message(_("configuration written to %s"), newname) // conf : conf 直接将xxx_defconfig 保存成 .config main() conf_write()
无论是是 menuconfg 配置, 还是解析 xxx_defconfig 最终都会先保存成 .config
2.2.2 .config 解析
当我们配置生成好 .config 后。在编译内核的时候,会提前将 .config 转换对应的宏。
//conf.c main(); conf_write_autoconf(); file_write_dep("include/config/auto.conf.cmd"); .... if (!name) name = "include/generated/autoconf.h"; if (rename(".tmpconfig.h", name)) return 1; name = getenv("KCONFIG_TRISTATE"); if (!name) name = "include/config/tristate.conf"; if (rename(".tmpconfig_tristate", name)) return 1; name = conf_get_autoconfig_name();
2.2.3 总结
linux 内核主要是基于 Kconfig 来组织menuconfig从而达到配置内核的目的。那么主要从两方面入手。
- make menuconfig :生成mconf 应用,产生图形界面,并且保存.config
- make xxx_defconf:生成conf 应用,解析xxx_defconf,并保存成.config
本质上.config 和 xxx_defconfig 是同一文件。
在编译内核的过程中会将 .config 转换为相应的宏,包含在头文件autoconf.h 中,这样就可以供内核使用了。
故我们只需要掌握了 Kconfig 配置,就基本掌握了menuconfig 配置和添加流程。
3. Kconfig 常用语法
3.1 配置项前缀
在Kconfig文件中,假设配置项的名字是XXX,在.config文件中:
- 默认情况下,它对应的变量名为CONFIG_XXX
- 如果设置了环境变量CONFIG_=ABC,则对应的变量名为ABC_XXX
3.2 单个配置项 config
如图 USB Webcam Gadget 就是一个配置项:
- 输入M:编成模块形式。.config 对应 CONFIG_USB_G_WEBCAM=M
- 输入N:不选择配置。.config 对应 CONFIG_USB_G_WEBCAM is not set
3.2.1. 语法
我们还是以一个例子说明:
# put drivers that need isochronous transfer support (for audio # or video class gadget drivers), or specific hardware, here. config USB_G_WEBCAM tristate "USB Webcam Gadget" depends on VIDEO_DEV select USB_LIBCOMPOSITE select VIDEOBUF2_VMALLOC help The Webcam Gadget acts as a composite USB Audio and Video Class device. It provides a userspace API to process UVC control requests and stream video data to the host. Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_webcam".
config 配置基础语法如下:
config option type "xxx" //简单描述 depends on xxx //依赖选项,可选 default xxx //初始值 help //帮助信息 xxxxxxxxxxxxxxx
- config option 是一个配置的开始,紧跟着的是配置选项的名称。
- config 下定义了以下属性:
- 类型、输入提示、依赖关系、默认值、帮助信息。
- 每个表示配置的菜单都有类型。变量共有五种类型。
- bool:布尔类型
- tristate:三态类型
- string:字符串
- hex:十六进制
- int:整型
- "USB Webcam Gadget":提示信息
- depends on:表示依赖关系。只有VIDEO_DEV 选中,才可以选择该项
- default:表示配置项的默认值。bool 类型可以是 y/n
- help:帮助信息
3.2.2. 示例
config TEST_A bool "config test A" default y help test config test A, yes/no config TEST_B bool "config test B" depends on TEST_A default y help test config test B, yes/no
TEST_B 只有在A 选中才能生效。
3.3. 菜单menu/endmenu
如图 USB audio choice 包含两个配置项。UAC1_PLAY 和 UAC1_CAP
3.3.1. 语法
menu "USB audio choice" depends on GADGET_UAC1 config GADGET_UAC1_PLAY tristate "USB audio play" default y config GADGET_UAC1_CAP default y tristate "USB audio cap" choice prompt "cap from" default MIC depends on GADGET_UAC1_CAP config GADGET_UAC1_CAP_USER bool "cap from user" config GADGET_UAC1_CAP_MIC bool "cap from mic" endchoice endmenu
我们先忽略 choice 和 endchoice。menu 语法以 menu 开始,endmenu 结束。中间包含若干项config配置, 当然也可以包含 其他语法。
3.3.2. 示例
menu "test menu" config TEST_MENU_A tristate "menu test A" config TEST_MENU_B bool "menu test B" default n endmenu
test menu 包含两个配置项:
3.4. 单选 choice/endchoice
如图为 linux usb gadget 驱动,支持各种gadget 设备:
3.4.1 语法
choice config USB_G_HID tristate "HID Gadget" select USB_LIBCOMPOSITE help ¦ The HID gadget driver provides generic emulation of USB ¦ Human Inter # put drivers that need isochronous transfer support (for audio # or video class gadget drivers), or specific hardware, here. ...... config USB_G_WEBCAM tristate "USB Webcam Gadget" depends on VIDEO_DEV select USB_LIBCOMPOSITE select VIDEOBUF2_VMALLOC help ¦ The Webcam Gadget acts as a composite USB Audio and Video Class ¦ device. It provides a userspace API to process UVC control requests ¦ and stream video data to the host. ¦ Say "y" to link the driver statically, or "m" to build a ¦ dynamically linked module called "g_webcam". endchoice
- choice 开始,endchoice 结束。
- choice 中间可以加入其他配置,以及 choice 嵌套
- 他们之间只能有一个被设置为 y:表示编译进内核
- 他们之间可以有多个被设置为 m:表示编译成模块
3.4.2. 示例
choice prompt "The maximal size of fifo" default USB_FIFO_512 config USB_FIFO_512 bool "512" config USB_FIFO_1024 bool "1024" config USB_FIFO_3072 bool "3072" endchoice
3.5. menuconfig
menuconfig XXX和config XXX类似, 唯一不同的是该选项除了能设置y/m/n外,还可以实现菜单效果(能回车进入该项内部)。
比如 usb gadget 驱动就是 menuconfig 配置
3.5.1. 语法
menuconfig常用格式有2种:
menuconfig M if M config C1 config C2 endif
或者
menuconfig M config C1 depends on M config C2 depends on M
第1项menuconfig M跟config M语法是一样的, 不同之处在于menuocnfig M后面可以跟着好几个依赖于M的config C1、config C2等子配置项.
3.6. if/endif
3.6.1. 语法
在上面的menuconfig中就有if/endif的使用,它的语法如下:
if xxx endif
3.6.2. 示例
if USB_GADGET config USB_GADGET_DEBUG boolean "Debugging messages (DEVELOPMENT)" depends on DEBUG_KERNEL help ¦ Many controller and gadget drivers will print some debugging ¦ messages if you use this option to ask for those messages. ¦ A ...... endif
只有定义了 USB_GADGET ,以下部分才会显示出来。
3.7. source
3.7.1. 语法
source 语句用于读取另一个文件中的 Kconfig 文件, 比如driver/usb/Kconfig 中就包含了其他Kconfig:
source "drivers/usb/gadget/Kconfig"
3.8. comment
3.8.1. 语法
comment 语句出现在界面的第一行,用于定义一些提示信息,如:
界面如下:
4. 总结
本文主要分析了 menuconfig 生成和使用过程,并且介绍了Kconfig 常见用法及语法介绍。
有关 config/menu/menuconfig/choice等 Kconfig语法本质上就是脚本语言,也存在对应的相互组合关系,每种语法规则不是独立的。熟悉了 Kconfig 基本组织规则,那么就熟悉了 内核配置过程。无论是 linux 还是 rtos 只要是基于menconfig 配置的都是一通百通。