《Linux内核Makefile分析》之 auto.conf, auto.conf.cmd, autoconf.h【转】

摘要:
123456789101112131415161718ifeq#Readinconfig-includeinclude/config/auto.confifeq#ReadindependenciestoallKconfig*files,makesuretorun#oldconfigifchangesaredetected.-includeinclude/config/auto.conf.cmd#Toavoidanyimplicitruletokickin,defineanemptycommand$include/config/auto.conf.cmd:;#If.configisnewerthaninclude/config/auto.conf,someonetinkered#withitandforgottorunmakeoldconfig.#ifauto.conf.cmdismissingthenweareprobablyinacleanedtreeso#weexecutetheconfigsteptobesuretocatchupdatedKconfigfilesinclude/config/%.conf:$include/config/auto.conf.cmd$$-f$/Makefilesilentoldconfig其中,引用-includeinclude/config/auto.conf-includeinclude/config/auto.conf.cmd这两行尝试包含auto.conf和auto.conf.cmd这两个文件。假如我们已经编译好了vmlinux这个目标,那么我们会在include/config这个目录下看到auto.conf和auto.conf.cmd这两个文件。从include/config/%.conf:$include/config/auto.conf.cmd这条语句可以知道,auto.conf文件依赖于$和include/config/auto.conf.cmd。那么include/config/auto.conf.cmd这个文件应该在什么时候生成?现在仍然假设auto.conf和auto.conf.cmd还没有生成,那么由上面的$include/config/auto.conf.cmd:;这条语句知道,该语句中的目标没有依赖,也没有生成它的规则命令,所以可想GNUMake本身无法生成auto.conf.cmd的。123%config:scripts_basicoutputmakefileFORCE$mkdir-pinclude/linuxinclude/config$$$=scripts/kconfig$@这时,我们来到scripts/kconfig/Makefile文件里。

转自:http://blog.sina.com.cn/s/blog_87c063060101l25y.html

转载:http://blog.csdn.net/lcw_202/article/details/6661364

在编译构建性目标时(如 make vmlinux),顶层 Makefile 的 $(dot-config) 变量值为 1 。
在顶层 Makefile 的 497-504 行看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ifeq($(dot-config),1)
# Read in config
-includeinclude/config/auto.conf
ifeq($(KBUILD_EXTMOD),)
# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
-includeinclude/config/auto.conf.cmd
# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG)include/config/auto.conf.cmd: ;
# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf:$(KCONFIG_CONFIG)include/config/auto.conf.cmd
$(Q)$(MAKE)-f$(srctree)/Makefilesilentoldconfig

其中,

引用
-include include/config/auto.conf
-include include/config/auto.conf.cmd

这两行尝试包含 auto.conf 和 auto.conf.cmd 这两个文件。由于使用 -include 进行声明,所以即使这两个文件不存在也不会报错退出,比如在第 1 次编译内核,且已经配置好 .config 文件时,这两个文件还未生成。
假如我们已经编译好了 vmlinux 这个目标,那么我们会在 include/config 这个目录下看到 auto.conf 和 auto.conf.cmd 这两个文件。
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd 这条语句可以知道,auto.conf 文件依赖于 $(KCONFIG_CONFIG) 和 include/config/auto.conf.cmd 。其中 $(KCONFIG_CONFIG) 变量的值就是 .config 这个配置文件。那么

include/config/auto.conf.cmd 这个文件应该在什么时候生成?
现在仍然假设 auto.conf 和 auto.conf.cmd 还没有生成,那么由上面的 $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ; 这条语句知道,该语句中的目标没有依赖,也没有生成它的规则命令,所以可想 GNU Make 本身无法生成 auto.conf.cmd 的。然后该条语句后面的一个分号表明,这两个目标被强制是最新的,所以下面这条命令得以执行:
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
这里我们看到要生成一个目标 silentoldconfig ,这个目标定义在 scripts/kconfig/Makefile 中。因为这里使用 -f 选项重新指定了顶层 Makefile,而目标又是 silentoldconfig ,所以该命令最终会在顶层 Makefile 的 462-464 这里执行:
1
2
3
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir-pinclude/linuxinclude/config
$(Q)$(MAKE)$(build)=scripts/kconfig$@

这时,我们来到 scripts/kconfig/Makefile 文件里。在该文件的 32-34 行看到:
1
2
3
silentoldconfig:$(obj)/conf
$(Q)mkdir-pinclude/generated
$< -s$(Kconfig)

从上面看到,silentoldconfig 目标需要依赖 conf 这个程序,该程序也在 scripts/kconfig 目录下生成。
$< -s $(Kconfig) 该条命令相当于 conf -s $(Kconfig) ,这里 $(Kconfig) 是位于不同平台目录下的 Kconfig 文件,比如在 x86 平台就是 arch/x86/Kconfig 。
conf 程序的源代码的主函数在同目录的 conf.c 文件中,在 main() 函数中看到:
1
2
3
4
5
6
7
8
9
10
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 。同样在 main() 函数还看到:
1
2
3
4
5
6
7
8
9
10
11
12
13
if(sync_kconfig) {
name = conf_get_configname();
if(stat(name, &tmpstat)) {
fprintf(stderr, _("*** "
"*** You have not yet configured your kernel! "
"*** (missing kernel config file "%s") "
"*** "
"*** Please run some configurator (e.g. "make oldconfig" or "
"*** "make menuconfig" or "make xconfig"). "
"*** "), name);
exit(1);
}
}

上面代码中,如果我们从未配置过内核,那么就会打印出错误信息,然后退出。这里假设已经配置过内核,并生成了 .config 文件,那么在 main() 函数中会来到:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
switch(input_mode) {
caseset_default:
if(!defconfig_file)
defconfig_file = conf_get_default_confname();
if(conf_read(defconfig_file)) {
printf(_("*** "
"*** Can't find default configuration "%s"! "
"*** "), defconfig_file);
exit(1);
}
break;
caseask_silent:
caseask_all:
caseask_new:
conf_read(NULL);
break;
... ...

由于使用 s 选项,则 input_mode 为 ask_silent,所以这里会执行 conf_read(NULL); 函数。
conf_read(NULL); 函数用来读取 .config 文件。读取的各种相关内容主要存放在一个 struct symbol 结构链表里,而各个结构的相关指针则放在一个 symbol_hash[] 的数组中,对于数组中元素的寻找通过 fnv32 哈希算法进行定位。
最后会来到 conf.c 中的底部:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if(sync_kconfig) {
if(conf_get_changed() && conf_write(NULL)) {
fprintf(stderr, _(" *** Error during writing of the kernel configuration. "));
exit(1);
}
if(conf_write_autoconf()) {
fprintf(stderr, _(" *** Error during update of the kernel configuration. "));
return1;
}
}else{
if(conf_write(NULL)) {
fprintf(stderr, _(" *** Error during writing of the kernel configuration. "));
exit(1);
}
}

实际上也只有当处理 silentoldconfig 目标是 sync_kconfig 变量才会为 1 。上面代码中的 conf_write_autoconf() 函数就用来生成 auto.conf, auto.conf.cmd 以及 autoconf.h 这 3 个文件。
在 if (conf_get_changed() && conf_write(NULL)) 这个判断里,conf_get_changed() 函数判断 .config 文件是否做过变动,如果是,那么会调用 conf_write(NULL) 来重新写 .config 文件。实际上,对于 defconfig, oldconfig, menuconfig 等目标来说,conf 程序最终也是调用 conf_write() 函数将配置结果写入 .config 文件中(最后那个 else 里的内容便是)。
确保了 .config 已经最新后,那么调用 conf_write_autoconf() 生成 auto.conf,auto.conf.cmd 以及 autoconf.h 这 3 个文件。
来到 conf_write_autoconf() 函数:
在 conf_write_autoconf() 里,调用 file_write_dep("include/config/auto.conf.cmd"); 函数将相关内容写入 auto.conf.cmd 文件。在生成的 auto.conf.cmd 文件中可以看到:
1
2
include/config/auto.conf:
$(deps_config)

可以看到 auto.conf 文件中的内容依赖于 $(deps_config) 变量里定义的东西,这些东西基本上是各个目录下的 Kconfig 以及其它一些相关文件。
auto.config 和 .config 的差别是在 auto.config 里去掉了 .config 中的注释项目以及空格行,其它的都一样。
仍然在 conf_write_autoconf() 里,分别建立了 .tmpconfig,.tmpconfig_tristate 和 .tmpconfig.h 这 3 个临时文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
out =fopen(".tmpconfig","w");
if(!out)
return1;
tristate =fopen(".tmpconfig_tristate","w");
if(!tristate) {
fclose(out);
return1;
}
out_h =fopen(".tmpconfig.h","w");
if(!out_h) {
fclose(out);
fclose(tristate);
return1;
}

然后将文件头的注释部分分别写入到这几个临时文件中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sym = sym_lookup("KERNELVERSION", 0);
sym_calc_value(sym);
time(&now);
fprintf(out,"# "
"# Automatically generated make config: don't edit "
"# Linux kernel version: %s "
"# %s"
"# ",
sym_get_string_value(sym),ctime(&now));
fprintf(tristate,"# "
"# Automatically generated - do not edit "
" ");
fprintf(out_h," "
"#define AUTOCONF_INCLUDED ",
sym_get_string_value(sym),ctime(&now));

接着在 for_all_symbols(i, sym) 这个循环里(是一个宏)里将相关内容分别写入到这几个文件中。
在最后一段代码中,将这几个临时文件进行改名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
name =getenv("KCONFIG_AUTOHEADER");
if(!name)
name ="include/generated/autoconf.h";
if(rename(".tmpconfig.h", name))
return1;
name =getenv("KCONFIG_TRISTATE");
if(!name)
name ="include/config/tristate.conf";
if(rename(".tmpconfig_tristate", name))
return1;
name = conf_get_autoconfig_name();
if(rename(".tmpconfig", name))
return1;

上面代码中的 conf_get_autoconfig_name() 实现为:
1
2
3
4
5
6
constchar*conf_get_autoconfig_name(void)
{
char*name =getenv("KCONFIG_AUTOCONFIG");
returnname ? name :"include/config/auto.conf";
}

从上面可以看到,分别生成了以下几个文件:
引用
include/generated/autoconf.h
include/config/tristate.conf
include/config/auto.conf

其中 include/generated/autoconf.h 头文件由内核本身使用,主要用来预处理 C 代码。比如在 .config 或 auto.conf 中定义要编译为模块的项,如:
CONFIG_DEBUG_NX_TEST=m
在 autoconf.h 中会被定义为:
#define CONFIG_DEBUG_NX_TEST_MODULE 1
在 .config 或 auto.conf 后接字符串值的项,如:
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
在 autoconfig.h 中会被定义为:
#define CONFIG_DEFCONFIG_LIST "/lib/modules/$UNAME_RELEASE/.config"
同样对应于 int 型的项如 CONFIG_HZ=1000 在 autoconf.h 中被定义为 #define CONFIG_HZ 1000 。

免责声明:文章转载自《《Linux内核Makefile分析》之 auto.conf, auto.conf.cmd, autoconf.h【转】》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇解决adober reader已停止工作的问题查询表空间总大小(dba_data_files和dba_segments,dba_free_space区别)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Delphi开发Linux版的kbmMW Server

项目需要,必须在CentOS上运行应用服务器,不得矣,已经三天的时间,终于把windows版的kbmMW Server运行到CentOS上了。一路坎坷,Linux从0开始,多亏xalion等朋友们相助,能出了第一个结果。 很早就想尝试用Linux做服务器,但迟迟没得动手,想不到最终还是现实逼的迫不得矣,这三天,从安装CentOS 7,再学习简单的命令,搭建...

后端开发工程师的开发环境配置(Vscode+C/Go/Python等)

前言         我是一名后端开发工程师,主要语言是C、Go、Python。早年做C开发的时候都是在windows下开发,一直使用的是soure insight,尤其是时隔多年更新的4.0版本解决了中文乱码等问题,用起来更是得心应手。后来转到Mac下开发,虽然可以用wine运行windows程序,但总感觉别扭,也是时候做一些新的尝试了。      ...

linux添加用户,修改用户密码,修改用户权限,设置root用户操作

1、添加普通用户 [root@server ~]# useradd chenjiafa   //添加一个名为chenjiafa的用户[root@server ~]# passwd chenjiafa    //修改密码Changing password for user chenjiafa.New UNIX password:              ...

[置顶] export命令-linux

export 命令 功能说明: 设置或显示环境变量。 语 法: export [-fnp][变量名称]=[变量设置值] 补充说明: 在shell中执行程序时,shell会提供一组环境变量。 export可新增,修改或删除环境变量,供后续执行的程序使用。export的效力仅及于该此登陆操作。 参 数: -f 代表[变量名称]中为函数名称...

Linux下PHP的完全卸载

如果想把PHP彻底的卸载干净,直接用yum的remove命令是不行的,而需要查看有多少rpm包,然后按照依赖顺序逐一卸载,在网上查了好多,都是通过 "rpm -qa | grep php" 命令查看有哪些rpm包,然后按照依赖关系依次卸载。 通过命令查看 [root@localhost test]# rpm -qa | grep php php-cli-5...

linux下数据推送(同步)方案

相信各位小伙伴在日常的工作中,经常会遇到需要将数据定时推送到别的服务器,甚至是要实时同步的情况。 下面笔者将会介绍几种可行的方式。 一.scp+ssh-key+crontab 这种是最原始的办法,但也是最基本,最不受限制的,基本只要能ssh到对端,这种方法就是可行的。笔者曾经在项目中遇到过两端的服务器之间存在多重网络限制。折腾来折腾去,最后还是选用这种方...