给定Makefile的这一位:
# for pattern matching
$(OBJDIR) := build
# just to see if a level of indirection will work
my_dir = $(dir $(1))
$(OBJECTS) : $(OBJDIR)/% : $(HEADERS) $(SRCDIR)/% | % $(dir %) $(call my_dir,%)
@echo output-only = $|
这是一个静态模式规则,具有仅限顺序的先决条件。
考虑目标"build/putility/debug.js"。上面规则的输出是:
output-only = utility/debug.js ./
- 第一个组件"utility/debug.js"是从stem(%)中正确复制的
- 第二个组件"./"是调用先决条件列表中的
dir
函数的输出 - 第三个组件是一个空字符串,它是调用先决条件列表中的
my_dir
函数的输出
如果我将my_dir
更改为:
my_dir = $(1)
输出保持不变。如果我把它改成这个:
my_dir = "foo"
然后make抱怨没有规则生成"foo"(这是预期的)。那么,在对my_dir
的调用中,$(1)
似乎没有被绑定。
怎么回事?为什么我不能将词干传递给函数?我有一个使用二次扩展的解决方法,但我想知道为什么我不能用这种方式编写规则。
编辑:我是stackoverflow的新手,如果这里不是这样做的,请原谅我。
正如Alex所指出的,我想要$(1),因为我将词干作为参数传递给my_dir
。
我不知道为什么有人建议我要"$"。我不相信美元本身会在任何情况下扩展到任何东西。
我知道自动变量只在配方中可用。我没有在先决条件中使用自动变量-我使用的是词干:
每个目标都与目标模式相匹配,以提取目标名称的一部分,称为词干。这个词干被替换到每个prereq模式中,以形成先决条件名称(每个preeq模式中有一个)。-手动
这个例子证明了词干是可用的:当单独使用时,词干会扩展到正确的值,但当传递给函数时则不会。
正如GNU make手册的这一部分所示,在读入阶段,先决条件列表中的变量和函数引用会立即展开。这意味着,在进行任何模式匹配之前,%
还没有特殊意义;它被解释为两个函数引用$(dir %)
和$(call my_dir,%)
中的文字字符,这两个函数的结果都是./
,它们被合并到配方中对$|
的引用中。
除了您已经找到的解决方案,即二次扩展,我不知道还有其他解决方案。
注意$1
不是一个特殊的变量,它可以扩展到与模式规则(或静态模式规则)相关的任何有趣的内容。$1
变量仅在$(call ...)
函数调用的用户定义宏的上下文中具有唯一行为。
您希望使用$*
,而不是$1
;$*
是一个自动变量,它扩展到规则目标的词干。
然而,在所有版本的make(包括make的POSIX标准定义)中,自动变量(包括$*
、$<
、$@
、$^
等)仅在配方的上下文中可用。它们在目标或先决条件列表中不可用。有关更多详细信息,请参阅GNU make手册中关于自动变量的部分。
正如您所建议的,有一个GNU特定于make的功能是由.SECONDEXPANSION伪目标启用的,它提供了一种避免这种限制的方法。