Erik Bennett
Erik Bennett

Reputation: 1089

GNUMake trouble with implicit rules

I'm missing something about implicit rules. Here's the Makefile (GNU Make 4.2.1)

heimdall /tmp 1670> cat Makefile

PARTS= a b c

.SECONDEXPANSION:

data/events2: $$(patsubst %,$$(@D)/%.ppd,$(PARTS))
        /bin/ls -l $^

%/events2: $$(patsubst %,$$(@D)/%.ppd,$(PARTS))
        /bin/ls -l $^

Here are the cooked up data to illustrate the situation:

heimdall /tmp 1671> ls -1 data data1
data:
a.ppd
b.ppd
c.ppd

data1:
a.ppd
b.ppd
c.ppd

Here is make using an explicit rule, which works like I'd expect.

heimdall /tmp 1672> make data/events2
/bin/ls -l data/a.ppd data/b.ppd data/c.ppd
-rw-rw-r-- 1 bennett None 0 Feb  4 12:19 data/a.ppd
-rw-rw-r-- 1 bennett None 0 Feb  4 12:19 data/b.ppd
-rw-rw-r-- 1 bennett None 0 Feb  4 12:19 data/c.ppd

And finally, this:

heimdall /tmp 1673> make data1/events2
make: *** No rule to make target 'data1/events2'.  Stop.

Why doesn't the implicit rule match? I feel like I've missed something fundamental.

Thanks.

-E

Upvotes: 0

Views: 86

Answers (1)

Ondrej K.
Ondrej K.

Reputation: 9664

%/events2: $$(patsubst %,$$(@D)/%.ppd,$(PARTS))

Is not a pattern rule that would match in your sample structure. From the docs:

% in a prerequisite of a pattern rule stands for the same stem that was matched by the % in the target. In order for the pattern rule to apply, its target pattern must match the file name under consideration and all of its prerequisites (after pattern substitution) must name files that exist or can be made. These files become prerequisites of the target.

However in your target % would be matching data1. But there isn't actually any % to match on prerequisite side as those present are oft patsubst function and directory (stem) is referred to as $(@D).

I've tried to write such rule like this using foreach function:

%/events2: $(foreach part,$(PARTS), %/$(part).ppd)
        /bin/ls -l $^

If you wanted to stick with patsubst, this should work as well:

%/events2: $(patsubst %,\%/%.ppd,$(PARTS))
        /bin/ls -l $^

Not that % is used for directory name matching the one in target and it's escaped with \ to make it through patsubst unscathed.

Either way seems to have gone well with GNU make yielding:

$ make data1/events2
/bin/ls -l data1/a.ppd data1/b.ppd data1/c.ppd
-rw-r--r-- 1 ondrej users 0 Feb  4 22:00 data1/a.ppd
-rw-r--r-- 1 ondrej users 0 Feb  4 22:00 data1/b.ppd
-rw-r--r-- 1 ondrej users 0 Feb  4 22:00 data1/c.ppd

Upvotes: 1

Related Questions