OpenWrt makefile 分析

本文详细分析了OpenWrt的编译过程,包括编译host工具、交叉工具链、内核模块、ipk,以及如何将内核和文件系统组合成最终binary。重点解析了顶层Makefile的结构,特别是如何通过`OPENWRT_BUILD`变量控制编译的不同阶段。Makefile的执行涉及多个子目录的Makefile,通过$(INCLUDE_DIR)/subdir.mk动态建立规则,并使用变量命名的目标来确保正确的工作顺序。

编译总体过程

  1. 编译host工具
  2. 编译交叉工具链
  3. 编译内核模块
  4. 编译ipk
  5. 安装ipk到文件系统
  6. 编译内核
  7. 将内核和文件系统组合成最终binary

顶层Makefile分析

在顶层Makefile里比较麻烦的是,将Makefile分为了两个主要分支,第一个部分主要是执行编译前的准备,第二个部分是执行编译。在每个分支里通过include载入相应的文件,在这些文件里包含相应的目标执行命令,在命令中多次用make+目标+参数的方式,则会再次执行Makefile文件,就形成了Makefile的嵌套执行。在嵌套执行的过程中,通过变量OPENWRT_BUILD来区分是执行顶层Makefile的那个部分,如果在make命令行中有OPENWRT_BUILD为0,则执行第一个部分,没有加OPENWRT_BUILD变量则执行第二个部分。
由于OPENWRT_BUILD是make命令行参数,所以在Makefile中如果要改变它的值,就用到了override指示符。

target/Makefile、package/Makefile、tools/Makefile、toolchain/Makefile这四个子目录下的Makefile实际上是不能独立执行。主要利用$(INCLUDE_DIR)/subdir.mk动态建立规则,诸如$(toolchain/stamp-install)目标是靠$(INCLUDE_DIR)/subdir.mk的stampfile函数动态建立。

$(package/stamp-compile): $(target/stamp-compile) $(package/stamp-cleanup)

这类使用变量命名的目标,其变量的赋值位置在$(INCLUDE_DIR)/subdir.mk的stampfile函数中。目标只有依赖关系,可能说明其工作顺序,在$(INCLUDE_DIR)/subdir.mk的stampfile函数中有进一步说明其目标执行的命令,并为目标建立一个空文件,即使用变量命名的目标为真实的文件。

top Makefile: $(package/stamp-compile): $(target/stamp-compile) $(package/stamp-cleanup)
package_makefile:  $(eval $(call stampfile,$(curdir),package,compile,$(TMP_DIR)/.build))
subdir.mk:  
define stampfile     # Parameters: <subdir> <name> <target> <depends> <config options> <stampfile location>
      $(1)/stamp-$(3):=$(if $(6),$(6),$(STAGING_DIR))/stamp/.$(2)_$(3)$(5)
      $$($(1)/stamp-$(3)): $(TMP_DIR)/.build $(4)

$(1)=$(curdir)   $(2)=package   $(3)=compile   
$(package/stamp-compile):=$(STAGING_DIR)/stamp/.package_compile

prereq应该是预请求目标,在OpenWrt执行Makefile时好像都要先执行prereq目标。
prepare应该是准备目标,是world依赖的一个伪目标。依赖于文件.config和$(tools/stamp-install) $(toolchain/stamp-install)目标。

top Makefile:  // second part
prereq: $(target/stamp-prereq) tmp/.prereq_packages
prepare: .config  $(tools/stamp-install)  $(toolchain/stamp-install)
world: prepare  $(target/stamp-compile)  $(package/stamp-compile)  $(package/stamp-install)   $(target/stamp-install)  FORCE
        $(_SINGLE)$(SUBMAKE) -r package/index
toplevel.mk:
prereq:: prepare-tmpinfo .config
        @+$(NO_TRACE_MAKE) -r -s $@                    (@make  tmp/.prereq-build)

%::
        @+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq         
        @+$(ULIMIT_FIX) $(SUBMAKE) -r $@

除了少数在toplevel中被定义的目标外, 其他编译目标都会走到这里.将之简化后:
%::
make prereq
make $@
首先执行prereq, 然后再执行我们指定的目标或者默认目标world.

NO_TRACE_MAKE := $(MAKE) V=99
上面的 “%::” 用于解释world目标的规则
%是通配符,加上双冒号规则,此组合表示任何目标去无条件执行下面的命令

在执行@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq命令的时候,在make命令行里有$(PREP_MK)变量,而由于OPENWRT_BUILD的值为0,在verbose.mk文件里NO_TRACE_MAKE := $(MAKE) V=99,所以会执行顶层目录的Makefile第一个分支部分的目标prereq,即toplevel.mk文件中的目标prereq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值