转自: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
-include include/config/auto.conf
 
ifeq ($(KBUILD_EXTMOD),)
# Read in dependencies to all Kconfig* files,
make sure to run
# oldconfig if changes are
detected.
-include include/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)/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
这个配置文件。那么

 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
-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
        $<
-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,
_(
"***\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);
        }
    }

上面代码中,如果我们从未配置过内核,那么就会打印出错误信息,然后退出。这里假设已经配置过内核,并生成了 .config 文件,那么在
main() 函数中会来到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    switch
(input_mode) {
    case
set_default:
        if
(!defconfig_file)
            defconfig_file
= conf_get_default_confname();
        if
(conf_read(defconfig_file)) {
            printf(_("***\n"
                "***
Can't find default configuration \"%s\"!\n"
                "***\n"),
defconfig_file);
            exit(1);
        }
        break;
    case
ask_silent:
    case
ask_all:
    case
ask_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,
_(
"\n*** Error during writing of
the kernel configuration.\n\n"
));
            exit(1);
        }
        if
(conf_write_autoconf()) {
            fprintf(stderr,
_(
"\n*** Error during update of the
kernel configuration.\n\n"
));
            return
1;
        }
    }
else {
        if
(conf_write(NULL)) {
            fprintf(stderr,
_(
"\n*** Error during writing of
the kernel configuration.\n\n"
));
            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)
        return
1;
 
    tristate
=
fopen(".tmpconfig_tristate", "w");
    if
(!tristate) {
        fclose(out);
        return
1;
    }
 
    out_h
=
fopen(".tmpconfig.h",
"w");
    if
(!out_h) {
        fclose(out);
        fclose(tristate);
        return
1;
    }

然后将文件头的注释部分分别写入到这几个临时文件中:

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,
"#\n"
             "#
Automatically generated make config: don't edit\n"
             "#
Linux kernel version: %s\n"
             "#
%s"
             "#\n",
             sym_get_string_value(sym),
ctime(&now));
    fprintf(tristate,
"#\n"
              "#
Automatically generated - do not edit\n"
              "\n");
    fprintf(out_h,
"\n"
               "#define
AUTOCONF_INCLUDED\n"
,
               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))
        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();
    
    if
(rename(".tmpconfig",
name))
        return
1;

上面代码中的 conf_get_autoconfig_name() 实现为:

1
2
3
4
5
6
const char *conf_get_autoconfig_name(void)
{
    char
*name = getenv("KCONFIG_AUTOCONFIG");
 
    return
name ? 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【转】的更多相关文章

  1. linux内核Makefile整体分析

    转自:http://www.cnblogs.com/amanlikethis/p/3675486.html <请阅读原文> 一.概述 1.本文的意义 众多的资料(<嵌入式Linux应 ...

  2. Linux内核源代码分析方法

    Linux内核源代码分析方法   一.内核源代码之我见 Linux内核代码的庞大令不少人"望而生畏",也正由于如此,使得人们对Linux的了解仅处于泛泛的层次.假设想透析Linux ...

  3. 2019-2020-1 20199303 《Linux内核原理分析》 第一周作业

    2019-2020-1 20199303 <Linux内核原理分析> 第一周作业 1. 环境准备 在众多的Linux发行版中,Ubuntu,小红帽还有类Unix系统的BSD系统,我选择了目 ...

  4. linux内核makefile概览

    linux内核makefile概览 本博客参照内核官方英文文档 linux的内核makefile主要用于编译整个内核源码,按照用户的需求生成各种目标文件,对于用户来说,编译内核时非常简单的,只需要几个 ...

  5. Linux内核Makefile文件(翻译自内核手册)

    --译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...

  6. Linux内核(3) - 分析内核源码如何入手(下)

    下面的分析,米卢教练说了,内容不重要,重要的是态度.就像韩局长对待日记的态度那样,严谨而细致. 只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB,比如进程管理,在花 ...

  7. Linux内核(2) - 分析内核源码如何入手(上)

    透过现象看本质,兽兽们无非就是一些人体艺术展示.同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的. 既然要学习内核源码,就要经常对内核代码进行分析, ...

  8. 《Linux内核与分析》第七周

    by 21035130王川东 Linux内核如何装载和启动一个可执行程序 一. EIF文件格式: 1.ELF头部在文件的开始,描述文件的总体格式,保存了路线图,描述该文件的组织情况,即生成该文件系统的 ...

  9. Linux内核启动分析过程-《Linux内核分析》week3作业

    环境搭建 环境的搭建参考课件,主要就是编译内核源码和生成镜像 start_kernel 从start_kernel开始,才真正进入了Linux内核的启动过程.我们可以把start_kernel看做平时 ...

随机推荐

  1. 【函数应用】PHP中关于URL的函数处理

    一,函数介绍 1.解析HTTP头信息:get_header() array get_headers ( string 目标URL [, int $format = 0 [如果将可选的 format 参 ...

  2. java util - Hex转换工具

    测试代码 package cn.java.codec.hex; public class Test { public static void main(String[] args) { String ...

  3. SSM(Spring+Spring MVC+Mybatis)开发前台后功能完整的java开源博客管理系统

    项目描述 本项目通过SSM(SpringMVC+Mybatis+Spring)框架编写的一个人博客管理系统,使用hexo主题,以及MAVEN进行对项目管理,并且前端具有粒子和点击爱心效果.后端的页面框 ...

  4. 初学js之qq聊天实例

    实现的功能为上图所示,但是每新发送的消息必须显示在最上面. 我实现了两版,样式有是一样的.我们直接看代码. 版本一: <!DOCTYPE html> <html lang=" ...

  5. Linux命令之---mv

    命令简介 mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files) 命令格式 mv [选项] 源文件或目录 目标文件或目录 命令参数 -b 若需覆盖文件,则覆 ...

  6. [原]sencha touch之表单(login demo)

    现在来说说sencha touch中的表单,举个简单的login的例子,相关的说明我都放在了注释中,看下面代码 Ext.application({ id:'itKingApp', launch:fun ...

  7. Java集合---List、Set、Iterator、Map简介

    1.List集合 1.1概念 List继承自Collection接口.List是一种有序集合,List中的元素可以根据索引(顺序号:元素在集合中处于的位置信息)进行取得/删除/插入操作. 跟Set集合 ...

  8. day 16 JS DOM 继续

    为什么有jquey了还学DOM  ? 因为JQuey 是大而全,可能有10k 但是我们用到的只有1k  网站小没事,网站大流量就是问题 所以大网站都是自己用DOM 实现一个类似于JQuey 的适合自己 ...

  9. Hotspot GC实现原理

    GC扫描 可达性分析的GC Roots主要是全局性引用或在Stack Frame中 ,现在的应用仅仅方法区往往就有几百兆,这样要这个检查这里面的引用,就必然会消耗很多时间,效率很低. 分析工作在一个保 ...

  10. Python 模块搜索路径

    Python 会在什么地方寻找文件来导入模块? 使用命名为 path 变量的存储在标准 sys 模块 下的一系列目录名和 ZIP 压缩文件. 你可以读取和修改这个列表.下面是在我的 Mac 上 Pyt ...