hoey@nrl-aic.ARPA (Dan Hoey) (03/21/85)
In <177@osiris.UUCP> eric@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@cyb-eng.UUCP (Howard Johnson) and greg@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