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手册:

           JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

            在此语句之前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手册的定义:

       JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

      而在根命令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手册:

                 JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

          所以 kbuild-dir = ./scripts/basic

         4.3 kbuild-file的定义:

                kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)

                wildcard的功能参考Makefile手册的定义:

                      JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

                所以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手册:

                      JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

     所以最终 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手册:

            JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

     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手册:

                                                 JZ2440开发板移植u-boot 2015.01----第三篇,分析make -f ./scripts/Makefile.build obj=scripts/basic

                                        所以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