Linux内核menuconfig分析

menuconfig原理详解

参考博客menuconfig原理分析

1、menuconfig内核解析过程

menuconfig的解析主要依赖scripts/目录下的kconfig:

(1)mconf.c文件的过程

该文件是一个包含main函数的c文件,主要作用是解析内核配置文件并生产.config文件,5.12.1内核版本的main函数实现如下,内核在这部分的变化很少:

int main(int ac, char **av)
{
	char *mode;
	int res;

	signal(SIGINT, sig_handler);

	if (ac > 1 && strcmp(av[1], "-s") == 0) {
		silent = 1;
		/* Silence conf_read() until the real callback is set up */
		conf_set_message_callback(NULL);
		av++;
	}
	conf_parse(av[1]);//解析配置参数,该参数实质上就是Kconfig,是由scripts/kconfig/Makefile文件中传入,该函数也是menuconfig的核心函数
	conf_read(NULL);

	mode = getenv("MENUCONFIG_MODE");
	if (mode) {
		if (!strcasecmp(mode, "single_menu"))
			single_menu_mode = 1;
	}

	if (init_dialog(NULL)) {//这里实质上是调用curses库函数,对应的第三方库为 ncurses-dev,是一种图形化库
		fprintf(stderr, "Your display is too small to run Menuconfig!\n");
		fprintf(stderr, "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);//设置配置文件msg处理回调函数,该函数主要是格式化处理配置文件。
	do {
		conf(&rootmenu, NULL);//真正意义上的设置配置的过程,实质上就是讲配置文件的内容解析到struct menu结构体变量中,并记录下图形化处理过的内容,这个内容以一种双向链表的形式存在。
		res = handle_exit();
	} while (res == KEY_ESC);

	return res;
}

(2)conf_parse对Kconfig的解析过程

该函数在内核中的实现有变化,在5.12.1版本,该函数定义在scripts/kconfig/parser.y中,4.19.125版本定义在zconf.y中,4.4.58版本定义在zconf.tab.c中,详细实现如下:

void conf_parse(const char *name)
{
	struct symbol *sym;
	int i;

	zconf_initscan(name);//Kconfig文件的初始化扫描

	_menu_init();//初始化struct menu全局变量

	if (getenv("ZCONF_DEBUG"))
		yydebug = 1;
	yyparse();//在老一点的内核版本中使用的是zconfparse函数解析

	/* Variables are expanded in the parse phase. We can free them here. */
	variable_all_del();

	if (yynerrs)
		exit(1);
	if (!modules_sym)
		modules_sym = sym_find( "n" );

	if (!menu_has_prompt(&rootmenu)) {
		current_entry = &rootmenu;
		menu_add_prompt(P_MENU, "Main menu", NULL);
	}

	menu_finalize(&rootmenu);
	for_all_symbols(i, sym) {
		if (sym_check_deps(sym))
			yynerrs++;
	}
	if (yynerrs)
		exit(1);
	sym_set_change_count(1);
}

(3)conf函数实现内核配置

这里直接贴代码,不再详述,主要作用就是解析出从Kconfig读取的内容,并逐个记录到menu队列中,在解析玩配置文件以及从menuconfig图形界面读取到修改之后,会读取图形界面的各种选择,判断是否保存修改,并提示通过ESC推出界面,这里主要通过conf_get_changed来判断是否在图形界面有修改(与原来的.config比较,如果没有.config文件,则直接保存配置),在保存文件之后,结束图形界面,同事讲配置内容写到.config中。

static void conf(struct menu *menu, struct menu *active_menu)
{
	struct menu *submenu;
	const char *prompt = menu_get_prompt(menu);
	struct subtitle_part stpart;
	struct symbol *sym;
	int res;
	int s_scroll = 0;

	if (menu != &rootmenu)
		stpart.text = menu_get_prompt(menu);
	else
		stpart.text = NULL;
	list_add_tail(&stpart.entries, &trail);//加入到队尾

	while (1) {
		item_reset();
		current_menu = menu;
		build_conf(menu);
		if (!child_count)
			break;
		set_subtitle();
		dialog_clear();
		res = dialog_menu(prompt ? prompt : "Main Menu",
				  menu_instructions,
				  active_menu, &s_scroll);
		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
			break;
		if (item_count() != 0) {
			if (!item_activate_selected())
				continue;
			if (!item_tag())
				continue;
		}
		submenu = item_data();
		active_menu = item_data();
		if (submenu)
			sym = submenu->sym;
		else
			sym = NULL;

		switch (res) {
		case 0:
			switch (item_tag()) {
			case 'm':
				if (single_menu_mode)
					submenu->data = (void *) (long) !submenu->data;
				else
					conf(submenu, NULL);
				break;
			case 't':
				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
					conf_choice(submenu);
				else if (submenu->prompt->type == P_MENU)
					conf(submenu, NULL);
				break;
			case 's':
				conf_string(submenu);
				break;
			}
			break;
		case 2:
			if (sym)
				show_help(submenu);
			else {
				reset_subtitle();
				show_helptext("README", mconf_readme);
			}
			break;
		case 3:
			reset_subtitle();
			conf_save();
			break;
		case 4:
			reset_subtitle();
			conf_load();
			break;
		case 5:
			if (item_is_tag('t')) {
				if (sym_set_tristate_value(sym, yes))
					break;
				if (sym_set_tristate_value(sym, mod))
					show_textbox(NULL, setmod_text, 6, 74);
			}
			break;
		case 6:
			if (item_is_tag('t'))
				sym_set_tristate_value(sym, no);
			break;
		case 7:
			if (item_is_tag('t'))
				sym_set_tristate_value(sym, mod);
			break;
		case 8:
			if (item_is_tag('t'))
				sym_toggle_tristate_value(sym);
			else if (item_is_tag('m'))
				conf(submenu, NULL);
			break;
		case 9:
			search_conf();
			break;
		case 10:
			show_all_options = !show_all_options;
			break;
		}
	}

	list_del(trail.prev);
}

//保存配置文件并退出图形界面
static int handle_exit(void)
{
	int res;

	save_and_exit = 1;
	reset_subtitle();
	dialog_clear();
	if (conf_get_changed())
		res = dialog_yesno(NULL,
				   "Do you wish to save your new configuration?\n"
				     "(Press <ESC><ESC> to continue kernel configuration.)",
				   6, 60);
	else
		res = -1;

	end_dialog(saved_x, saved_y);

	switch (res) {
	case 0:
		if (conf_write(filename)) {
			fprintf(stderr, "\n\n"
					  "Error while writing of the configuration.\n"
					  "Your configuration changes were NOT saved."
					  "\n\n");
			return 1;
		}
		conf_write_autoconf(0);
		/* fall through */
	case -1:
		if (!silent)
			printf("\n\n"
				 "*** End of the configuration.\n"
				 "*** Execute 'make' to start the build or try 'make help'."
				 "\n\n");
		res = 0;
		break;
	default:
		if (!silent)
			fprintf(stderr, "\n\n"
					  "Your configuration changes were NOT saved."
					  "\n\n");
		if (res != KEY_ESC)
			res = 0;
	}

	return res;
}

2、内核配置文件依赖

配置文件主要包括下面部分的解析:
config-prog := conf
menuconfig-prog := mconf //这里主要解析的是Kconfig
nconfig-prog := nconf
gconfig-prog := gconf
xconfig-prog := qconf
而内核最终的配置文件(.config)主要来源于Kconfig解析、arch/$ARCH/configs下的配置文件读取。

内核根目录新增配置

如果想新增一个原始内核不存在的一级配置,只需要在内核根目录下的Kconfig添加(source “…”)新增一级配置的Kconifg,若要能够成功编译新增模块,只需要改写Makefile即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值