如何定义一个Make规则,整个目标与通配符(%)匹配?

时间:2014-04-28 09:10:53

标签: makefile wildcard gnu-make

我知道我可以使用以下语法在make规则中使用模式匹配:

%.csv : %.tsv
  tsv2csv $< $@

然而,如果整个目标应该匹配,似乎这不起作用:

虽然

%.csv : %.csv.gz
  zcat $< > $@

%.tsv : %.tsv.gz
  zcat $< > $@

工作正常,

% : %.gz
  zcat $< > $@

我知道对于这个特例,我可以使用

%sv : %sv.gz
  zcat $< > $@

但想象一下,我也想使用相同的规则来获取*.txt个文件的未压缩副本。

是否存在(和/或不应该)可能的原因,如果没有,我如何在(GNUmake中实现这一目标?

我想这是一个常见的需求(例如将foo.c编译为foo),但我在SO或其他地方(网络搜索)都找不到任何内容。

附录

正如评论/ answer中所指出的,我上面的最小例子工作得很好。

然而,在我较大的Makefile中,它没有。

我发现这似乎是由第二级模式匹配引发的。

考虑以下Makefile:

all : testA testB

testA : testA.txt
  ln -s $< $@

testB : testB.txt
  ln -s $< $@

testA.txt : testA.txt.gz
  zcat $< > $@

testB.txt : testB.txt.gz
  zcat $< > $@

我使用

创建了一些虚拟输入文件
touch testA.txt testB.txt
gzip testA.txt testB.txt

如果我运行make -n,我会

zcat testA.txt.gz > testA.txt
ln -s testA.txt testA
zcat testB.txt.gz > testB.txt
ln -s testB.txt testB

使用模式规则,我可以将上面的Makefile缩短为

all : testA testB

testA : testA.txt
  ln -s $< $@

testB : testB.txt
  ln -s $< $@

%.txt : %.txt.gz
  zcat $< > $@

在此版本上使用make -n,我仍然可以获得与之前相同的输出。

我现在发现我也可以将它缩短为

all : testA testB

testA : testA.txt
  ln -s $< $@

testB : testB.txt
  ln -s $< $@

% : %.gz
  zcat $< > $@

all : testA testB

% : %.txt
  ln -s $< $@

testA.txt : testA.txt.gz
  zcat $< > $@

testB.txt : testB.txt.gz
  zcat $< > $@

所以匹配通配符(%)的整个目标不是问题。

但是,我不能将上述简化结合在一个Makefile中:

all : testA testB

% : %.txt
  ln -s $< $@

% : %.gz
  zcat $< > $@

此Makefile导致make -n的以下输出:

make: *** No rule to make target `testA', needed by `all'.  Stop.

我认为make可能存在两个模式规则的问题,即将通配符作为整个目标(尽管我认为这是可能的;至少在这种情况下)。

这就是我尝试以下版本的原因:

all : testA testB

% : %.txt
  ln -s $< $@

%.txt : %.txt.gz
  zcat $< > $@

令我惊讶的是,这被make接受了。

不幸的是,我需要这样的东西:

all : testA.csv testB.csv

testA.csv : testA.txt testA.tsv
  tsv2csv $^ $@

testB.csv : testB.txt testB.tsv
  tsv2csv $^ $@

testA.txt : testA.txt.gz
  zcat $< > $@

testB.txt : testB.txt.gz
  zcat $< > $@

testA.tsv : testA.tsv.gz
  zcat $< > $@

testB.tsv : testB.tsv.gz
  zcat $< > $@

我使用

创建了测试输入
touch testA.txt testB.txt testA.tsv testB.tsv
gzip testA.txt testB.txt testA.tsv testB.tsv

并运行make -n返回

zcat testA.txt.gz > testA.txt
zcat testA.tsv.gz > testA.tsv
tsv2csv testA.txt testA.tsv testA.csv
zcat testB.txt.gz > testB.txt
zcat testB.tsv.gz > testB.tsv
tsv2csv testB.txt testB.tsv testB.csv

综合上述观察,我可以将其缩短为

all : testA.csv testB.csv

%.csv : %.txt %.tsv
  tsv2csv $^ $@

%.txt : %.txt.gz
  zcat $< > $@

%.tsv : %.tsv.gz
  zcat $< > $@

但不是这样:

all : testA.csv testB.csv

%.csv : %.txt %.tsv
  tsv2csv $^ $@

% : %.gz
  zcat $< > $@

make这种行为的原因是什么,有没有办法改变它?

2 个答案:

答案 0 :(得分:1)

目标为%的规则受到GNU make的不同处理,如http://www.gnu.org/software/make/manual/make.html#Match_002dAnything-Rules

中所述

您可能可以通过智能放置双冒号来制定规则,或许可以遵守此规则:

% :: %.gz

答案 1 :(得分:0)

我不确定您是如何尝试执行make命令的,但以下命令序列对我有用。

生成文件:

% : %.gz
    zcat $< > $@

命令:

touch foo.txt
gzip foo.txt   # Creates foo.txt.gz
make foo.txt   # Produces foo.txt again.