内核映像的形成——prepare和scripts目标

2.2.3 preparescripts目标

上一节我们找到了整个KBuild体系的第一个目标,根据是否进行了编译配置而分别是385行的scripts_basic949行的include/config/kernel.release。更重要的是,通过第一个目标的寻找,我们把KBuild体系的整个顶层Makefile文件脉络梳理了一遍,这对我们研究vmlinux的形成及其重要。下面我们就从第一个目标开始,对编译配置后make的整个过程来过一遍。

 

949行,第一个目标:

949 include/config/kernel.release: include/config/auto.conf FORCE

950        $(Q)rm -f $@

951        $(Q)echo $(kernelrelease) > $@

 

执行的命令很简单,删除旧的kernel.release,新建一个kernel.release并把kernelrelease变量的值转移标准输出,写入该文件:

358 KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)

948 kernelrelease = $(KERNELVERSION)$(localver-full)

 

第一个目标完成后,来到966行的prepare3目标:

966 prepare3: include/config/kernel.release

967 ifneq ($(KBUILD_SRC),)

968        @$(kecho) '  Using $(srctree) as source for kernel'

969        $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then /

970               echo "  $(srctree) is not clean, please run 'make mrproper'";/

971               echo "  in the '$(srctree)' directory.";/

972               /bin/false; /

973        fi;

974 endif

 

没有问题,不会去执行的,因为$(KBUILD_SRC)是空的。所以来到977行:

977 prepare2: prepare3 outputmakefile

 

我们看到prepare2什么命令也不执行,但它除了prepare3还有个依赖outputmakefile

396 outputmakefile:

397 ifneq ($(KBUILD_SRC),)

398        $(Q)ln -fsn $(srctree) source

399        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile /

400            $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)

401 endif

 

同样也不会执行这个命令。那么就来到了979行:

979 prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h /

980                   include/config/auto.conf

981        $(cmd_crmodverdir)

 

看到它的依赖:

1013 include/linux/version.h: $(srctree)/Makefile FORCE

1014      $(call filechk,version.h)

 

有个FORCE,所以尽管include/linux/version.h是存在的,但也要执行1014的命令。我们只是学习学习新知识,1014行代码,函数callcall 关键字是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call 函数来向这个表达式传递参数。其语法是:

$(call <expression>,<parm1>,<parm2>,<parm3>...)

 

make 执行这个函数时,<expression>参数中的变量,如$(1)$(2)$(3)等,会被参数<parm1><parm2><parm3>依次取代。而<expression>的返回值就是call 函数的返回值。

 

例如:

reverse = $(1) $(2)

foo = $(call reverse,a,b)

 

那么,foo 的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:

reverse = $(2) $(1)

foo = $(call reverse,a,b)

此时的 foo 的值就是b a

 

所以我们猜到1014行的代码是让filechk变量等于变成另一个字符串。那么,filechk变量在哪儿定义的呢?顶层Makefile找不到,那么在/scripts/Kbuild.include中找,49行:

define filechk

       $(Q)set -e;                           /

       $(kecho) '  CHK     $@';         /

       mkdir -p $(dir $@);                    /

       $(filechk_$(1)) < $< > [email protected];          /

       if [ -r $@ ] && cmp -s $@ [email protected]; then   /

              rm -f [email protected];                     /

       else                              /

              $(kecho) '  UPD     $@';  /

              mv -f [email protected] $@;        /

       fi

endef

 

调用call以后filechk变量就会变成

       $(Q)set -e;                           /

       $(kecho) '  CHK     $@';         /

       mkdir -p $(dir $@);                    /

       $(filechk_ version.h) < $< > [email protected];         /

       if [ -r $@ ] && cmp -s $@ [email protected]; then   /

              rm -f [email protected];                     /

       else                              /

              $(kecho) '  UPD     $@';  /

              mv -f [email protected] $@;        /

       fi

 

其中的$@include/linux/version.h所以我们看到make之后屏幕输出的第一行肯定是

  CHK     include/linux/version.h

 

第三个依赖include/generated/utsrelease.h来自1016

1016 include/generated/utsrelease.h: include/config/kernel.release FORCE

1017      $(call filechk,utsrelease.h)

跟第二个依赖一样所以不去管它了。

 

最后一个依赖include/config/auto.confmake menucofig生成的所以就执行prepare1的命令了

cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) /

                  $(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*)

 

这个命令我没看懂是什么,只知道在373行有个$(MODVERDIR)变量的定义:

export MODVERDIR := /

$(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions

 

不管怎样,这个文件夹终究会被删除的,不去详细分析了。那么prepare1也结束了,这时候才来到了archprepare的第二个依赖,scripts_basic。有关scripts_basic我们在编译配置里已经详细谈过了,其结果是在scripts/basic/生成三个c程序:fixdepdocprochash。具体是怎么得到他们的请参照前面讲解的KBuild体系去查看scripts/basic/Makefile文件。至于他们是干什么的,以后用到了再研究。

 

scripts_basic目标结束后,archprepare因为没有附带任何命令,也结束了。所以来到985行的prepare0

prepare0: archprepare FORCE

       $(Q)$(MAKE) $(build)=.

       $(Q)$(MAKE) $(build)=. missing-syscalls

 

翻译一下:

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

@make -f scripts/Makefile.build obj=. missing-syscalls

 

这里是将顶层目录,也就是/usr/src/kernels/linux-2.6.34.1赋值给obj。当然,顶层Makefile本身也是个KBuild的参数,所以会在屏幕上打印以下一些信息:

  CC      kernel/bounds.s

  GEN     include/generated/bounds.h

  CC      arch/x86/kernel/asm-offsets.s

  GEN     include/generated/asm-offsets.h

  CALL    scripts/checksyscalls.sh

 

至于为啥,我也没弄懂,还要请教广大网友帮我研究研究。prepare0完毕以后,prepare也就完成了,$(vmlinux-dirs)的第一个依赖也就搞完了。一路走来还是很艰辛的,这就是内核!来看第二个依赖,scripts,在473行:

473 scripts: scripts_basic include/config/auto.conf include/config/tristate.conf

474        $(Q)$(MAKE) $(build)=$(@)

 

scripts_basic目标已经执行过了,include/config/tristate.conf文件也存在,所以直接执行474行的命令:

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

 

我们就去看scripts目录下的Makefile文件。具体内容我就不列出来了,主要是理清思路:先是subdir-y,有subdir-$(CONFIG_MODVERSIONS) += genksyms等内容,那么就到genksyms等等这些子目录去执行他们的Makefile,执行完后,再根据hostprogs-y的内容生成主机程序。

 

hostprogs-$(CONFIG_XXX)是去根据CONFIG_XXX标志主机程序,再去形成这些主机程序,也就是说直接去生成c程序而不是形成.o以制作built-in.o。具体的原理请去查阅前面有关KBuild体系主机程序的内容。

 

scripts目标执行完后,整个前期准备工作就算完成了。后面就是更加艰难的形成vmlinux工作。

你可能感兴趣的:(工作,shell,cmd,basic,Build,makefile)