Makefile 对应内核版本:2.6.35.13
在未配置内核时(没有 .config 这样的配置文件) 就执行如 make vmlinux 这样的构建命令会看到下面的错误提示:$ make vmlinux
/bin/sh: cannot open ncurses.h: No such file
scripts/kconfig/conf -s arch/x86/Kconfig
***
*** You have not yet configured your kernel!
*** (missing kernel config file ".config")
***
*** Please run some configurator (e.g. "make oldconfig" or
*** "make menuconfig" or "make xconfig").
***
make[2]: *** [silentoldconfig] Error 1
make[1]: *** [silentoldconfig] Error 2
make: *** No rule to make target `include/config/auto.conf', needed by `include/config/kernel.release'. Stop. 下面跟踪上面的出错产生流程。
在执行 make vmlinux 这样的内核目标时,在顶层 Makefile 里 $(dot-config) 变量( dog-config 目标是与 .config 配置相关的或依赖于 .config 文件的构建的目标)会设为 1,这样在顶层 Makefile 的 487 行判断通过:
因为在构建内核时,在 make 处理任何目标之前,它会努力生成 include/cofig/auto.conf 这个文件;在 489 ,494行看到:
[code=Makefile]
489 -include include/config/auto.conf
494 -include include/config/auto.conf.cmd[/mw_shl_code]
这里尝试将 auto.conf 和 auto.conf.cmd 这两个文件包含进来,注意这里用的是 -include ,它表示此时即使现在没有这个 auto.conf 和 autu.conf.cmd,make 也不会理会,它仍然会继续往下走其余的流程。
在 497 行,499-504 行有:
[code=Makefile]
497 $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
499 # If .config is newer than include/config/auto.conf, someone tinkered
500 # with it and forgot to run make oldconfig.
501 # if auto.conf.cmd is missing then we are probably in a cleaned tree so
502 # we execute the config step to be sure to catch updated Kconfig files
503 include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
504 $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
[/mw_shl_code]
上面的 $(KCONFIG_CONFIG) 变量就是 .config 文件。这里就是说, auto.conf 的生成依赖于 .config 和 auto.conf.cmd 这两个文件。如果 .config 和 auto.conf.cmd 如果比 auto.conf 要新,那么会重新构建 auto.conf 目标,这时会执行底下的语句。实际上这里,即使一个全新的还未配置过的内核,自然不会有 .config 和 auto.conf.cmd 这两个文件。然而,在 497 行我们看到 $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ; 这条语句,它后面有个分号,是个空依赖,它的作用是让 $(KCONFIG_CONFIG) 和 include/config/auto.conf.cmd 这两个目标看起来仍然是最新的(注意,这里的最新和它们是否实际存在并不冲突,当作普通的变量看待即可)。所以,这一定会执行 504 行的命令:$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig 。
为什么这里 -f $(srctree)/Makefile 一下呢?
原因是我们执行的是 make vmlinux 命令,这不是在构建 *config 目标,所以 $(config-targets) 变量为空,那它就不会进到 458-464 行这里来。然而使用 -f 选项再重新走一遍顶层 Makefile ,因为这时是在构建 silentoldconfig 目标(*config) ,所以 $(config-targets) 变量会为 1,从而会进入 462-464 行中来:
[code=Makefile]462 %config: scripts_basic outputmakefile FORCE
463 $(Q)mkdir -p include/linux include/config
464 $(Q)$(MAKE) $(build)=scripts/kconfig $@[/mw_shl_code]
进到这里来后,又看到了 $(Q)$(MAKE) $(build) 命令,这实际是调用 Makefile.build 文件,而在 Makefile.build 中又包含了 scrpits/kconfig/Makefile ,所以自然能够找到 silentoldconfig 这个目标了。
在 scrpits/kconfig/Makefile 中 silentoldconfig 的实现为:
[code=Makefile] 32 silentoldconfig: $(obj)/conf
33 $(Q)mkdir -p include/generated
34 $< -s $(Kconfig)[/mw_shl_code]
从上面可以看到,我们调用 conf 这个程序并以 -s 参数来处理 Kconfig 文件。下面来看一下 conf.c 这个文件中的相关代码片段:
[C++] 纯文本查看 复制代码 while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
switch (opt) {
case 'o':
input_mode = ask_silent;
break;
case 's':
input_mode = ask_silent;
sync_kconfig = 1;
break;
在使用 -s 选项时 sync_kconfig 会为 1 ,接着:
[C++] 纯文本查看 复制代码 if (sync_kconfig) {
name = conf_get_configname();
if (stat(name, &tmpstat)) {
fprintf(stderr, _("***\n"
"*** You have not yet configured your kernel!\n"
"*** (missing kernel config file \"%s\")\n"
"***\n"
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
"*** \"make menuconfig\" or \"make xconfig\").\n"
"***\n"), name);
exit(1);
}
}
其中 conf_get_configname() 函数在 confdata.c (同在 scripts/kconfig 下) 中实现:
[C++] 纯文本查看 复制代码 const char *conf_get_configname(void)
{
char *name = getenv("KCONFIG_CONFIG");
return name ? name : ".config";
}
这里使用 getenv() 函数获取环境变量并存到 name 中,最后返回的是 .config 。然后再用 stat(name, &tmpstat); 测试 .config 文件是否存在,stat() 函数在测试的文件存在时返回 0 ,而这里我们没有对内核配置过,也就是不会产生 .config ,所以 stat() 返回非 0,所以接下来就打印上面的出错信息。 |