GNU Make的多通配符模式规则

29

我想写类似正则表达式的东西:

SRC:="a.dat.1 a.dat.2"    
$(SRC): %.dat.%: (\\1).rlt.(\\2)    
      dat2rlt $^ $@

为了让 a.dat.1a.dat.2 分别对应 a.rlt.1a.rlt.2,有什么方法可以在GNU Make中做到“%只能使用一次”吗?


不,这个缺失了。一个解决方法是动态添加规则(使用eval或include)。请参见例如这个相关问题这个问题 - reinierpost
4个回答

19

很抱歉,您尝试以所建议的方式进行的操作是不可能的,因为-正如您已经提到的那样-(GNU) make仅允许一个单一的通配符'%', 请参见http://www.gnu.org/software/make/manual/make.html#Pattern-Rules:

 

模式规则看起来像普通规则,只是它的目标包含字符'%'(确切地说只有一个)。

如果没有它,创建这样的“多维”目标会很麻烦。

解决此问题的一种方法是在命令中重建依赖项的名称(而不是在依赖项列表中):

SRC := a.dat.1 a.dat.2

all : $(SRC:%=%.dat2rlt)

%.dat2rlt :
    dat2rtl $(word 1,$(subst ., ,$*)).rlt.$(word 2,$(subst ., ,$*)) $*

当然,这样做会失去依赖性,一旦rlt被更新,它就不会重新构建。

我唯一能想到的解决方法是显式地生成规则:

SRC := a.dat.1 a.dat.2

all : $(SRC)

define GEN_RULE
$1.dat.$2 : $1.rlt.$2
    dat2rtl $$< $$@
endef

$(foreach src,$(SRC),$(eval $(call GEN_RULE,$(word 1,$(subst ., ,$(src))),$(word 3,$(subst ., ,$(src))))))

6
使用命名变量,我们可以编写更易读的代码(基于Paljas的答案):
letters:=a b c
numbers:=1 2 3 4

define GEN_RULE
$(letter).dat.$(number) : $(letter).rlt.$(number)
    ./rlt2dat $$< $$@
endef

$(foreach number,$(numbers), \
  $(foreach letter,$(letters), \
    $(eval $(GEN_RULE)) \
  ) \
)

我们可以以类似的方式生成SRC。请注意,使用这种方法,SRC将包含所有组合。这可能有利也可能无益。

1

在 Erzsébet Frigó 的答案基础上,你可以选择:

  • 在内部循环中,eval 不是宏本身,而是调用它的结果
  • 将宏命名为所调用程序的名称 dat2rtl
  • 结合使用,允许你
    • 使用 make 的 ${0} 引用程序名称
    • 定义一个目标 ${0}s(扩展为 dat2rts - 注意复数形式),前提条件是所有字母和数字的组合都需要先调用 dat2r2

像这样:

letters:=a b c
numbers:=1 2 3 4

define rlt2dat
${0}s::$(letter).dat.$(number)
$(letter).dat.$(number): $(letter).rlt.$(number)
    ./${0} $$< $$@
endef

$(foreach number,$(numbers), \
  $(foreach letter,$(letters), \
     $(eval $(call rlt2dat))))

您可以使用以下命令构建所有rlt2dat目标:

make rlt2dats


该命令将帮助您完成相关的IT技术操作。

-2

对于你提供的有限示例,你可以使用一个%的模式。

SRC := a.dat.1 a.dat.2
${SRC}: a.dat.%: a.rlt.%    
      dat2rlt $^ $@
  1. 食谱中的$*将扩展为与%匹配的任何内容。
  2. 请注意,您原始宏周围的"肯定是错误的。
  3. 查看手册中的.SECONDEXPANSION以获取更复杂的内容(或在这里)。

抱歉,也许这个例子不够全面,但我想涵盖b.dat.1、b.dat.2。 - heroxbd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接