uboot-Makefile学习(4)

学习目标:

uboot顶层Makefile分析。

学习内容:

学习使用了正点原子的I.MX6ULL教程及开发平台。
uboot的make mx6ull_14x14_ddr512_emmc_defconfig配置过程

学习时间:

2022-06-05

学习产出:

1、make xxx_defconfig的过程
在顶层Makefile下有如下代码,

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
$(info #########################1#############################)
$(info no-dot-config-targets=$(no-dot-config-targets))
$(info MAKECMDGOALS=$(MAKECMDGOALS))

config-targets := 0
mixed-targets  := 0
dot-config     := 1

ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
	ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
		dot-config := 0
	endif
endif
$(info dot-config=$(dot-config))
$(info KBUILD_EXTMOD=$(KBUILD_EXTMOD))

ifeq ($(KBUILD_EXTMOD),)
        ifneq ($(filter config %config,$(MAKECMDGOALS)),)
                config-targets := 1
                ifneq ($(words $(MAKECMDGOALS)),1)
                        mixed-targets := 1
                endif
        endif
endif
$(info config-targets=$(config-targets))
$(info mixed-targets=$(mixed-targets))

ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.

PHONY += $(MAKECMDGOALS) __build_one_by_one

$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
	@:

__build_one_by_one:
	$(Q)set -e; \
	for i in $(MAKECMDGOALS); do \
		$(MAKE) -f $(srctree)/Makefile $$i; \
	done

else
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target

KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG

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

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

else
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.

ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf

# 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
	@# If the following part fails, include/config/auto.conf should be
	@# deleted so "make silentoldconfig" will be re-run on the next build.
	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
		{ rm -f include/config/auto.conf; false; }
	@# include/config.h has been updated after "make silentoldconfig".
	@# We need to touch include/config/auto.conf so it gets newer
	@# than include/config.h.
	@# Otherwise, 'make silentoldconfig' would be invoked twice.
	$(Q)touch include/config/auto.conf

-include include/autoconf.mk
-include include/autoconf.mk.dep

# We want to include arch/$(ARCH)/config.mk only when include/config/auto.conf
# is up-to-date. When we switch to a different board configuration, old CONFIG
# macros are still remaining in include/config/auto.conf. Without the following
# gimmick, wrong config.mk would be included leading nasty warnings/errors.
ifneq ($(wildcard $(KCONFIG_CONFIG)),)
ifneq ($(wildcard include/config/auto.conf),)
autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \
						include/config/auto.conf)
$(info autoconf_is_old=$(autoconf_is_old))						
ifeq ($(autoconf_is_old),)
$(info ##########################################2################################################)
include config.mk
include arch/$(ARCH)/Makefile
endif
endif
endif

首先定义了两个变量,

version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h

version_h 变量是保存uboot的版本号文件,此文件在make时才能自动生成。
timestamp_h 变量是保存ubot的时间戳文件,此文件在make时才能自动生成。
接下来定义了变量no-dot-config-targets := clean clobber mrproper distclean
help %docs check% coccicheck ubootversion backup
定义变量config-targets初值为0;
定义变量mixed-targets初值为0;
定义变量dot-config初值为1。
然后判断MAKECMDGOALS中是否有符合no-dot-config-targets的,此时的MAKECMDFLASG的值为mx6ull_14x14_ddr512_emmc_defconfig,不满足条件判断,dot-config的值仍然为1。
之后判断KBUILD_EXTMOD是否为空,从前面章节的分析中可知,KBUILD_EXTMOD是关于模块编译的,未用模块编译,其值为空,满足判断条件,后面再判断,MAKECMDGOALS中是否有符合config和%config的部分,很明显条件成立,此时config-targets的值变为1,然后继续判断MAKECMDGOALS变量中的单词数是否为1,此处单词数为1,判断条件不成立。mixed-targets的值仍为0。
下面根据config-targets、mixed-targets、dot-config的值进入ifeq…else ifeq判断,这里进入else ifeq ($(config-targets),1)之中。
首先给变量KBUILD_DEFCONFIG赋值为sandbox_defconfig,然后导出变量,KBUILD_DEFCONFIG值为sandbox_defconfig,KBUILD_KCONFIG值为空。
因为我们make的目标为mx6ull_14x14_ddr512_emmc_defconfig,所以不会执行下面的语句:

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

直接匹配进入下面的语句执行,后面的else ifeq将不再执行。

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

可以看出匹配的目标中有三个依赖分别为scripts_basic 、outputmakefile 和FORCE,一条规则为$(Q)$(MAKE) $(build)=scripts/kconfig $@
1.1 FORCE
在顶层Makefile中有如下代码:

PHONY += FORCE
FORCE:

可以看出FORCE是没有依赖和规则的,所以每此都会执行FORCE。当FORCE作为其他目标的依赖时,由于FORCE总是被更新的,因此依赖所在的规则总是会执行的。
1.2 outputmakefile
在顶层Makefile中规则outputmakefile作为目标有如下代码:

PHONY += outputmakefile
outputmakefile:
ifneq ($(KBUILD_SRC),)
	$(Q)ln -fsn $(srctree) source
	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
	    $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

outputakefile作为目标时没有依赖,因此也总是会被更新的,首先判断变量KBUILD_SRC是否为空,没有设置KBUILD_SRC的值,因此KBUILD_SRC的值空,所以判断条件不成立,依赖outputmakefile直接结束。
1.3 scripts_basic
在顶层makefile下有如下代码,

PHONY += scripts_basic
scripts_basic:
	$(Q)$(MAKE) $(build)=scripts/basic
	$(Q)rm -f .tmp_quiet_recordmcount

scripts_basic作为目标时,也没有依赖,一次总是被更新的。其中包含两条规则。从前面章节的分析可知,$(Q)为空。$(MAKE)就是make。而build在文件
scripts/Kbuild.include中有定义,顶层Makefile中也包含了此文件include scripts/Kbuild.include。而在scripts/Kbuild.include文件中对build有如下定义:

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

而srctree为顶层Makefile导出的变量值为.,所以,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文件,且传入的参数值为obj=scripts/basic。
进入./scripts/Makefile.build文件中,首先有如下代码:

# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif

首先,定义了变量prefix 的值为tpl,然后定义变量src,这里用到了函数patsubst。此函数的格式如下:

$(patsubst <pattern>,<replacement>,<text>)

此函数用于在text中查找符合patttern的部分,如果匹配的话就用replacement替换掉。pattern是可以包含通配符"%“,如果在replacement中也包含通配符”%“,那么replacement中的这个”%“,将是pattern中的那个”%"所代表的字符串。函数的返回值就是替换后的字符串。因此,$(patsubst $(prefix)/%,%,$(obj))的意思就是在scripts/basic中查找符合tpl/%的部分然后替换掉,但是scripts/basic中没有tpl/%,所以src=scripts/basic。
接下来判断obj的值和src的值是否相等,很明显此处条件成立,继续执行。prefix的值变为了spl。继续执行src := $(patsubst $(prefix)/%,%,$(obj)),src的值仍为src=scripts/basic。
再继续obj和src的值相等,所以,prefix=.。
继续向下有如下代码:

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

将kbuild-dir展开后的结果为:

$(if $(filter /%,scripts/basic),scripts/basic,./scripts/basic)

因为没有以/%开头的单词,所以$(filter /%,scripts/basic)的值为空,kbuild-dir的值为./scripts/basic,kbuild-dir:=./scripts/basic
将kbuild-file展开后为:

$(if $(wildcard ./scripts/basic/Kbuild),./scripts/basic/Kbuild,./scripts/basic/Makefile)

因为./scripts/basic/下没有Kbuild这个文件,所以kbuild-file的值为./scripts/basic/Makefile,kbuild-file:=./scripts/basic/Makefile
下面的include $(kbuild-file),变为了include ./scripts/basic/Makefile,也就是读取./scripts/basic下面的Makefile文件。
继续向下会有如下代码:

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
	 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
	 $(subdir-ym) $(always)
	@:

因为在顶层Makefile执行make -f ./scripts/Makefile.build obj=scripts/basic时,没有指明目标,所以会使用__build作为默认目标,在顶层Makefile导出的变量中,KBUILD_BUILTIN的值为1,KBUILD_MODULES为空。因此将目标展开后为:

__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:

可以看出有五个依赖,$(builtin-target),$(lib-target),$(extra-y)),$(subdir-ym),$(always),将这五个依赖的值直接打印出来,如图所示:

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
	 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
	 $(subdir-ym) $(always)
	@:
	@echo builtin-target=$(builtin-target)
	@echo lib-target=$(lib-target)
	@echo extra-y=$(extra-y)
	@echo subdir-ym=$(subdir-ym)
	@echo always=$(always)

其结果如图所示:
在这里插入图片描述
可以看出只有always有值。
由此可见,__build最终变为:

__build: scripts/basic/fixdep
	@:

__build的最终依赖为scripts/basic/fixdep。因此就会编译scripts/basic/fixdep.c这个文件,最终生成scripts/basic/fixdep这个软件,用于再构建过程中生成依赖项信息。
1.4、%config的规则
回到顶层Makefile中,%config的三个依赖已经分析完了,下面看规则,内容如下。

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

将规则展开就为:

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

同样进入./scripts/Makefile.build文件中,此时:

src= scripts/kconfig
kbuild-dir = ./scripts/kconfig
kbuild-file = ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile

可以看出,Makefile.build会读取./scripts/kconfig/Makefile中的内容,此Makefile中有如下代码:

%_defconfig: $(obj)/conf
	$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

目标%_defconfig刚好和我们输入的mx6ull_14x14_ddr512_emmc_defconfig相匹配,所以会执行这条规则。其依赖为$(obj)/conf,展开后就是scripts/kconfig/conf。下面就是检查并生成依赖 scripts/kconfig/conf。conf 是主机软件这里先到此为止,conf工具从根目录开始树状读取默认的Kconfig文件,分析其配置保存在内存里,分析完默认的Kconfig文件后再读取指定的xxx_defconfig文件,更新得到最终的符号表,并输出到.config文件中。
得到 scripts/kconfig/conf 以后就要执行目标%_defconfig 的命令:

$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

相关变量的值如下:
silent=
SRCARCH=…
Kconfig=Kconfig
将其展开就是:

scripts/kconfig/conf --defconfig=arch/../configs/mx6ull_14x14_ddr512_emmc_defconfig Kconfig

这里会将mx6ull_alientek_emmc_defconfig 中的配置输出到.config 文件中,最终生成 uboot 根目录下的.config 文件。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值