make xxx_defconfig

配置介绍

1.1 常用命令  

  当前 uboot 的配置已经完全变成Linux 内核的配置形式了,完全可以按照Linux 内核的分析方是区分析 uboot。

  uboot 和 Linux的代码配置项由 Kconfig 来完成的,关于 Kconfig 语法,可参见:linux/Documentation/kbuild/kconfig-language.txt

  在编译时,先进行配置,目的是根据需求选择功能以及编译生成方式类型(模式或包含在内核中).

  配置项操作可以由如下命令中的其中一条来完成:

   make config, make menuconfig, make oldconfig, make xx_defconfig

  • make config:这个要求用户手动选择所有配置项,配置完成后生成 .config 文件。
  • make menuconfig:显示以curses的图形配置菜单,当已有.config文件存在时,它会根据 .config 文件设定默认项。若不存在 .config 文件,则根据各级 Kconfig 文件来设定菜单项。完成配置后,生成.config文件。
  • make oldconfig:与 make menuconfig 相同,区别在于这个没有图形界面,当已有 .config 文件存在时,它根据.config文件设定默认项,若kconfig有新配置项时,会提示你进行选择;若不存在 .config 文件,则根据各级 Kconfig 文件来设定菜单项。完成配置后,生成 .config 文件。

  若已存在 .config 文件,make menuconfig 及 make oldconfig 都会把原 .config 另存为 .config.old。

  • make xx_defconfig: 一般源码中都有不同硬件平台的默认配置文件,你也可以制做自己的默认配置文件,当这个命令执行时,它会根据 kconfig 及 xx_defconfig 来生成 .config 文件。

  在执行完其中一条 config 命令后,会生成 .config 及 autoconf 文件,autoconf 是根据配置项生成的相应宏定义,供 makefile 使用,当执行 make 命令时,就会根据 autoconf 定义的宏及 makefile 去编译源码。

  u-boot的编译跟kernel编译一样,分两步执行: 
  - 第一步:配置,执行make xxx_defconfig进行各项配置,生成.config文件 
  - 第二部:编译,执行make进行编译,生成可执行的二进制文件u-boot.bin或u-boot.elf

1.2 Linux 内核构建系统所支持的目标

  make targets,targets 就是我们前述的那些命令,我们可以通过 make help 打印出来内核构建系统所支持的目标完整列表。

  如下所示,是 make help 所打印的所有目标:

  

  • clean 目标
    • clean:清除大多数生成的文件,但是保留配置
    • mrproper:清除所有生成的文件、配置文件和各种备份文件
    • distclean:此项就是 mrproper 的升级版本,多加了清除备份和补丁文件  

  make xxx_defconfig_第1张图片

  • 配置项目标:
    • config:利用命令行更新当前配置
    • nconfig:使用基于ncurses菜单的程序更新当前配置
    • menuconfig:利用菜单程序更新当前配置
    • xconfig:利用基于Qt的前端更新当前配置
    • gconfig:利用基于GTK +的前端更新当前配置
    • oldconfig:使用提供的.config作为基础更新当前配置
    • localmodconfig:更新当前配置禁用未加载的模块
    • localyesconfig:更新当前配置将本地mods转换为core
    • silentoldconfig:与oldconfig相同,但是安静地更新deps
    • defconfig:来自ARCH的默认配置提供了defconfig
    • savedefconfig:保存当前配置为./defconfig(最小配置)
    • allnoconfig:新的配置,所有选项的答案都是no
    • allyesconfig:新的配置,所有选项的答案都是yes
    • allmodconfig:新的配置,尽可能的选择模块
    • alldefconfig:将所有符号设置为默认值的新配置
    • randconfig:对所有选项进行随机答案的新配置
    • listnewconfig:列出新选项
    • olddefconfig:与 silentoldconfig 相同,但是对默认值设置新的符号  

  make xxx_defconfig_第2张图片

  • 其他通用目标
    • all:根据配置构建所有必要的镜像
    • tests:为 sandbox 构建 U-Boot,并测试
    • * u-boot:构建空的 uboot
    • dir/ :在dir和子目录下构建所有文件
    • dir/file.[oisS] :仅构建指定的目标
    • dir/file.lst :仅构建指定的混合源/汇编目标(需要最新的binutils和最新的版本(System.map))
    • tags/ctags:生成 ctags 索引文件
    • etags:生成 etags 索引文件
    • cscope:生成 cscope 索引
    • ubootrelease:输出发行版本字符串(需要用 make -s)
    • ubootversion:输出保存在 Makefile 中的版本(需要用 make -s)
    • cfg:不构建,仅仅只创建 .cfg 文件
    • envtools:只构建目标端环境工具  

  

  • 静态分析:
    • checkstack:生成堆栈列表
    • coccicheck:用Coccinelle执行静态代码分析  

  make xxx_defconfig_第3张图片

  文件目标 就是 uboot 中所有格式的文件,之后就是构建时候 可以传入的参数。

  最后还由一段话,就是 执行 make  或  make all  的时候,构建所有以 * 开头的目标,这里只有  * u-boot ,即使执行此项。

  构建系同与 .config 相关的目标,就是上面用配置目标  

1.3 构建系统的文件

1.3.1 文件介绍

  在 ./Document/kbuild/makefiles.txt 中有详细介绍

  • Makefiles 有 5 个部分:
    • Makefile:顶层 Makefile,提供针对各种目标的接口,一般和实现无关。当我们要针对某个目标进行分析时,作为起点,总是尝试在此文件中找到对应的目标定义,然后沿着该定义深入挖掘。
    • .config:uboot 配置文件,如果是内核,就是内核的配置文件,在配置 uboot时候生成,所有的 Makefile 文件(包括顶层目录及各级子目录)都是根据 .config 来决定使用哪些文件。
    • arch/$(ARCH)/Makefile:平台相关 Makefile,提供针对不同架构的目标,变量和规则定义。文件位置比较固定
    • scripts/Makefile.*:Makefile 共用的通用规则、脚本等
    • kbuild Makefiles:各级子目录下的  Makefile,相对简单,被上一层 Makefile 调用来编译当前目录下的文件。

  顶层 Makefiles 读取从uboot 配置程序中生成的 .config 文件  

1.3.2 文件关联

  在上述的所有文件中,除了顶层的  Makefile,其他文件都或直接、或间接的和 它相关联。这些关联可以分为两类:

(1)直接包含

  在一个文件中,用  include 来包含另外的文件

(2)间接包含

  使用 make -f 来调用,-f 是使用不同的  makefile 文件来进行 make 的选项。

1.4 make xxx_defconfig 命令执行分析

  由于 2018.03 的 uboot 版本中已经遗弃了 2440 所以我们选择一块其他开发板进行分析。

  执行命令:make smdkc100_defconfig V=1

  V = 1 的意思是打开编译过程

  过程如下:

复制代码

 1 make -f ./scripts/Makefile.build obj=scripts/basic
 2   cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer      -o scripts/basic/fixdep scripts/basic/fixdep.c  
 3 rm -f .tmp_quiet_recordmcount
 4 make -f ./scripts/Makefile.build obj=scripts/kconfig smdkc100_defconfig
 5   cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_GNU_SOURCE -DCURSES_LOC="" -DLOCALE   -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c
 6   cat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.c
 7   cat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.c
 8   cat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.c
 9   cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_GNU_SOURCE -DCURSES_LOC="" -DLOCALE  -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c
10   cc  -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o  
11 scripts/kconfig/conf  --defconfig=arch/../configs/smdkc100_defconfig Kconfig
12 #
13 # configuration written to .config
14 #

复制代码

  

  这一项是生成了 scripts/basic/fixdep 工具

  make xxx_defconfig_第4张图片

  这一项是生成了 scripts/kconfig/conf 工具

  

  最后执行 scripts/kconfig/conf 工具 生成.config

   可以知道 make xxx_defconfig 的执行主要分成三个部分:

  1. 执行 make -f ./scripts/Makefile.build obj=scripts/basic,编译生成 scripts/basic/fixdep 工具
  2. 执行 make -f ./scripts/Makefile.build obj=scripts/kconfig rpi_3_32b_defconfig 编译生成 scripts/kconfig/conf 工具
  3. 执行 scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig生成最终的 .config 配置文件 

     

二、编译第一步 make xxx_defconfig

2.1 顶层make defconfig规则

  make xxx_defconfig 的执行主要分成三个部分:

  1. 执行 make -f ./scripts/Makefile.build obj=scripts/basic,编译生成 scripts/basic/fixdep 工具
  2. 执行 make -f ./scripts/Makefile.build obj=scripts/kconfig rpi_3_32b_defconfig 编译生成 scripts/kconfig/conf 工具
  3. 执行 scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig生成最终的 .config 配置文件 

  执行 make xxx_defconfig 命令时,u-boot 根目录下的 Makefile 中有唯一的规则匹配目标:

  代码第 467 到 478 行

复制代码

 1 # ===========================================================================
 2 # *config targets only - make sure prerequisites are updated, and descend
 3 # in scripts/kconfig to make the *config target
 4 
 5 KBUILD_DEFCONFIG := sandbox_defconfig
 6 export KBUILD_DEFCONFIG KBUILD_KCONFIG
 7 
 8 config: scripts_basic outputmakefile FORCE
 9     $(Q)$(MAKE) $(build)=scripts/kconfig $@
10 
11 %config: scripts_basic outputmakefile FORCE
12     $(Q)$(MAKE) $(build)=scripts/kconfig $@

复制代码

  注释意思为,仅限 *config 目标,确保先决条件已经更新,并在 scripts/kconfig 下创建 *config 目标。上面有两个变量 config 和 %config,% 符号为通配符,对应所有的 xxxconfig 目标,前面已经说过。我们的 make xxx_defconfig 就对应 %config,我们并没有执行 make config 命令。

  Makefile中几种变量赋值运算符:

  • =      :最简单的赋值 
  • :=     :一般也是赋值 
    • 以上这两个大部分情况下效果是一样的,但是有时候不一样。
    • 用 = 赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以看变量引用的值时不能只往前面看,还要往后面看。
    • 用 := 来赋值的,则是就地直接解析,只用往前看即可。  
  • ?=     : 如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行被忽略。
  • +=   用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面,有点类似于strcat     
    • 在shell makefile等文件中,可以认为所有变量都是字符串,+= 就相当于给字符串 strcat 接续内容
    • +=续接的内容和原来的内容之间会自动加一个空格隔开

2.1.1 代码执行到%config 的条件  

  先往上分析下这段代码的执行条件: ifeq ($(config-targets),1),代码在415 到 447 行

复制代码

 1 # To make sure we do not include .config for any of the *config targets
 2 # catch them early, and hand them over to scripts/kconfig/Makefile
 3 # It is allowed to specify more targets when calling make, including
 4 # mixing *config targets and build targets.
 5 # For example 'make oldconfig all'.
 6 # Detect when mixed targets is specified, and make a second invocation
 7 # of make so .config is not included in this case either (for *config).
 8 
 9 version_h := include/generated/version_autogenerated.h
10 timestamp_h := include/generated/timestamp_autogenerated.h
11 
12 no-dot-config-targets := clean clobber mrproper distclean \
13              help %docs check% coccicheck \
14              ubootversion backup tests
15 
16 config-targets := 0
17 mixed-targets  := 0
18 dot-config     := 1
19 
20 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
21     ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
22         dot-config := 0
23     endif
24 endif
25 
26 ifeq ($(KBUILD_EXTMOD),)
27         ifneq ($(filter config %config,$(MAKECMDGOALS)),)
28                 config-targets := 1
29                 ifneq ($(words $(MAKECMDGOALS)),1)
30                         mixed-targets := 1
31                 endif
32         endif
33 endif

复制代码

  代码注释内容:为了确保我们不包含任何 * config 目标的 .config,请尽早捕获它们,并将它们交给 scripts / kconfig / Makefile。调用make 时允许指定更多目标,包括混合 * config 目标和构建目标。例如 'make oldconfig all' 。检测何时指定了混合目标,并进行make的第二次调用,因此 .config不包含在这种情况下(对于* config)。

  • version_h:版本号文件,此文件是自动生成的
  • timestamp_h:时间戳文件,此文件是自动生成的
  • no-dot-config-targets:指代的是那些和 .config 没有关系的目标
  • config-targets:配置目标,初始值设置为0
  • mixed-targets:混合目标,初始值设置为0
  • dot-config:初始值设置为1

  变量 MAKECMDGOALS:make 在执行时会设置一个特殊变量 -- "MAKECMDGOALS" ,该变量记录了命令行参数指定的终极目标列表,没有通过参数指定终极目标时此变量为空。该变量仅限于用在特殊场合(比如判断),在 Makefile 中最好不要对它进行重新定义。

  我们执行  make xxx_defconfig 的时候,MAKECMDGOALS 变量的值就为 xxx_defconfig。

  filter 函数 和 filter-out 函数:

复制代码

1 $(filter PATTERN…,TEXT)
2 函数名称:  过滤函数— filter。
3 函数功能:  过滤掉字串“ TEXT”中所有不符合模式“ PATTERN”的单词,保留所
4         有符合此模式的单词。可以使用多个模式。模式中一般需要包含模式字
5        符“ %”。存在多个模式时,模式表达式之间使用空格分割。
6 返回值:空格分割的“ TEXT”字串中所有符合模式“ PATTERN”的字串。
7 函数说明:“ filter”函数可以用来去除一个变量中的某些字符串

复制代码

1 $(filter-out PATTERN...,TEXT)
2 函数名称:  反过滤函数— filter-out
3 函数功能:  和“ filter”函数实现的功能相反。过滤掉字串“ TEXT”中所有符合模式“ PATTERN”的单词,保留所有不符合此模式的单词。
        可以有多个模式。存在多个模式时,模式表达式之间使用空格分割
4 返回值:  空格分割的“ TEXT”字串中所有不符合模式“ PATTERN”的字串。
5 函数说明:  “ filter-out”函数也可以用来去除一个变量中的某些字符串,(实现和“ filter”函数相反)

  代码执行的过程就为,如果 过滤掉 MAKECMDGOALS 不符合 no-dot-config-targets 后结果不为空,则执行分支语句。很显然过滤后为空,则不执行分支语句,dot-config 依然 值为1。

  接着执行下一条 ifeq 语句,对 KBUILD_EXTMOD 进行判定。KBUILD_EXTMODE 的赋值地方在代码 182 到 191 行处:

复制代码

 1 # Use make M=dir to specify directory of external module to build
 2 # Old syntax make ... SUBDIRS=$PWD is still supported
 3 # Setting the environment variable KBUILD_EXTMOD take precedence
 4 ifdef SUBDIRS
 5   KBUILD_EXTMOD ?= $(SUBDIRS)
 6 endif
 7 
 8 ifeq ("$(origin M)", "command line")
 9   KBUILD_EXTMOD := $(M)
10 endif

复制代码

  由注释可以知道,SUBDIRS 这个变量是通过执行 make 的时候传进来的,我们并没有执行此项,所以未定义SUBDIRS,第一个分支不会去走。第二个 if 语句为 ifeq 语句,这里使用 origin 函数。

  origin 函数不是操作变量(即它的参数),它只是获取此变量(参数)相关的信息,告诉我们这个变量的出处(定义方式)。

  那么 ifeq 语句可以理解为 如果make传入的命令行变量存在且是M,那么,变量KBUILD_EXTMOD变为变量M的值。

  第一阶段中我们并没有传入 M 值,则 KBUILD_EXTMOD 值为空

  继续回到此小节主代码处,当前执行 KBUILD_EXTMOD 的判定,此处满足 ifeq  条件,开始执行分支语句,分支语句同样是一个判断,首先过滤掉 MAKECMDGOALS 不符合 config 和 %config 模式的字符串,然后返回 xxx_defconfig ,xxx_defconfig 再与 空进行比较,if 语句为 ifneq ,很显然, filter  语句不为空,与空进行比较,满足 ifneq 执行语句。

  此处将 config-targets 重新赋值为 1;赋值完后,进行  ifneq  条件判断,再次涉及  makefile 的函数——words。

  make xxx_defconfig_第5张图片

  显然我们的传入的单词数据为1,与1相等,则不执行分支,即 mixed-targets 不进行重新赋值,依然为0。

  再代码进行到 ifeq ($(config-targets),1) 时候,先进行了 ifeq ($(mixed-targets),1)分支,如果 mixed-targets 则执行另一条分支,就不会再执行ifeq ($(config-targets),1) 了。我们这里执行的ifeq ($(mixed-targets),1) 的 else中的分支语句。

  到此处,ifeq ($(config-targets),1) 是否会执行已经分析完毕。

  当前我们已经知道的变量的值为:

  • MAKECMDGOALS = xxx_defconfig
  • KBUILD_EXTMOD =
  • version_h := include/generated/version_autogenerated.h
  • timestamp_h := include/generated/timestamp_autogenerated.h
  • no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
  • config-targets := 1
  • mixed-targets := 0
  • dot-config := 1

2.1.2 %config分析

  ifeq ($(config-targets),1) 中也由else分支,我们从上面的小节可以知道,else 分支不会去执行。所以很多代码可以忽略了

  make xxx_defconfig_第6张图片

  从这里可以知道,此处此处选择语句一直执行到 1655 行,466~480 行才是我们需要分析的。

  471 到 472 行

1 KBUILD_DEFCONFIG := sandbox_defconfig
2 export KBUILD_DEFCONFIG KBUILD_KCONFIG

  这里定义了两个环境变量:

  • KBUILD_DEFCONFIG = sandbox_defconfig  
  • KBUILD_KCONFIG 为空

  继续执行474 到 475 行

1 config: scripts_basic outputmakefile FORCE
2     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  此处目标没有匹配,不会去执行

  继续执行477 478 行

1 %config: scripts_basic outputmakefile FORCE
2     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  %config 依赖scripts_basic outputmakefile  FORCE

(1)依赖 FORCE

  FORCE 的定义在 1748 和 1749 行

1 PHONY += FORCE
2 FORCE:

  FORCE被定义为一个空目标。如果一个目标添加 FORCE 依赖,每次编译都会去先去执行 FORCE(实际上什么都不做),然后运行命令更新目标,这样就能确保目标每次都会被更新。

(2)依赖 scripts_basic

  392 - 402 行

复制代码

 1 # ===========================================================================
 2 # Rules shared between *config targets and build targets
 3 
 4 # Basic helpers built in scripts/
 5 PHONY += scripts_basic
 6 scripts_basic:
 7     $(Q)$(MAKE) $(build)=scripts/basic
 8     $(Q)rm -f .tmp_quiet_recordmcount
 9 
10 # To avoid any implicit rule to kick in, define an empty command.
11 scripts/basic/%: scripts_basic ;

复制代码

   Q = @,MAKE = make,build 变量的定义在 scripts/Kbuild.include 文件中

  主Makefile 在327-329 行包含 scripts/Kbuild.include 文件

1 # We need some generic definitions (do not try to remake the file).
2 scripts/Kbuild.include: ;
3 include scripts/Kbuild.include

  build 变量在 scripts/Kbuild.include 在177 - 181 行定义

1 ###
2 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
3 # Usage:
4 # $(Q)$(MAKE) $(build)=dir
5 build := -f $(srctree)/scripts/Makefile.build obj

  srctree 定义在主 Makefile 中202-212 行

复制代码

 1 ifeq ($(KBUILD_SRC),)
 2         # building in the source tree
 3         srctree := .
 4 else
 5         ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
 6                 # building in a subdirectory of the source tree
 7                 srctree := ..
 8         else
 9                 srctree := $(KBUILD_SRC)
10         endif
11 endif

复制代码

  KBUILD_SRC (构建的源码目录) 在执行 make 命令的时候并没有传入,设为空,则srctree 为当前 uboot 源码的根目录

  scripts/Kbuild.include 在177 - 181 行的展开为:build := -f ./scripts/Makefile.build obj

  主 Makefile 中 scripts_basic 的展开为:

1 scripts_basic:
2      make -f ./scripts/Makefile.build obj=scripts/basic  # 根据传入的 obj 参数显示的执行 ./scripts/Makefile.build 文件
3      rm -f .tmp_quiet_recordmcount

  ./scripts/Makefile.build 文件之后再分析。

(3)outputmakefile 依赖

  404 - 413 行

复制代码

 1 PHONY += outputmakefile
 2 # outputmakefile generates a Makefile in the output directory, if using a
 3 # separate output directory. This allows convenient use of make in the
 4 # output directory.
 5 outputmakefile:
 6 ifneq ($(KBUILD_SRC),)
 7     $(Q)ln -fsn $(srctree) source
 8     $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
 9         $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
10 endif

复制代码

  KBUILD_SRC 为空,所以ifneq 中的语句不会执行。 outputmakefile 为空

  重新回到 %config 处

1 %config: scripts_basic outputmakefile FORCE
2     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  依据前面的条件,展开表达式为:

1 make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

2.2 总结

2.2.1 变量

  • MAKECMDGOALS = xxx_defconfig
  • KBUILD_EXTMOD =
  • version_h := include/generated/version_autogenerated.h
  • timestamp_h := include/generated/timestamp_autogenerated.h
  • no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
  • config-targets := 1
  • mixed-targets := 0
  • dot-config := 1
  • KBUILD_SRC =
  • build := -f ./scripts/Makefile.build obj

2.2.2 环境变量

  • KBUILD_DEFCONFIG := sandbox_defconfig
  • KBUILD_KCONFIG =

2.2.3 需要进行分析的地方

(1)scripts_basic 目标执行的命令

  make -f ./scripts/Makefile.build obj=scripts/basic

(2)%config 目标执行的命令

  make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

三、编译第一步 make xxx_defconfig——Makefile.build 脚本

3.1 上章分析回顾

3.1 上章分析出的参数

3.1.1 变量

  • MAKECMDGOALS = xxx_defconfig
  • KBUILD_EXTMOD =
  • version_h := include/generated/version_autogenerated.h
  • timestamp_h := include/generated/timestamp_autogenerated.h
  • no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
  • config-targets := 1
  • mixed-targets := 0
  • dot-config := 1
  • KBUILD_SRC =
  • build := -f ./scripts/Makefile.build obj

3.1.2 环境变量

  • KBUILD_DEFCONFIG := sandbox_defconfig
  • KBUILD_KCONFIG =

3.1.3 需要进行分析的地方

(1)scripts_basic 目标执行的命令

  make -f ./scripts/Makefile.build obj=scripts/basic

(2)%config 目标执行的命令

  make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

  由以上分析可以知道,执行 make xxx_defconfig 需要执行 Makefile.build 脚本,第一次传入的参数为 scripts/basic,第二次传入的参数为 scripts/kconfig xxx_defconfig

3.2 Makefile.build 脚本分析

3.2.1 make -f ./scripts/Makefile.build obj=scripts/basic

  make -f scripts/Makefile.build obj=scripts/basic 命令由于没有指定目标,所以会在 script/Makefile.build 中处理默认目标__build:

  114~119 行

1 # We keep a list of all modules in $(MODVERDIR)
2 
3 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
4      $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
5      $(subdir-ym) $(always)
6     @:

  同时,在scripts/Makefile.build 中会包含进 scripts/basic 目录下的 Kbuild/Makefile,所以该make命令的实际效果是去编译出 scripts/basic 目录下的三个 host program,也就是 fixdep docproc和hash。

  56 到 59 行 包含

1 # The filename Kbuild has precedence over Makefile
2 kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
3 kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
4 include $(kbuild-file)

  什么是host program?一般认为是和内核无关,但是要在编译过程中使用的工具程序。关于这些程序的编译,参考 scripts/Makefile.host 文件,以及 Documentation/kbuild/makefile.txt 文件中关于 host program 的这一节。

  scripts/basic 文件中的 Makefile

1 hostprogs-y    := fixdep
2 always        := $(hostprogs-y)
3 
4 # fixdep is needed to compile other host programs
5 $(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep

3.2.2 make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

  文件 scripts/Makefile.build 会包含obj变量所指代目录内的 Makefile的,在这里就是 script/kconfig/Makefile。

  所以这里得查看这个文件:120~125行

1 %_defconfig: $(obj)/conf
2     $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
3 
4 # Added for U-Boot (backward compatibility)
5 %_config: %_defconfig
6     @:

  在这里,xxx_defconfig 需要依赖于同目录下的conf程序。这其实就是 Linux 内核进行Kconfig操作的主程序之一了,类似的还有mconf,qconf和gconf等。他们其实都是 host program。关于它们是如何被编译出来的,还请参见 scripts/kconfig/Makefile 文件,主要是借助于bison,flex和gperf三个工具来生成c源程序文件,之后再编译出来的。这部分和我们Linux内核的构建主题关系不大.

  看一下 kconfig 的定义,变量的赋值在 scripts\kconfig'Makefile 中

1 ifdef KBUILD_KCONFIG
2 Kconfig := $(KBUILD_KCONFIG)
3 else
4 Kconfig := Kconfig
5 endif

  由于变量 KBUILD_KCONFIG 在arm架构Makefile中没有被定义,所以 Kconfig 被定义成 arch/arm/kconfig,所以这个目标的规则就简化成:

1 /* silent 是确定是否执行静态编译 */
2 ifeq ($(quiet),silent_)
3 silent := -s
4 endif
5 
6 $(obj)/conf -s --defconfig=arch/arm/configs/xxx_defconfig arch/arm/Kconfig

  这个命令就是读取并解析以 arch/arm/Kconfig 为首的内核功能选项配置文件,并将文件 arch/arm/configs/s3c2410_defconfig 所设置的默认值分配给对应的所有选项,最终生成隐藏配置文件 .config。

  在 uboot 或内核开始真正编译之前,构建系统会以 .config 文件为蓝本生成 include/config/auto.conf 文件,这个文件的格式和 .config类似,这个文件会在顶层 以及 scripts/Makefile.build 文件中被直接包含进来,所以这些变量其实就成了 GNU Make 的变量。而uboot 或 内核各子目录中的 Kbuild/Makefile 就可以使用这些变量的定义,来决定是否将该目录下对应的代码功能直接编译到内核里面(这些变量取值为"y")、编译成模块(取值为"m")或者干脆不进行编译(取值为"空")。可以想见,如果选择不编译,那出来的Linux内核就不会有对应的功能。

   在 arch/arm/Kconfig 文件中,我们可以查看到添加一块开发板需要大致更改的地方:

  • arch/arm/cpu 目录
  • board/  目录

  在配置的时候,配置工具首先会解析架构平台目录下的 Kconfig,这就是所谓和平台相关的主Kconfig。主Kconfig文件会包含其他目录的Kcofnig文件,而其他目录的Kconfig又会包含其他各子目录的 Kconfig。如此形成一个树型结构。 

3.3 小结

  作为uboot 或 内核构建系统对 kconfig 的支持,到这步就算是结束了,其根本目标是产生 .config 隐藏文件,用以记录我们所需要的配置结果。但是在uboot或Linux内核里面,仅仅把配置结果保存在像 .config 这样一个文件中是不够的。在后面的配置中,依然会用到 

你可能感兴趣的:(linux,uboot)