Multi-step implicit rules for make(1)

Dan Hoey hoey at nrl-aic.ARPA
Thu Mar 21 09:48:50 AEST 1985


In <177 at osiris.UUCP> eric at osiris.UUCP (Eric Bergan) has a problem with
make's use of implicit rules.  An example of the problem can be seen
with a makefile like

    .SUFFIXES: .D .C .B .A

    CONVERT_A_TO_B=cp
    CONVERT_B_TO_C=cp
    CONVERT_C_TO_D=cp

    .A.B:
	    $(CONVERT_A_TO_B) $< $@
    .B.C:
	    $(CONVERT_B_TO_C) $< $@
    .C.D:
	    $(CONVERT_C_TO_D) $< $@

    all:    foo.D

Executed in a directory with only makefile and foo.A, this make will
complain that it doesn't know how to make foo.D.

As both howard at cyb-eng.UUCP (Howard Johnson) and greg at ncr-tp.UUCP (Greg
Noel) have pointed out, the problem is that for an implicit make rule
".A.B" to be invoked foo.A must either exist or be mentioned as a
target or dependent in some rule.  Thus the problem can be circumvented
by the addition of the dependency
    foo.D: foo.B foo.C
or even
    foo.C: foo.B
in the makefile.  One problem with adding lines like this is that they
must be added for bar.D, baz.D, ad infinitum.  Another problem is that
the methods fool make's error handling.  If we instead add the line
    foo.D: foo.B
make will create only foo.B, with no complaints.  The problem is that
it treats "foo.D" as a target like "all" in this case, not as a file
that must be created.

We now turn to methods for getting make to use implicit rules to create
foo.D.  Both Howard and Greg propose adding a rule like
    .A.D:
	    $(CONVERT_A_TO_B) $< $*.B
	    $(CONVERT_B_TO_C) $*.B $*.C
	    $(CONVERT_C_TO_D) $*.C $@
(their solutions are identical except for Greg's cleanup line
	    rm -f $*.B $*.C
) to the makefile.  In this case, with four suffixes involved, we might
want to also add rules for .A.C: and .B.D:.  I find these methods
unsatisfactory because of the proliferation of the information about
the commands used for converting one object into another.  For
instance, if the procedure for $(CONVERT_B_TO_C) took the arguments in
the opposite order, we would have to change the information in two or
three rules.

I would suggest that the rules to be added should tell make to
use the previously defined implicit rules, for example
    .A.D .B.D:
	    @make $(MFLAGS) $*.C $@
	    rm -f $*.C
    .A.C:
	    @make $(MFLAGS) $*.B $@
	    rm -f $*.B
There are a few things to watch out for here.  For one thing, the
inclusion of $(MFLAGS) does not pass all of make's invocation to the
subsidiary make.  If you expect to invoke this script as, for instance
``make CONVERT_B_TO_C=mv'', you must set up the recursive invocations to
say ``@make CONVERT_B_TO_C=$(CONVERT_B_TO_C) $(MFLAGS) ...''.  It is
clear this could get out of hand.  And if you like to try things out
with ``make -f fakefile'' you had better forget this approach entirely.

Another thing to watch out for is the ordering of ".SUFFIXES:".  The
dependents of .SUFFIXES must be in reverse temporal order for this to
work.  Since lines like ".SUFFIXES: .A" append to the list of suffixes,
this is sufficient if you want to add preprocessors to your source
files.  If you want to add postprocessors to targets already known to
make, be sure to start with a ``.SUFFIXES:'' line with no dependents.

It would of course be nicer if we could get make to know how to
recursively apply its own implicit rules as it does for explicit rules,
but I suppose there are problems with that.

Dan Hoey
Navy Center for Applied Research in Artificial Intelligence



More information about the Comp.unix.wizards mailing list