我正在尝试在我的 makefile 中使用 canned Recipes 为我的项目中的几个子目录动态定义菜谱。然而,我定义的变量并没有像我期望的那样扩展:
define project
$(1)_dir := $(realpath $(2))
.PHONY: $(1)
$(1):
$(info $(1)_dir = "$($(1)_dir)")
endef
$(eval $(call project,hello_world,./hello-world))
我希望当我运行
hello_world_dir = "/path/to/hello-world"
时,上面的 makefile 会打印 make hello_world
。但是,它会打印 hello_world_dir = ""
。我不明白为什么当变量名被正确替换时嵌套扩展无法正常工作。
我不明白为什么当变量名被正确替换时嵌套扩展无法正常工作。
这是一个时间问题。
$(call)
只是一种扩展变量的奇特方式。当您使用它来扩展变量 project
时,其中的所有变量和函数引用也会扩展。此时, $(1)
是对 call
提供的临时变量的引用,因此 $(1)_dir
会按您的预期展开,无论它出现在 project
的值中的任何位置。该变量的赋值也被正确扩展,但此时它只是文本。此时 $(info ...)
也被扩展,但尚未定义变量 hello_world_dir
——直到结果被 $(eval)
ed 时才会发生这种情况。 $(info)
的输出正确地反映了当时 $(hello_world_dir)
扩展为空。
首先,帮自己一个忙,扔掉内部嵌入的
$(info)
。除了与扩展有关的时间问题之外,它还存在内容问题:它会扩展为空,从而使您的规则hello_world_dir
的配方仅包含空命令。如果您希望规则在运行时显示文本,请在其中使用 echo
命令。
其次,在规则的配方运行之前您不希望扩展的任何内容都需要通过
$(call)
来防止扩展。更简单的方法之一是将 $
符号加倍来引用。
总的来说,你可能会得到这样的结果:
define project
$(1)_dir := $(realpath $(2))
.PHONY: $(1)
$(1):
@echo '$(1)_dir = "$$($(1)_dir)"'
endef
$(eval $(call project,hello_world,./hello-world))
当然,请确保
./hello-world
实际上指定了现有文件或目录。