openwrt
这里主要介绍openwrt的主Makefile,并未对各个目录下的Makefile和相关文件进行介绍。
在Makefile里是两个主要的分支,由if语句根据OPENWRT_BUILD的值进行不同的处理。第一个部分主要是执行编译前的准备,第二个部分是执行编译。
打开Makefile文件,可以看到默认的make目标world,这个目标没有依赖文件和执行命令。
执行make的时候,首先进入第一个部分,此时OPENWRT_BUILD的值为0,然后将OPENWRT_BUILD的值赋为1,在这里用到了override指示符,override指示符的作用的忽略make命令行的参数的赋值,可以对该变量进行赋值。
载入include下的相关文件,在toplevel.mk可以看到
%::
@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
@+$(SUBMAKE) -r $@
默认的目标就会执行这里。
在toplevel.mk的顶部定义了PREP_MK= OPENWRT_BUILD= QUIET=0,将OPENWRT_BUILD的值赋为0。
在执行@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq命令的时候,在make命令行里有$(PREP_MK)变量,而由于OPENWRT_BUILD的值为0,在verbose.mk文件里,所以会执行顶层
目录的Makefile第一个分支部分的目标prereq,即toplevel.mk文件中的目标prereq: prereq:: prepare-tmpinfo .config
@+$(MAKE) -r -s tmp/.prereq-build $(PREP_MK)
@+$(NO_TRACE_MAKE) -r -s $@
这里会进行一些编译前的准备工作,然后执行@+$(NO_TRACE_MAKE) -r -s $@,再次去执行顶层Makefile,此时,并没有$(PREP_MK)变量,所以会执行顶层Makefile的第一个部分,载入include下的相关文件,和一些必要的Makefile文件,在顶层Makefile去寻找prereq目标,
prereq: $(target/stamp-prereq) tmp/.prereq_packages
处理它的依赖文件。
然后再接着执行toplevel.mk
%::
@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
@+$(SUBMAKE) -r $@
在@+$(SUBMAKE) -r $@命令中也没有$(PREP_MK)变量,所以在顶层Makefile的第二个部分,寻找Makefile的默认目标,即world。
world: prepare $(target/stamp-compile) $(package/stamp-cleanup) $(package/stamp-compile) $(package/stamp-install) $(package/stamp-rootfs-prepare) $(target/stamp-install) FORCE $(_SINGLE)$(SUBMAKE) -r package/index
根据各个依赖文件进行相应的编译,最终完成编译。
在顶层Makefile里比较麻烦的是,将Makefile分为了两个主要分支,在每个分支里通过include载入相应的文件,在这些文件里包含相应的目标执行命令,在命令中多次用make + 目标 + 参数 的方式,则会再次执行Makefile文件,就形成了Makefile的嵌套执行。
在嵌套执行的过程中,通过变量OPENWRT_BUILD来区分是执行顶层Makefile的那个部分,如果在make命令行中有OPENWRT_BUILD为0,则执行第一个部分,没有加OPENWRT_BUILD变量则执行第二个部分。
由于OPENWRT_BUILD是make命令行参数,所以在Makefile中如果要改变它的值,就用到了override指示符。