6

I thought this is quite simple

%.png: ../figs/%.png
        convert $? -resize '40%' $@

That is, I want to generate an image in this directory from the corresponding image in "../figs/" .

But, the above leads to an infinite chain of dependencies because ../figs/foo.png matches %.png and therefore make tries to check ../figs/../figs/foo.png, which matches %.png and therefore make tries to . . . Eventually, make stops with "File name too long".

I must be missing something. What is a clean solution?

Ryo
  • 317
  • 1
  • 7

3 Answers3

7

Kill the chain with an empty rule

%.png: ../figs/%.png
    convert $? -resize '40%' $@

../figs/%.png: ;
user657267
  • 20,568
  • 5
  • 58
  • 77
  • Thanks! That's perfect. Interestingly, GNU Make 3.81 that comes with Mac OS X still generates an infinite chain with your code, whereas GNU Make 4.2.1 which I separately installed does not. Does that mean that this problem was solved only recently? – Ryo Jul 29 '16 at 13:43
  • 1
    Looks like pattern rules were switched to shortest stem order in [3.82](http://git.savannah.gnu.org/cgit/make.git/tree/NEWS), you can work around this in 3.81 by putting the empty rule before the other one. – user657267 Jul 29 '16 at 13:50
4

All the answers above are quite interesting. However, I'll like to mention the terminal rule solution:

%.png:: ../figs/%.png
    convert $? -resize '40%' $@

By changing to a double colon ::, we then mark the prerequisites terminal:

One choice is to mark the match-anything rule as terminal by defining it with a double colon. When a rule is terminal, it does not apply unless its prerequisites actually exist. Prerequisites that could be made with other implicit rules are not good enough. In other words, no further chaining is allowed beyond a terminal rule.

Note: only suitable for match-anything rules.

davidhcefx
  • 130
  • 1
  • 8
1

user657267's solution is perfect. Another option is to use static pattern rules:

PNGS    := $(patsubst ../figs/%.png,%.png,$(wildcard ../figs/*.png))

all: $(PNGS)

$(PNGS): %.png: ../figs/%.png
    convert $< -resize '40%' $@

clean:
    rm -f $(PNGS)

Computing the list of all targets from the list of all prerequisites has several nice side effects, like the prossibility of adding the all and clean targets, for instance.

Community
  • 1
  • 1
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • 1
    Thanks! I already use a list of targets like your PNGS, but I didn't know that you can use the list to limit the application of the pattern (your 3rd non-empty line, with two colons). By the way, I use `$(notdir . . .)` function instead of `patsubst`. – Ryo Aug 05 '16 at 03:51