目录
make xxx_defconfig 过程
Makefile.build 脚本分析
scripts_basic 目标对应的命令
%config 目标对应的命令
make xxx_defconfig 过程
在编译uboot之前要使用"make xxx_defconfig"命令来配置uboot,那么这个配置过程是如何运行的呢?在顶层Makefile中有如下代码:
第422行定义了变量version_h,这变量保存版本号文件,此文件是自动生成的。文件include/generated/version_autogenerated.h内容如图所示:
第423行定义了变量timestamp_h,此变量保存时间戳文件,此文件也是自动生成的。文件include/generated/timestamp autogenerated.h内容如图所示:
第425行定义了变量no-dot-config-targets。
第429行定义了变量config-targets,初始值为0。
第430行定义了变量mixed-targets,初始值为0。
第431行定义了变量dot-config,初始值为1。
第433行将MAKECMDGOALS中不符合no-dot-config-targets的部分过滤掉,剩下的如果不为空的话条件就成立。MAKECMDGOALS是make的一个环境变量,这个变量会保存你所指定的终极目标列表,比如执行"make mx6ull_alientek_emme_defconfig",那么MAKECMDGOALS就为 mx6ull_alientek_emme_defconfig。很明显过滤后为空,所以条件不成立,变量 dot-config依旧为1。
第439行判断KBUILD_EXTMOD是否为空,如果KBUILD_EXTMOD为空的话条件成立,经过前面的分析,我们知道KBUILD_EXTMOD为空,所以条件成立。
第440行将MAKECMDGOALS中不符合"config"和“%config"的部分过滤掉,如果剩下的部分不为空条件就成立,很明显此处条件成立,变量config-targets=1。
第442行统计MAKECMDGOALS中的单词个数,如果不为1的话条件成立。此处调用Makefile 中的words函数来统计单词个数,words 函数格式如下:
$(words <text>)
很明显, MAKECMDGOALS的单词个数是1个,所以条件不成立, mixed-targets继续为0。综上所述,这些变量值如下:
config-targets = 1
mixed-targets = 0
dot-config=1
第448行如果变量mixed-targets为1的话条件成立,很明显,条件不成立。
第473行,没有目标与之匹配,所以不执行。
第465行如果变量config-targets为1的话条件成立,很明显,条件成立,执行这个分支。
第473行,没有目标与之匹配,所以不执行。
第476行,有目标与之匹配,当输入"make xxx_defconfig"的时候就会匹配到%config目标,目标“%config”依赖于scripts_basic、outputmakefile和FORCE。FORCE在顶层Makefile的1610 行有如下定义:
可以看出FORCE是没有规则和依赖的,所以每次都会重新生成FORCE。当FORCE作为其他目标的依赖时,由于FORCE总是被更新过的,因此依赖所在的规则总是会执行的。
依赖scripts_basic和outputmakefile在顶层Makefile中的内容如下:
第408行,判断KBUILD_SRC是否为空,只有变量KBUILD_SRC不为空的时候outputmakefile才有意义,经过我们前面的分析KBUILD_SRC为空,所以outputmakefile无效。只有 scripts_basic是有效的。
第396-398行是scripts_basic的规则,其对应的命令用到了变量Q、MAKE和build,其中:
Q=@或为空
MAKF=make
变量build是在scripts/Kbuild.include文件中有定义,定义如下:
从示例代码可以看出build--f$(srctree)/scripts/Makefile.build obj,经过前面的分析可知,变量srctree为”.”,因此:
build=-f./scripts/Makefile.build obj
scripts_basic展开以后如下:
scripts_basic:
@make-f./scripts/Makefile.build obj=scripts/basic //也可以没有@,视配置而定
@rm-f.tmp quiet recordmcount //也可以没有@
Scripts_basic会调用文件./scripts/Makefile.build,这个我们后面在分析。
接着回到示例代码顶层Makefile中的%config处,内容如下:
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) S(build)=scripts/kconfig $@
将命令展开就是:
@make-f./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
同样也跟文件./scripts/Makefile.build有关,使用如下命令配置uboot,并观察其配置过程:
从图可以看出,我们的分析是正确的,接下来就要结合下面两行命令重点分析一下文件scripts/Makefile.build。
1.scripts_basic 目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/basic
2.%config 目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
Makefile.build 脚本分析
从上可知,"make xxx_defconfig"配置 uboot 的时候如下两行命令会执行脚本
scripts/Makefile.build:
@make -f ./scripts/Makefile.build obj=scripts/basic
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
scripts_basic 目标对应的命令
scripts_basic 目标对应的命令为:@make -f ./scripts/Makefile.build obj=scripts/basic。打开文
件scripts/Makefile.build,有如下代码:
第 9 行定义了变量 prefix 值为 tpl。
第 10 行定义了变量 src,这里用到了函数 patsubst,此行代码展开后为:
$(patsubst tpl/%,%, scripts/basic)
patsubst 是替换函数,格式如下:
$(patsubst <pattern>,<replacement>,<text>)
此函数用于在 text 中查找符合 pattern 的部分,如果匹配的话就用 replacement 替换掉。
pattenr 是可以包含通配符“%”,如果 replacement 中也包含通配符“%”,那么 replacement 中的
这个“%”将是 pattern 中的那个“%”所代表的字符串。函数的返回值为替换后的字符串。因
此,第 10 行就是在“scripts/basic”中查找符合“tpl/%”的部分,然后将“tpl/”取消掉,但是
“scripts/basic”没有“tpl/”,所以 src= scripts/basic。
第11行判断变量obj和src是否相等,相等的话条件成立,很明显,此处条件成立。
第12行和第9行一样,只是这里处理的是“spl”,“scripts/basic”里面也没有“spl/”,所以
src继续为scripts/basic。
第15行因为变量obj和src相等,所以prefix=.。
继续分析scripts/Makefile.build,有如下代码:
将 kbuild-dir 展开后为:
$(if $(filter /%, scripts/basic), scripts/basic, ./scripts/basic),
因为没有以“/”为开头的单词,所以$(filter /%, scripts/basic)的结果为空,kbuild dir=./scripts/basic。
将 kbuild-file 展开后为:
$(if $(wildcard ./scripts/basic/Kbuild), ./scripts/basic/Kbuild, ./scripts/basic/Makefile)
因为 scrpts/basic目录中没有 Kbuild 这个文件,所以 kbuild-file= ./scripts/basic/Makefile。最 后将 59 行展开,即:
include ./scripts/basic/Makefile
也就是读取 scripts/basic 下面的 Makefile 文件。
继续分析 scripts/Makefile.build,如下代码:
__build 是默认目标,因为命令“@make -f ./scripts/Makefile.build obj=scripts/basic”没有指
定目标,所以会使用到默认目标:__build。在顶层 Makefile 中,KBUILD_BUILTIN 为 1,
KBUILD_MODULES 为 0,因此展开后目标__build 为:
__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always) @:
可以看出目标__build 有5个依赖:builtin-target、lib-target、extra-y、subdir-ym 和 always。
这5个依赖的具体内容我们就不通过源码来分析了,直接在 scripts/Makefile.build 中输入图所示内容,将这5个变量的值打印出来:
执行如下命令:
make mx6ull_14x14_ddr512_emmc_defconfig V=1
从上图可以看出,只有 always 有效,因此__build 最终为:
__build: scripts/basic/fixdep @:
__build 依赖于 scripts/basic/fixdep,所以要先编译 scripts/basic/fixdep.c,生成 fixdep,前面
已经读取了scripts/basic/Makefile 文件。
综上所述,scripts_basic目标的作用就是编译出scripts/basic/fixdep 这个软件。
%config 目标对应的命令
%config 目标对应的命令为: @make -f ./scripts/Makefile.build obj=scripts/kconfig
xxx_defconfig,各个变量值如下:
src= scripts/kconfig
kbuild-dir = ./scripts/kconfig
kbuild-file = ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile
可以看出,Makefilke.build 会读取 scripts/kconfig/Makefile 中的内容,此文件有如下所示内容:
目标%_defconfig 刚好和我们输入的 xxx_defconfig 匹配,所以会执行这条规则。依赖为
$(obj)/conf,展开后就是 scripts/kconfig/conf。接下来就是检查并生成依赖 scripts/kconfig/conf。
conf 是主机软件,到这里我们就打住,不要纠结 conf 是怎么编译出来的,否则就越陷越深,太
绕了,像 conf 这种主机所使用的工具类软件我们一般不关心它是如何编译产生的。如果一定要
看是 conf 是怎么生成的,可以输入如下命令重新配置 uboot,在重新配置 uboot 的过程中就会
输出 conf 编译信息。
make distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_
defconfig V=1
得到 scripts/kconfig/conf 以后就要执行目标%_defconfig 的命令:
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
相关的变量值如下:
silent=-s 或为空
SRCARCH=..
Kconfig=Kconfig
将其展开就是:
@ scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
上述命令用到了 xxx_defconfig 文件,比如 mx6ull_alientek_emmc_defconfig。这里会将
mx6ull_alientek_emmc_defconfig 中的配置输出到.config 文件中,最终生成 uboot 根目录下
的.config 文件。
这个就是命令make xxx_defconfig 执行流程,总结一下如图所示: