Path: utzoo!attcan!uunet!mcvax!hp4nl!philmds!leo From: leo@philmds.UUCP (Leo de Wit) Newsgroups: comp.lang.c Subject: Re: Recursive #includes Keywords: recursive includes, modularity Message-ID: <969@philmds.UUCP> Date: 2 Mar 89 11:40:30 GMT References: <570@marob.MASA.COM> <9727@smoke.BRL.MIL> <964@philmds.UUCP> <9736@smoke.BRL.MIL> Reply-To: leo@philmds.UUCP (Leo de Wit) Organization: Philips I&E DTS Eindhoven Lines: 124 In article <9736@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) ) writes: |In article <964@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: |>In article <9727@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) ) writes: |>|It's easy to get the Makefile correct; just declare that a header |>|depends on the others that it #includes. |>This is not correct, as it is never correct to declare make dependencies |>between source files (this includes header files as well). | |Sorry, but it IS technically correct. Dependence is a transitive |property. The only practical problem you could run into here occurs |when your version of "make" barfs on cyclic dependencies caused by |mutually-dependent headers. If you don't have recursion among the |headers, though, you should be safe. Not so. You always have a problem. If I may quote from S.I.Feldman's 'Make - A Program for Maintaining Computer Programs': (section Description Files and Substitutions) " A dependency line may have either a single or a double colon. A target " name may appear on more than one dependency line, but all of those " lines must be of the same (single or double colon) type. " " 1. For the usual single-colon case, at most one of these dependency " lines may have a command sequence associated with it. If the " target is out of date with any of the dependents on any of the " lines, and a command sequence is specified (even a null one " following a semicolon or a tab), it is executed; otherwise a " default creation rule may be invoked. " " 2. In the double-colon case, a command sequence may be associated " with each dependency line; if the target is out of date with any " of the files on a particular line, the associated commands are " executed. A builtin-rule may also be executed. This detailed form " is of particular value in updating archive-type files. Note especially the last sentence of 1.: "otherwise a default creation rule may be invoked.". Although it might not be clear, the implicit rules are meant here (suffix dependencies). NOT a .DEFAULT rule, which is only invoked if a target must be made and no explicit rule has been specified and no implicit rules can be applied (an implicit rule can be applied when both suffixes appear in the .SUFFIXES list, the 'source suffix' file exists, and an implicit rule has been given for this pair of suffixes). I checked Ultrix's native make (/bin/make), its S5 make (/bin/s5make), our local make (a System III port, /usr/local/make) and Sun's make (from /usr/sunpro, the one that sorts out header dependencies and has lots of fancy stuff). They all behave this way, that is: invoking an implicit rule if a dependency 'to be updated' has no associated command sequence. A little demo to make things clear; because not all makes support SCCS, I don't use .h~.h rules; instead .h files are made dependent from .x files, and the .x file copied to the .h if needed (of course in real a check to prevent clobbering an existing file would be added). (demo) Script started on Wed Mar 1 21:31:49 1989 (demo) philmds> cat makefile (demo) (demo) a.out : main.c inc1.h (demo) $(CC) main.c (demo) (demo) inc1.h : inc2.h (demo) (demo) .SUFFIXES : .h .x (demo) (demo) .x.h : (demo) cp $< $*.h (demo) (demo) philmds> cat main.c (demo) #include "inc1.h" (demo) (demo) main(){} (demo) philmds> cat inc1.h (demo) #include "inc2.h" (demo) philmds> cat inc2.h (demo) /* Nothing in here */ (demo) philmds> cp inc1.h inc1.x (demo) philmds> /bin/make (demo) cp inc1.x inc1.h (demo) /bin/cc main.c (demo) philmds> touch inc2.h (demo) philmds> /bin/make (demo) cp inc1.x inc1.h (demo) /bin/cc main.c (demo) philmds> touch inc2.h (demo) philmds> /usr/local/make (demo) cp inc1.x inc1.h (demo) cc main.c (demo) philmds> touch inc2.h (demo) philmds> /bin/s5make (demo) cp inc1.x inc1.h (demo) cc main.c (demo) philmds> (demo) script done on Wed Mar 1 22:02:21 1989 I suspect the reason that your approach works for instance on Suns, is that those makes have implicit knowledge of SCCS; note it did not get it right with the implicit rule I added myself (.x.h). |The make/SCCS behavior you describe is clearly erroneous; a later- |modified checked-out file should never be clobbered by retrieval |from the archive. True. In fact, the problem (in /usr/local/make) is in the implicit rules: .h~.h: $(GET) $(GFLAGS) -p $< > $*.h You can draw your own conclusions ... Of course it can only occur with dependencies between sources (which I still consider incorrect), but the clobbering is unforgivable. | I think this behavior occurs because of the |redundancy introduced in the default rules in an attempt to |compensate for "make" not getting the logical transitivity right. Maybe you expect too much of Make; you want a target name both to represent a logical and a physical item. To use the demo example, the preprocessed inc1.h is dependent of inc1.h and inc2.h, inc1.h itself is not (inc1.h does not change if you modify inc2.h). The use of dummy targets (I think that was what you meant by FRC?) I do not consider a kludge. Leo.