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?

有帮助吗?

解决方案

Rules with a target of % are treated differently by GNU make, as explained in http://www.gnu.org/software/make/manual/make.html#Match_002dAnything-Rules

You might be able to get your rules to work with a smart placing of a double colon, perhaps on this rule:

% :: %.gz

其他提示

I am not sure how you are trying to execute the make command, but the following sequence of commands works for me.

Makefile:

% : %.gz
    zcat $< > $@

Commands:

touch foo.txt
gzip foo.txt   # Creates foo.txt.gz
make foo.txt   # Produces foo.txt again.
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top