android编译分析之5—node_fns.mk

我理解这个makefile名字的意思就是node相关functions的函数,在android编译系统中,可以包含很多的产品,对于特定的一个产品都会定义一个makefile,例如对于aosp_arm而言,既是build/target/product/aosp_arm.mk,一种产品就是一个node。
node_fns.mk主要就是将一种产品的makefile中定义的相关变量导入到系统的全局变量中。例如product中定义了PRODUCT_NAME=aosp_arm,那么最终PRODUCT_NAME会保存在PRODUCTS.*aosp_arm.mk.PRODUCT_NAME中

# 清除变量的值
# Clears a list of variables using ":=".
#
# E.g.,
#   $(call clear-var-list,A B C)
# would be the same as:
#   A :=
#   B :=
#   C :=
#
# $(1): list of variable names to clear
#
define clear-var-list
$(foreach v,$(1),$(eval $(v):=))
endef

拷贝原变量到加了前缀的变量中,android编译系统中这种用法很普遍,一般前缀都是和产品相关的makefile文件的路径。

#
# Copies a list of variables into another list of variables.
# The target list is the same as the source list, but has
# a dotted prefix affixed to it.
#
# E.g.,
#   $(call copy-var-list, PREFIX, A B)
# would be the same as:
#   PREFIX.A := $(A)
#   PREFIX.B := $(B)
#
# $(1): destination prefix
# $(2): list of variable names to copy
#
define copy-var-list
$(foreach v,$(2),$(eval $(strip $(1)).$(v):=$($(v))))
endef

拷贝变量,但是拷贝前后的前缀不同,换个前缀,拷贝完成后,将原变量清空。

#
# Moves a list of variables into another list of variables.
# The variable names differ by a prefix.  After moving, the
# source variable is cleared.
#
# NOTE: Spaces are not allowed around the prefixes.
#
# E.g.,
#   $(call move-var-list,SRC,DST,A B)
# would be the same as:
#   DST.A := $(SRC.A)
#   SRC.A :=
#   DST.B := $(SRC.B)
#   SRC.B :=
#
# $(1): source prefix
# $(2): destination prefix
# $(3): list of variable names to move
#
define move-var-list
$(foreach v,$(3), \
  $(eval $(2).$(v) := $($(1).$(v))) \
  $(eval $(1).$(v) :=) \
 )
endef

在一个list中剔除重复的部分,只保留首次出现的。

#
# $(1): haystack
# $(2): needle
#
# Guarantees that needle appears at most once in haystack,
# without changing the order of other elements in haystack.
# If needle appears multiple times, only the first occurrance
# will survive.
#
# How it works:
#
# - Stick everything in haystack into a single word,
#   with "|||" separating the words.
# - Replace occurrances of "|||$(needle)|||" with "||| |||",
#   breaking haystack back into multiple words, with spaces
#   where needle appeared.
# - Add needle between the first and second words of haystack.
# - Replace "|||" with spaces, breaking haystack back into
#   individual words.
#
define uniq-word
$(strip \
  $(if $(filter-out 0 1,$(words $(filter $(2),$(1)))), \
    $(eval h := |||$(subst $(space),|||,$(strip $(1)))|||) \
    $(eval h := $(subst |||$(strip $(2))|||,|||$(space)|||,$(h))) \
    $(eval h := $(word 1,$(h)) $(2) $(wordlist 2,9999,$(h))) \
    $(subst |||,$(space),$(h)) \
   , \
    $(1) \
 ))
endef

继承的标志为@inherit :,

INHERIT_TAG := @inherit:

将变量中有INHERIT_TAG的部分留下来,然后把保留下来的这部分去掉INHERIT_TAG,并sort,sort就是按字母排序,并剔除重复的。在android make系统中,node其实指的都是makefile文件,这个函数就是为了得到继承的makefile文件,后续使用时会有详细介绍。

#
# Walks through the list of variables, each qualified by the prefix,
# and finds instances of words beginning with INHERIT_TAG.  Scrape
# off INHERIT_TAG from each matching word, and return the sorted,
# unique set of those words.
#
# E.g., given
#   PREFIX.A := A $(INHERIT_TAG)aaa B C
#   PREFIX.B := B $(INHERIT_TAG)aaa C $(INHERIT_TAG)bbb D E
# Then
#   $(call get-inherited-nodes,PREFIX,A B)
# returns
#   aaa bbb
#
# $(1): variable prefix
# $(2): list of variables to check
#
# 将INHERIT_TAG替换为空
# sort 以字母排序 然后去掉重复的
define get-inherited-nodes
$(sort \
  $(subst $(INHERIT_TAG),, \
    $(filter $(INHERIT_TAG)%, \
      $(foreach v,$(2),$($(1).$(v))) \
 )))
endef

下面这个函数主要是为了获取继承的makefile中的值。

#
# for each variable ( (prefix + name) * vars ):
#   get list of inherited words; if not empty:
#     for each inherit:
#       replace the first occurrence with (prefix + inherited + var)
#       clear the source var so we can't inherit the value twice
#
# $(1): context prefix
# $(2): name of this node 
# $(3): list of variable names
# 主要为了将变量中继承的部分展开为继承的值
# 例如已经通过$(call inherit-product, full.mk)继承了full.mk
# 下面举个例子,将makefile的路径省略了,为了简便
# 首先获取加前缀的原变量prefix.aosp_arm.mk.PRODUCT_LOCALES,
# 假如为en_US @inherit:full.mk,这时候_eiv_tv就为en_US @inherit:full.mk
# 而_eiv_i为full.mk,即继承的node。
# 而且通过uniq-word保证_eiv_tv中只继承一次full.mk即不能有多个@inherit:full.mk
# 然后将prefix.aosp_arm.mk.PRODUCT_LOCALES中的@inherit:full.mk替换为
# prefix.full.mk.PRODUCT_LOCALES,而这个参数既是继承的full.mk中定义的PRODUCT_LOCALES
# 最后自己不能继承自己,否则会是个死循环。
define _expand-inherited-values
  $(foreach v,$(3), \
    $(eval ### "Shorthand for the name of the target variable") \
    $(eval _eiv_tv := $(1).$(2).$(v)) \
    $(eval ### "Get the list of nodes that this variable inherits") \
    $(eval _eiv_i := \
        $(sort \
            $(patsubst $(INHERIT_TAG)%,%, \
                $(filter $(INHERIT_TAG)%, $($(_eiv_tv)) \
     )))) \
    $(foreach i,$(_eiv_i), \
      $(eval ### "Make sure that this inherit appears only once") \
      $(eval $(_eiv_tv) := \
          $(call uniq-word,$($(_eiv_tv)),$(INHERIT_TAG)$(i))) \
      $(eval ### "Expand the inherit tag") \
      $(eval $(_eiv_tv) := \
          $(strip \
              $(patsubst $(INHERIT_TAG)$(i),$($(1).$(i).$(v)), \
                  $($(_eiv_tv))))) \
      $(eval ### "Clear the child so DAGs don't create duplicate entries" ) \
      $(eval $(1).$(i).$(v) :=) \
      $(eval ### "If we just inherited ourselves, it's a cycle.") \
      $(if $(filter $(INHERIT_TAG)$(2),$($(_eiv_tv))), \
        $(warning Cycle detected between "$(2)" and "$(i)" for context "$(1)") \
        $(error import of "$(2)" failed) \
      ) \
     ) \
   ) \
   $(eval _eiv_tv :=) \
   $(eval _eiv_i :=)
endef

# 下面这三个函数从import-nodes倒着分析
# $(1): context prefix
# $(2): makefile representing this node
# $(3): list of node variable names
#
# _include_stack contains the list of included files, with the most recent files first.
# $(1)为_nic.PRODUCTS.[[aosp_arm.mk]]
# $(2)为aosp_arm.mk,而$(3)为_product_var_list
# 前缀是_nic.PRODUCTS.[[aosp_arm.mk]] 
# 首先include aosp_arm.mk,如果在aosp_arm.mk中有继承,则
# 通过inherit后 ,PRODUCT_NAME这些变量的值变化了
# 如果这时候PRODUCT_NAME为空,那么$($(v))就为空,PRODUCT_NAME就被修改为
# @inherit $(SRC_TARGET_DIR)/product/full.mk
# inherit_var= PRODUCTS.aosp_arm.mk.INHERITS_FROM
# 然后把PRODUCTS.aosp_arm.mk.INHERITS_FROM 的值设置为$(SRC_TARGET_DIR)/product/full.mk
# MAKEFILE_LIST是Make的一个全局变量,当前正在include的makefile,
# filter-out 过滤掉makefile_list中的所有包括$2的东西,剩下不包括的
# 这里_included为空吧
# 将product_list都加前缀,$(1).$(2).$(3)=$(3),如果调用了inherit,这时候$(3)的值已经
# 变为@inherit:$(SRC_TARGET_DIR)/product/full.mk
# $(1).$(2).inherited已经变成了$(SRC_TARGET_DIR)/product/full.mk
# 然后再调用一次,_import-nodes-inner,将$(SRC_TARGET_DIR)/product/full.mk再import一下
# 即将继承的产品此时也import一下
# 最后一步将最顶端的include stack出栈
define _import-node
  $(eval _include_stack := $(2) $$(_include_stack))
  $(call clear-var-list, $(3))
  $(eval LOCAL_PATH := $(patsubst %/,%,$(dir $(2))))
  $(eval MAKEFILE_LIST :=)
  $(eval include $(2))
  $(eval _included := $(filter-out $(2),$(MAKEFILE_LIST)))
  $(eval MAKEFILE_LIST :=)
  $(eval LOCAL_PATH :=)
  $(call copy-var-list, $(1).$(2), $(3))
  $(call clear-var-list, $(3))

  $(eval $(1).$(2).inherited := \
      $(call get-inherited-nodes,$(1).$(2),$(3)))
  $(call _import-nodes-inner,$(1),$($(1).$(2).inherited),$(3))

  $(call _expand-inherited-values,$(1),$(2),$(3))

  $(eval $(1).$(2).inherited :=)
  $(eval _include_stack := $(wordlist 2,9999,$$(_include_stack)))
endef

#
# This will generate a warning for _included above
#  $(if $(_included), \
#      $(eval $(warning product spec file: $(2)))\
#      $(foreach _inc,$(_included),$(eval $(warning $(space)$(space)$(space)includes: $(_inc)))),)
#

#
# $(1): context prefix
# $(2): list of makefiles representing nodes to import
# $(3): list of node variable names
#
#TODO: Make the "does not exist" message more helpful;
#      should print out the name of the file trying to include it.
# $(1)为_nic.PRODUCTS.[[aosp_arm.mk]]
# $(2)为aosp_arm.mk,而$(3)为_product_var_list
# 如果_nic.PRODUCTS.[[aosp_arm.mk]].aosp_arm.mk.seen为true,表示这个node
# 已经import过了,否则设置为true,然后调用_import-node
define _import-nodes-inner
  $(foreach _in,$(2), \
    $(if $(wildcard $(_in)), \
      $(if $($(1).$(_in).seen), \
        $(eval ### "skipping already-imported $(_in)") \
       , \
        $(eval $(1).$(_in).seen := true) \
        $(call _import-node,$(1),$(strip $(_in)),$(3)) \
       ) \
     , \
      $(error $(1): "$(_in)" does not exist) \
     ) \
   )
endef

# 导入一个产品的makefile
# $(1): output list variable name, like "PRODUCTS" or "DEVICES"
# $(2): list of makefiles representing nodes to import
# $(3): list of node variable names
# 前缀是_nic.PRODUCTS.[[aosp_arm.mk]]
# 最终产品中的变量会通过move-var-list,将前缀变为PRODUCTS.aosp_arm.mk.,
# 例如PRODUCT_NAME保存在PRODUCTS.aosp_arm.mk.PRODUCT_NAME中
define import-nodes
$(if \
  $(foreach _in,$(2), \
    $(eval _node_import_context := _nic.$(1).[[$(_in)]]) \
    $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                should be empty here: $(_include_stack))),) \
    $(eval _include_stack := ) \
    $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3)) \
    $(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \
    $(eval _node_import_context :=) \
    $(eval $(1) := $($(1)) $(_in)) \
    $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                should be empty here: $(_include_stack))),) \
   ) \
,)
endef
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值