I know that I can use the following syntax to use pattern-matching in make
rules:
%.csv : %.tsv
tsv2csv $< $@
However, it seems this doesn't work, if the whole target should be matched:
While
%.csv : %.csv.gz
zcat $< > $@
and
%.tsv : %.tsv.gz
zcat $< > $@
work fine,
% : %.gz
zcat $< > $@
doesn't.
I know that for this particular example I could use
%sv : %sv.gz
zcat $< > $@
but just imagine I also want to use the same rule to get uncompressed copies of *.txt
files.
Is there a reason why this isn't (and/or shouldn't be) possible and if not, how can I achieve that in (GNU
) make
?
I guess this is a common need (for examle to compile foo.c
to foo
) but I didn't find anything neither on SO, nor elsewhere (web search).
Addendum:
As pointed out in the comment/answer my minimal example above work just fine.
In my larger Makefile, however, it doesn't.
I figured out that this seems to be triggered by a second level of pattern-matching.
Consider the following 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 $< > $@
I created some dummy input files using
touch testA.txt testB.txt
gzip testA.txt testB.txt
If I run make -n
I get
zcat testA.txt.gz > testA.txt
ln -s testA.txt testA
zcat testB.txt.gz > testB.txt
ln -s testB.txt testB
Using pattern rules, I can shorten the above Makefile to
all : testA testB
testA : testA.txt
ln -s $< $@
testB : testB.txt
ln -s $< $@
%.txt : %.txt.gz
zcat $< > $@
Using make -n
on this version, I still get the same output as before.
I now found out that I can also shorten it to
all : testA testB
testA : testA.txt
ln -s $< $@
testB : testB.txt
ln -s $< $@
% : %.gz
zcat $< > $@
or
all : testA testB
% : %.txt
ln -s $< $@
testA.txt : testA.txt.gz
zcat $< > $@
testB.txt : testB.txt.gz
zcat $< > $@
So the whole target matching the wildcard (%
) was not the problem.
I cannot, however, combine the above simplifications in one Makefile:
all : testA testB
% : %.txt
ln -s $< $@
% : %.gz
zcat $< > $@
This Makefile results in the following output of make -n
:
make: *** No rule to make target `testA', needed by `all'. Stop.
I thought that make
might have a problem with two pattern rules having the wildcard as the whole target (even though I think it would be possible; at least in this case).
That's why I also tried the following version:
all : testA testB
% : %.txt
ln -s $< $@
%.txt : %.txt.gz
zcat $< > $@
To my surprise, this was accepted by make
.
Unfortunately, I need something like this:
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 $< > $@
I created test input using
touch testA.txt testB.txt testA.tsv testB.tsv
gzip testA.txt testB.txt testA.tsv testB.tsv
and running make -n
returns
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
Taking the above observations together, I can shorten this to
all : testA.csv testB.csv
%.csv : %.txt %.tsv
tsv2csv $^ $@
%.txt : %.txt.gz
zcat $< > $@
%.tsv : %.tsv.gz
zcat $< > $@
but not to this:
all : testA.csv testB.csv
%.csv : %.txt %.tsv
tsv2csv $^ $@
% : %.gz
zcat $< > $@
What is the reason for this behaviour of make
and is there a way to change that?