Makefile 如何在通配符(%)匹配整个目标的情况下定义生成规则?
我知道我可以使用以下语法在Makefile 如何在通配符(%)匹配整个目标的情况下定义生成规则?,makefile,wildcard,gnu-make,Makefile,Wildcard,Gnu Make,我知道我可以使用以下语法在make规则中使用模式匹配: %.csv:%.tsv tsv2csv$
make
规则中使用模式匹配:
%.csv:%.tsv
tsv2csv$<$@
但是,如果要匹配整个目标,这似乎不起作用:
当
%.csv:%.csv.gz
zcat$<>$@
及
%.tsv:%.tsv.gz
zcat$<>$@
干得好
%:%.gz
zcat$<>$@
没有
我知道对于这个特殊的例子,我可以使用
%sv:%sv.gz
zcat$<>$@
但是想象一下,我也想使用相同的规则来获取*.txt
文件的未压缩副本
有没有理由不可能(和/或不应该)这样做?如果没有,我如何在(GNU
)make
中实现这一点
我想这是一个常见的需求(例如编译foo.c
到foo
),但我没有在上面或其他地方找到任何东西(web搜索)
附录:
正如上面的评论/我的最小示例中所指出的那样,效果很好
然而,在我更大的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:**没有规则将目标设为'testA',这是'all'所需要的。停止
我认为,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$<>$@
我使用
触摸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
的这种行为的原因是什么?有没有办法改变这种行为?我不确定您是如何执行make
命令的,但是下面的命令序列对我有效
生成文件:
% : %.gz
zcat $< > $@
GNU make对目标为
%
的规则的处理方式不同,如中所述
您可能可以通过巧妙地放置双冒号来使用您的规则,可能是基于以下规则:
% :: %.gz
你想做的应该行得通。如果没有,你应该提供一个实际的不起作用的例子,包括makefile、你键入的命令和你得到的结果。@MadScientist:很抱歉这个坏例子,我希望新的信息是有用的。谢谢你的快速回答,也很抱歉在发布之前没有测试我的MWE。我发现它最终太小而无法工作。请查看新信息以重现问题。@sg lecram,不寻常的是错误消息是:`没有规则生成目标
testA.csv'
,而不是抱怨无法生成部件。关于错误消息,我认为这是由于make
处理基于模式的规则的方式造成的。好了,第一条可以使用的规则被使用了。因此,make
扫描了第一条规则,以及如果有零件或规则来制作这些零件,testA.csv
可以这样做的原因。由于make
似乎无法生成零件,因此该规则被忽略,并且make
继续寻找另一个与testA.csv
匹配的规则,因为既没有文件名testA.csv.gz
也没有生成该规则,第二条规则也被跳过。由于没有留下任何规则,make
得出结论,因此没有规则
% :: %.gz