JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic
make -f ./scripts/Makefile.build obj=scripts/basic
该语句的意思是指定make文件为./scripts/Makefile.build,传入obj=scripts/basic参数
由于make没有指定编译目标,故默认执行第一个目标:
>>>>>>>>>__build:
PHONY := __build
__build:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
该目标命令行没有可执行的内容,主要有4个依赖
1. $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y))
在上级Makefile中,KBUILD_BUILTIN的定义如下:
KBUILD_BUILTIN := 1
export KBUILD_MODULES KBUILD_BUILTIN
所以该语句展开为:
$(builtin-target) $(lib-target) $(extra-y)
1.1 builtin-target 定义:
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
strip函数的功能参考Makefile手册:
在此语句之前obj-y := obj-m := obj-未定义 subdir-m := 并且在所包含的文件中也没有给这些变量增加值。
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a
endif
所以lib-target也为空,extra-y未定义,这些变量都是在编译uboot时使用的
2. $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target))
在上级Makefile中定义KBUILD_MODULES := 所以该语句为空
3. $(subdir-ym)定义:
在Makefile.build包含的文件scripts/Makefile.lib定义如下:
subdir-ym := $(sort $(subdir-y) $(subdir-m))
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
subdir-y与subdir-m都为空,所以该目标也为空,这些都是在编译uboot阶段使用的参数
4. $(always)的定义:
在Makefile.build中always := 定义为空,但是在本文件中:
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
4.1 关于src的定义:
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
patsubst功能参考Makefile手册的定义:
而在根命令make -f ./scripts/Makefile.build obj=scripts/basic我们传入了obj=scripts/basic
所以src = obj = scripts/basic, prefix := .
4.2 kbuild-dir的定义:
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
filter函数的定义参考Makefile手册:
所以 kbuild-dir = ./scripts/basic
4.3 kbuild-file的定义:
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
wildcard的功能参考Makefile手册的定义:
所以kbuild-file = ./scripts/basic/Makefile
所以include $(kbuild-file)即为include ./scripts/basic/Makefile
在./scripts/basic/Makefile中:
hostprogs-y := fixdep
always := $(hostprogs-y)
$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
所以always = fixdep
4.4 又在Makefile.build中包含include scripts/Makefile.lib
而在scripts/Makefile.lib中always := $(addprefix $(obj)/,$(always))
addprefix的定义参考Makefile手册:
所以最终 always = scripts/basic/fixdep
故__build展开如下:
__build: scripts/basic/fixdep
@:
>>>>>>>>生成scripts/basic/fixdep
1. 在Makefile.build中有如下定义:
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host
endif
在./scripts/basic/Makefile中hostprogs-y = fixdep, 所以scripts/Makefile.host被包含进Makefile.build
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)),hostprogs-m为空,所以__hostprogs = fixdep
host-csingle := $(foreach m,$(__hostprogs), $(if $($(m)-objs)$($(m)-cxxobjs),,$(m)))
因为fixdep-objs与fixdep-cxxobjs都不存在,所以host-csingle = fixdep
host-csingle := $(addprefix $(obj)/,$(host-csingle)),所以host-csingle = scripts/basic/fixdep
$(host-csingle): $(obj)/%: $(src)/%.c FORCE
$(call if_changed_dep,host-csingle)
等价于:scripts/basic/fixdep:scripts/basic/fixdep.c FORCE
$(call if_changed_dep,host-csingle)
call函数功能参考Makefile手册:
2. if_changed_dep在scripts/Kbuild.include中定义:
if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
scripts/basic/fixdep $(depfile) [email protected] '$(make-cmd)' > $(dot-target).tmp;\
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd)
2.1 $(strip $(any-prereq) $(arg-check) )
any-prereq在scripts/Kbuild.include中定义
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
$? 表示所有比目标还要新的依赖文件;$^ 表示所有的依赖文件,$(filter-out $(PHONY),$?)就是过滤到比目标还要新的依赖文件中的伪目标,即为scripts/basic/fixdep.c,$(filter-out $(PHONY) $(wildcard $^),$^)表示过滤掉所有的依赖文件中的伪目标与存在的依赖文件,即为空,所以any-prereq = scripts/basic/fixdep.c
arg-check在scripts/Kbuild.include中定义:
ifneq ($(KBUILD_NOCMDDEP),1)
arg-check = $(strip $(filter-out $(cmd_$(1)), $([email protected])) \
$(filter-out $([email protected]), $(cmd_$(1))) )
else
arg-check = $(if $(strip $([email protected])),,1)
endif
KBUILD_NOCMDDEP是在make命令行中定义,我们并没有定义,所以:
arg-check = $(strip $(filter-out $(cmd_$(1)), $([email protected])) \
$(filter-out $([email protected]), $(cmd_$(1))) )
$(filter-out $(cmd_$(1)), $([email protected])) 表示过滤掉 $([email protected])中符合$(cmd_$(1))的项
$(1)表示if_changed_dep函数的第一个参数host-csingle,[email protected]表示目标文件scripts/basic/fixdep
cmd_scripts/basic/fixdep并没有定义,所以$(filter-out $(cmd_$(1)), $([email protected]))为空
cmd_host-csingle 在Makefile.host中定义:
cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o [email protected] $< $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
所以arg-check = $(filter-out $([email protected]), $(cmd_$(1))) = $(HOSTCC) $(hostc_flags) -o [email protected] $< $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
$(any-prereq) $(arg-check)都为非空,所以:
if_changed_dep = @set -e; \ //如果任何语句的执行结果不是true则应该退出
$(echo-cmd) $(cmd_$(1)); \
scripts/basic/fixdep $(depfile) [email protected] '$(make-cmd)' > $(dot-target).tmp;\
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd)
2.2 $(echo-cmd) $(cmd_$(1))等价于$(echo-cmd) $(cmd_host-csingle)
echo-cmd = $(if $($(quiet)cmd_$(1)),echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
quiet为空,在$(V)分析过,$(cmd_host-csingle)上面分析过,存在,所以:
echo-cmd = echo ' $(call escsq,$(cmd_host-csingle))$(echo-why)';
在scripts/Kbuild.include中:
why =
echo-why = $(call escsq, $(strip $(why)))
escsq = $(subst $(squote),'\$(squote)',$1) , squote := '
subst函数参考Makefile手册:
所以escsq的作用就是把$1中的’替换为\'
所以 echo-why 为空
cmd_host-csingle = '$(HOSTCC) $(hostc_flags) -o [email protected] $< $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))'
$(HOSTCC)为cc,此处不在深入解释,hostc_flags在Makefile.host中定义:
_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS_$(basetarget).o)
_hostc_flags = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer 此处不在深入分析
ifeq ($(KBUILD_SRC),) //KBUILD_SRC在make命令行定义,此处未定义
__hostc_flags = $(_hostc_flags) //-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
__hostcxx_flags = $(_hostcxx_flags)
else
__hostc_flags = -I$(obj) $(call flags,_hostc_flags)
__hostcxx_flags = -I$(obj) $(call flags,_hostcxx_flags)
endif
hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags)
在scripts/Kbuild.include中:
comma := ,
dot-target = $(dir [email protected]).$(notdir [email protected]) //scripts/basic/.fixdep
depfile = $(subst $(comma),_,$(dot-target).d) //scripts/basic/.fixdep.d
hostc_flags = -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
cmd_host-csingle = cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c
所以echo-cmd 即为打印cmd_host-csingle,$(cmd_$(1))即为执行cmd_host-csingle生成fixdep同时生成fixdep的依赖文件.fixdep.d
2.3 scripts/basic/fixdep $(depfile) [email protected] '$(make-cmd)' > $(dot-target).tmp;
等价于:scripts/basic/fixdep scripts/basic/.fixdep.d scripts/basic/fixdep 'cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c' > scripts/basic/.fixdep.tmp
2.4 rm -f $(depfile); //删除scripts/basic/.fixdep.d
2.5 mv -f $(dot-target).tmp $(dot-target).cmd) //将scripts/basic/.fixdep.tmp重命名为scripts/basic/.fixdep.cmd
总结:生成scripts/basic/fixdep的过程中会先打印cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c同时执行该语句生成fixdep,再用fixdep生成.fixdep.cmd