Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile pattern rule with two or more dependencies %.sas7bdat: %.sas %.dat

Tags:

makefile

I can't seem to find any examples of this online, and it doesn't seem to work for me. Can you have a pattern rule in a make file that has two matching dependencies?

For example

%.sas7bdat: %.sas %.dat
  # build %.sas7bdat using %.sas and %.dat

Specifically, if I run make, it states...

make: *** No rule to make target `sip84fp.sas7bdat', needed by `sipp84'.  Stop.

Even though the rule is clearly defined as above.

However, reducing the rule to this...

%.sas7bdat: %.sas

seems to work?

like image 211
Ben Southgate Avatar asked Mar 17 '23 03:03

Ben Southgate


1 Answers

Yes, both static pattern rules and implicit pattern rules can have multiple prerequisites that contain a % reference to the pattern stem.

Implicit pattern rules are different from static pattern rules, or ordinary non-pattern rules in that they only apply when they either have no prerequisites ("unconditionally make this thing") or else the prerequisites exist.

That is to say, if a target that needs to be built, like sip84fp.sas7bdat needs to be updated, then indeed the pattern rule %.sas7bdat: %.sas %.dat is a candidate. But a check is made: the sip84fp stem is inserted into the prerequisite patterns to generate sip84fp.sas sip84fp.dat. These both have to exist. If they do not exist, then the rule is removed from consideration, and the search continues for some other rule.

This is why in the end you get a message about "no rule": it really means that no rule was left after ignoring all the implicit rules that didn't apply.

By contrast, under a static pattern rule or ordinary rule, if a target matches a rule, and a prerequisite doesn't exist, the prerequisite must be updated. For instance if you have foo.o: foo.c and foo.c doesn't exist, the rule cannot be thrown away because it's not implicit: that rule must be used for foo.o. Make will then look for a rule which builds foo.c (and probably not find one: the error will then be that there is no rule to make foo.c, not foo.o).

See the topic Implicit Rule Search Algorithm in the GNU Make Manual.

If it is an expected behavior that the .dat file might not exist, you have to express that in some other way. For instance, one way is to use some external dependency generation to make numerous concrete rules of the form:

foo.sas7bdat: foo.dat

Put that into a foo.d file, and include it into the Makefile. If you have a variable called TARGETS which holds the names of all .sas7bdat files, you can include all their .d dependency files like this:

-include $(patsubst %.sas7bdat,%.d,$(TARGETS))

This is the same as for compiling C. We wouldn't write a pattern rule like this for C programs:

%.o: %.c %.h
        # ... build steps

This is because not every foo.c has a foo.h, and so the rule would not apply to such cases. Rather, we have:

%.o: %.c

and then any additional dependencies, like foo.o depending on foo.h are expressed elsewhere. The implicit rule only matches the principal deliverables: the object file and the "root" file of the translation unit.

like image 197
Kaz Avatar answered Apr 25 '23 15:04

Kaz