android编译分析之5—node_fns.mk

来源:互联网 发布:qq举报风险软件 编辑:程序博客网 时间:2024/06/15 09:09

我理解这个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-nodedefine _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
0 0