Makefile 中的 foreach 和 eval 函数如何工作?
How to foreach and eval function in Makefile work?
我正在尝试了解AOSP 的Makefile 语法和Makefile 系统。但是,这对像我这样的初学者来说很难。我了解 fereach 函数的工作原理,但不了解何时与 eval 函数一起使用,如下所示。有人可以解释下面的 Makefile 代码吗?它是如何一步步工作的以及每一步的输出? all_product_configs
变量的最终值?非常感谢!
all_product_configs := $(call get-product-makefiles,\
$(SRC_TARGET_DIR)/product/AndroidProducts.mk)
这是 get-product-makefiles
函数的定义:
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
eval
接受它的参数并将其评估为 Makefile 语法——变量和规则的定义,以及任何其他 GNUmake 语法——然后展开为空(一个空字符串)
foreach
接受它的第三个参数,并为第二个参数中的每个单词重复一次,第一个参数每次都被定义为相应的单词。结果是那个(大)字符串。
call
将其第一个参数作为变量名,并使用 $(1)
、$(2)
等扩展该变量,并将其设置为 call
的其他参数
所以从顶部开始,您展开 get-product-makefiles
并将 $(1)
设置为 $(SRC_TARGET_DIR)/product/AndroidProducts.mk
这实际上是 foreach 的第二个参数,并且只有一个词,所以 foreach
将扩展第三个参数一次,$(f)
设置为该字符串 ($(SRC_TARGET_DIR)/product/AndroidProducts.mk
)。所以这只是
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(SRC_TARGET_DIR)/product/AndroidProducts.mk))) \
$(eval include $(SRC_TARGET_DIR)/product/AndroidProducts.mk) \
$(PRODUCT_MAKEFILES) \
所以它运行那些定义那些变量(PRODUCT_MAKEFILES
和 LOCAL_DIR
)的评估,然后包含另一个 makefile(假定将 PRODUCT_MAKEFILES
定义为非空的东西,可能附加东西)。然后它扩展为任何内容,然后是最后两个 eval
命令清除这两个变量并扩展为空。因此,最终结果将是 $(PRODUCT_MAKEFILES)
中定义的任何内容,如 AndroidProducts.mk 中定义的那样,而该变量本身实际上不再被设置。然后它对其进行排序(sort
命令——它在排序后顺便删除了重复的单词),这就是整个事情的结果——这就是 all_product_configs
设置的内容。
如果 call
命令中有多个 makefile,这会更有趣。然后它将最终读取所有这些并提取它们在 PRODUCT_MAKEFILES
中定义的所有内容,连接并排序很多。
我正在尝试了解AOSP 的Makefile 语法和Makefile 系统。但是,这对像我这样的初学者来说很难。我了解 fereach 函数的工作原理,但不了解何时与 eval 函数一起使用,如下所示。有人可以解释下面的 Makefile 代码吗?它是如何一步步工作的以及每一步的输出? all_product_configs
变量的最终值?非常感谢!
all_product_configs := $(call get-product-makefiles,\
$(SRC_TARGET_DIR)/product/AndroidProducts.mk)
这是 get-product-makefiles
函数的定义:
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
eval
接受它的参数并将其评估为 Makefile 语法——变量和规则的定义,以及任何其他 GNUmake 语法——然后展开为空(一个空字符串)
foreach
接受它的第三个参数,并为第二个参数中的每个单词重复一次,第一个参数每次都被定义为相应的单词。结果是那个(大)字符串。
call
将其第一个参数作为变量名,并使用 $(1)
、$(2)
等扩展该变量,并将其设置为 call
的其他参数
所以从顶部开始,您展开 get-product-makefiles
并将 $(1)
设置为 $(SRC_TARGET_DIR)/product/AndroidProducts.mk
这实际上是 foreach 的第二个参数,并且只有一个词,所以 foreach
将扩展第三个参数一次,$(f)
设置为该字符串 ($(SRC_TARGET_DIR)/product/AndroidProducts.mk
)。所以这只是
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(SRC_TARGET_DIR)/product/AndroidProducts.mk))) \
$(eval include $(SRC_TARGET_DIR)/product/AndroidProducts.mk) \
$(PRODUCT_MAKEFILES) \
所以它运行那些定义那些变量(PRODUCT_MAKEFILES
和 LOCAL_DIR
)的评估,然后包含另一个 makefile(假定将 PRODUCT_MAKEFILES
定义为非空的东西,可能附加东西)。然后它扩展为任何内容,然后是最后两个 eval
命令清除这两个变量并扩展为空。因此,最终结果将是 $(PRODUCT_MAKEFILES)
中定义的任何内容,如 AndroidProducts.mk 中定义的那样,而该变量本身实际上不再被设置。然后它对其进行排序(sort
命令——它在排序后顺便删除了重复的单词),这就是整个事情的结果——这就是 all_product_configs
设置的内容。
如果 call
命令中有多个 makefile,这会更有趣。然后它将最终读取所有这些并提取它们在 PRODUCT_MAKEFILES
中定义的所有内容,连接并排序很多。