我试图理解以下递归目标以及为什么这样做:
顶级 makefile 和目标:
collect:
file_list="file_list.txt"
for makefile in $(ALL_PROJECTS) ; do \
$(MAKE) -s -f $$(basename $$makefile) --directory=$$(dirname $$makefile) GetDependenciesFile RELATIVE_DIR="$$(dirname $$makefile)" DEPENDENCIES_FILE="file_list"; \
done;
包含我试图理解的递归目标的Makefile:
.PHONY: GetDependenciesFile
$(if $(filter GetDependenciesFile, $(.OVERRIDEN)),OVERRIDEN,) GetDependenciesFile: DependenciesFile.tmp
ifeq ("$(DEPENDENCIES_FILE)","")
echo "DEPENDENCIES_FILE is not specified"
else
cat DependenciesFile.tmp >> $(DEPENDENCIES_FILE)
endif
DependenciesFile.tmp:
echo "$(ALL_DEPENDENCIES)" >> DependenciesFile.tmp
这是我正在处理的事情的简化版本(我删除了
sed
和其他明显的步骤,例如排序和删除重复项)。
我理解目标是遍历
$(ALL_PROJECTS)
中包含的所有makefile,并在每个makefile中将变量$(ALL_DEPENDENCIES)
的内容附加到DependenciesFile.tmp
,然后将其内容附加到$(DEPENDENCIES_FILE)
,即file_list.txt
从顶层目标开始。
我不明白的是这一行:
$(if $(filter GetDependenciesFile, $(.OVERRIDEN)),OVERRIDEN,) GetDependenciesFile: DependenciesFile.tmp
我尝试在 makefile 中 grep
OVERRIDEN
但找不到任何东西。
我不明白评估 if
的结果时发生了什么以及为什么将其放在目标名称之前。
有什么建议吗?
我理解目标是遍历
,中包含的所有makefile$(ALL_PROJECTS)
这确实是它实际所做的,至少是这样。
并在每个 makefile 中将变量
的内容附加到$(ALL_DEPENDENCIES)
,DependenciesFile.tmp
是的。
将其内容附加到
$(DEPENDENCIES_FILE)
是的。
与顶级目标相比
。file_list.txt
否。 基于顶级目标中的
DEPENDENCIES_FILE="file_list"
,目标文件仅命名为 file_list
。
我不明白的是这一行:
$(if $(filter GetDependenciesFile, $(.OVERRIDEN)),OVERRIDEN,) GetDependenciesFile: DependenciesFile.tmp
$(if ...)
是一个GNU make
“函数”,它根据其中的参数有条件地扩展(函数和函数扩展是标准make
的GNU扩展)。 语法是:
$(if condition,then-part[,else-part])
如果去掉前面和后面的空格然后扩展剩下的内容会产生非空字符串,则
condition
部分被认为是 true。 在这种情况下,将评估 then-part
以产生 if
的扩展。 否则,将评估 else-part
以生成扩展,其中不提供条件的该部分相当于提供空字符串。
在您的情况下,条件是
$(filter GetDependenciesFile, $(.OVERRIDEN))
,then 部分是 OVERRIDEN
,else 部分(明确)为空。
$(filter ...)
是另一个GNU make
函数。 语法是:
$(filter pattern...,text)
,其中模式以 GNU
make
特有的语法来表达。效果是在空格上分割 text
,并扩展到与任何指定模式匹配的所有结果单词,并通过空格连接。
在您的情况下,只给出了一种模式,
GetDependenciesFile
。 要过滤的文本是make
变量.OVERRIDEN
的扩展。 因此,如果 GetDependenciesFile
作为整个单词出现在 $(.OVERRIDEN)
的值中,则
$(filter)
表达式扩展为 GetDependenciesFile
,$(if)
的条件为真,所以OVERRIDEN
。否则,
$(filter)
扩展为空,$(if)
条件为假,所以$(if)
扩展为空。我不明白评估
的结果时发生了什么以及为什么将其放在目标名称之前。if
常规
make
规则可以有多个目标,表示为空格分隔的列表。 当 if
扩展为除空白之外的任何内容时,它会被解释为该规则的一个或多个附加目标。
具有多个目标的规则表示每个指定的目标取决于所有指定的先决条件,并且可以通过给定的配方单独构建它。 因此,当您的
$(if)
扩展到 OVERRIDEN
时,结果是 GetDependenciesFile
的规则也可以用于构建名为 OVERRIDEN
的目标。
该配方实际上并不创建具有任一名称的文件,因此除非通过其他方式创建此类文件,否则每个目标都将始终被视为过时。 我最好的猜测是,其目的是允许配方与某些 makefile 一起执行两次,一次针对目标
GetDependenciesFile
,一次针对目标 OVERRIDEN
,而它最多与其他 makefile 一起执行一次。