# # Copyright (C) 2007 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # # 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 # # 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 # # $(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. # empty := space := $(empty) $(empty) define uniq-word $(strip \ $(if $(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_TAG := @inherit: # # 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 # define get-inherited-nodes $(sort \ $(subst $(INHERIT_TAG),, \ $(filter $(INHERIT_TAG)%, \ $(foreach v,$(2),$($(1).$(v))) \ ))) endef # # 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 # 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) := \ $(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 # # $(1): context prefix # $(2): makefile representing this node # $(3): list of node variable names # #TODO: keep a debug stack to make error messages more helpful define _import-node $(call clear-var-list, $(3)) $(eval include $(2)) $(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 :=) endef # # $(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. 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 # # $(1): output list variable name, like "PRODUCTS" or "DEVICES" # $(2): list of makefiles representing nodes to import # $(3): list of node variable names # define import-nodes $(if \ $(foreach _in,$(2), \ $(eval _node_import_context := _nic.$(1).[[$(_in)]]) \ $(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)) \ ) \ ,) endef