Search code examples
makefilegnu-makeandroid-source

How to foreach and eval function in Makefile work?


I'm trying to understand Makefile syntax and Makefile system of AOSP. But, it is difficult to a beginner like me. I understand how fereach function work but dont understand when is used with eval function like below. Can someone explain the piece of Makefile code below ? how it work step by step and the output of every step ? the final value of all_product_configs variable ? Thanks all so much !

all_product_configs := $(call get-product-makefiles,\
    $(SRC_TARGET_DIR)/product/AndroidProducts.mk)

and this is definition of get-product-makefiles function :

define get-product-makefiles
$(sort \
  $(foreach f,$(1), \
    $(eval PRODUCT_MAKEFILES :=) \
    $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
    $(eval include $(f)) \
    $(PRODUCT_MAKEFILES) \
   ) \
  $(eval PRODUCT_MAKEFILES :=) \
  $(eval LOCAL_DIR :=) \
 )
endef

Solution

  • eval takes its argument and evaluates it as Makefile syntax -- definitions of variables and rules, and any other GNUmake syntax -- and expands to nothing (an empty string)

    foreach takes its 3rd argument and repeats it once for each word in the 2nd argument, with 1st argument being defined as the corresponding word each time. The result is that (big) string.

    call takes its first argument as the name of a variable and expands that variable with $(1), $(2), etc set to the other arguments of the call

    So from the top, you expand get-product-makefiles with $(1) set to $(SRC_TARGET_DIR)/product/AndroidProducts.mk That is actually the 2nd arg of a foreach, and is onlye one word, so the foreach will expand the 3rd arg once, with $(f) set to that string ($(SRC_TARGET_DIR)/product/AndroidProducts.mk). So that is just

    $(eval PRODUCT_MAKEFILES :=) \
    $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(SRC_TARGET_DIR)/product/AndroidProducts.mk))) \
    $(eval include $(SRC_TARGET_DIR)/product/AndroidProducts.mk) \
    $(PRODUCT_MAKEFILES) \
    

    So it runs those evals which defines those variables (PRODUCT_MAKEFILES and LOCAL_DIR) and then includes the other makefile (which presumables defines PRODUCT_MAKEFILES to be something non-empty, probably appending stuff to it). It then expands to whatever that is, followed by the last two eval commands whic clear those two variables and expand to nothing. So the net result will be just whatever $(PRODUCT_MAKEFILES) was defined as in the AndroidProducts.mk while that variable itself is not actually set any more. It then sorts that (the sort command -- which incidentally deletes duplicated words after sorting), and that is what the whole thing ends up as -- and that is what all_product_configs gets set to.

    This would be more interesting if there were mulitple makefiles in the call command. Then it would end up reading all of them and pulling in all the things they define in PRODUCT_MAKEFILES, concatenating and sorting the lot.