《Linux内核Makefile分析》之 auto.conf, auto.conf.cmd, autoconf.h【转】
转自:http://blog.sina.com.cn/s/blog_87c063060101l25y.html
在编译构建性目标时(如 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-include include/config/auto.confifeq ($(KBUILD_EXTMOD),)# Read in dependencies to all Kconfig* files,# oldconfig if changes are-include include/config/auto.conf.cmd# To avoid any implicit rule to kick in, define$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;# If .config is newer than# with it and forgot to run make# if auto.conf.cmd is missing then we are# we execute the config step to be sure toinclude/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd $(Q)$(MAKE)-f $(srctree)/Makefile silentoldconfig |
其中,
引用-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
这个配置文件。那么
这个文件应该在什么时候生成?
现在仍然假设 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 $(Q)mkdir-p include/linux include/config $(Q)$(MAKE)$(build)=scripts/kconfig $@ |
这时,我们来到 scripts/kconfig/Makefile 文件里。在该文件的 32-34 行看到:
|
1
2
3
|
silentoldconfig: $(obj)/conf $(Q)mkdir-p include/generated $< $(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 = "osdD:nmyrh")) != -1) switch(opt) { case'o': input_mode break; case's': input_mode sync_kconfig break;... |
所以,在使用 s 参数时,sync_kconfig 这个变量会为 1 。同样在 main() 函数还看到:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
if(sync_kconfig) { name if(stat(name, &tmpstat)) { fprintf(stderr,"***\n" "*** "*** "***\n" "*** "*** "***\n"), 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 if(conf_read(defconfig_file)) { printf(_("***\n" "*** "***\n"), 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() && fprintf(stderr,"\n*** Error during writing of)); exit(1); } if(conf_write_autoconf()) { fprintf(stderr,"\n*** Error during update of the)); return1; } }else { if(conf_write(NULL)) { fprintf(stderr,"\n*** Error during writing of)); 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"KERNELVERSION", sym_calc_value(sym); time(&now); fprintf(out,"#\n" "# "# "# "#\n", sym_get_string_value(sym),ctime(&now)); fprintf(tristate,"#\n" "# "\n"); fprintf(out_h,"\n" "#define, 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", return1; name getenv("KCONFIG_TRISTATE"); if(!name) name "include/config/tristate.conf"; if(rename(".tmpconfig_tristate", return1; name if(rename(".tmpconfig", return1; |
上面代码中的 conf_get_autoconfig_name() 实现为:
|
1
2
3
4
5
6
|
const char *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【转】的更多相关文章
- linux内核Makefile整体分析
转自:http://www.cnblogs.com/amanlikethis/p/3675486.html <请阅读原文> 一.概述 1.本文的意义 众多的资料(<嵌入式Linux应 ...
- Linux内核源代码分析方法
Linux内核源代码分析方法 一.内核源代码之我见 Linux内核代码的庞大令不少人"望而生畏",也正由于如此,使得人们对Linux的了解仅处于泛泛的层次.假设想透析Linux ...
- 2019-2020-1 20199303 《Linux内核原理分析》 第一周作业
2019-2020-1 20199303 <Linux内核原理分析> 第一周作业 1. 环境准备 在众多的Linux发行版中,Ubuntu,小红帽还有类Unix系统的BSD系统,我选择了目 ...
- linux内核makefile概览
linux内核makefile概览 本博客参照内核官方英文文档 linux的内核makefile主要用于编译整个内核源码,按照用户的需求生成各种目标文件,对于用户来说,编译内核时非常简单的,只需要几个 ...
- Linux内核Makefile文件(翻译自内核手册)
--译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...
- Linux内核(3) - 分析内核源码如何入手(下)
下面的分析,米卢教练说了,内容不重要,重要的是态度.就像韩局长对待日记的态度那样,严谨而细致. 只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB,比如进程管理,在花 ...
- Linux内核(2) - 分析内核源码如何入手(上)
透过现象看本质,兽兽们无非就是一些人体艺术展示.同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的. 既然要学习内核源码,就要经常对内核代码进行分析, ...
- 《Linux内核与分析》第七周
by 21035130王川东 Linux内核如何装载和启动一个可执行程序 一. EIF文件格式: 1.ELF头部在文件的开始,描述文件的总体格式,保存了路线图,描述该文件的组织情况,即生成该文件系统的 ...
- Linux内核启动分析过程-《Linux内核分析》week3作业
环境搭建 环境的搭建参考课件,主要就是编译内核源码和生成镜像 start_kernel 从start_kernel开始,才真正进入了Linux内核的启动过程.我们可以把start_kernel看做平时 ...
随机推荐
- 【函数应用】PHP中关于URL的函数处理
一,函数介绍 1.解析HTTP头信息:get_header() array get_headers ( string 目标URL [, int $format = 0 [如果将可选的 format 参 ...
- java util - Hex转换工具
测试代码 package cn.java.codec.hex; public class Test { public static void main(String[] args) { String ...
- SSM(Spring+Spring MVC+Mybatis)开发前台后功能完整的java开源博客管理系统
项目描述 本项目通过SSM(SpringMVC+Mybatis+Spring)框架编写的一个人博客管理系统,使用hexo主题,以及MAVEN进行对项目管理,并且前端具有粒子和点击爱心效果.后端的页面框 ...
- 初学js之qq聊天实例
实现的功能为上图所示,但是每新发送的消息必须显示在最上面. 我实现了两版,样式有是一样的.我们直接看代码. 版本一: <!DOCTYPE html> <html lang=" ...
- Linux命令之---mv
命令简介 mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files) 命令格式 mv [选项] 源文件或目录 目标文件或目录 命令参数 -b 若需覆盖文件,则覆 ...
- [原]sencha touch之表单(login demo)
现在来说说sencha touch中的表单,举个简单的login的例子,相关的说明我都放在了注释中,看下面代码 Ext.application({ id:'itKingApp', launch:fun ...
- Java集合---List、Set、Iterator、Map简介
1.List集合 1.1概念 List继承自Collection接口.List是一种有序集合,List中的元素可以根据索引(顺序号:元素在集合中处于的位置信息)进行取得/删除/插入操作. 跟Set集合 ...
- day 16 JS DOM 继续
为什么有jquey了还学DOM ? 因为JQuey 是大而全,可能有10k 但是我们用到的只有1k 网站小没事,网站大流量就是问题 所以大网站都是自己用DOM 实现一个类似于JQuey 的适合自己 ...
- Hotspot GC实现原理
GC扫描 可达性分析的GC Roots主要是全局性引用或在Stack Frame中 ,现在的应用仅仅方法区往往就有几百兆,这样要这个检查这里面的引用,就必然会消耗很多时间,效率很低. 分析工作在一个保 ...
- Python 模块搜索路径
Python 会在什么地方寻找文件来导入模块? 使用命名为 path 变量的存储在标准 sys 模块 下的一系列目录名和 ZIP 压缩文件. 你可以读取和修改这个列表.下面是在我的 Mac 上 Pyt ...