Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!decwrl!sun!pitstop!sundc!seismo!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: <964@philmds.UUCP> Date: 26 Feb 89 18:11:01 GMT References: <570@marob.MASA.COM> <9727@smoke.BRL.MIL> Reply-To: leo@philmds.UUCP (Leo de Wit) Organization: Philips I&E DTS Eindhoven Lines: 64 In article <9727@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) ) writes: [] |>Furthermore, permitting recursive includes may tend to smear the |>separation between modular components of the software system, and |>designing a correct makefile will be a mess. | |If a module's interface depends on another's, then necessarily you |have to #include the other module's interface definition just to |properly declare this one's. Of course most modules (packages) |should not have interfaces that are tied to others, but sometimes |it is necessary. | |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). It may very well get you into trouble, as I'll show. Regarding make dependencies I tend to use the rule that an update of a dependency's source must imply the update of the dependency's target. A common (though understandable) mistake is to declare dependencies between C source files and their header files: there is none (at least not in the sense of Make). The real dependency is between the header file(s) and the preprocessed C file! (the C _source_ does not change due to a change in the header file, the preprocessed source and hence the corresponding object _does_). The solution of the multilevel - and perhaps recursive - includes is not that difficult: find, given a header file, recursively all header files it includes; if you encounter the same header file in the list, ignore it. The list of include files is so to speak the transitive closure with respect to inclusion. Now declare a macro that consist of the list of header file names a given header file (recursively) includes, and use that in dependencies instead of the original given header file. (Side issue: of course you must treat conditional includes as unconditional, since most makes cannot handle correctly a change of an on the commandline supplied macro (though Sun's make _does_); you'll have to manually touch sources / remove objects to force a recompile. Note that, if you want to do that conditional stuff correctly too, the list may well dynamically change due to a C macro change). And now for the promised trouble: Let's say we have a C file file.c that includes a header file1.h. This header also includes a header: file2.h (you guessed it 8-). Now whether or not file2.h includes file1.h (or possible other ones too), if your makefile contains file1.h : file2.h you're bound to have trouble. Suppose file1.h has been stored in an SCCS directory, and you got out a copy for edit. You made a few changes to file1.h, then to file2.h, and then said 'make'. Your edited copy will be clobbered by the old one fetched by SCCS, using an implicit make rule !! However, some clever SCCS'es - notably Sun's - refuse to write to a writable file, consider it a 'source fetched for edit', so that Make will abort; some others most certainly do. Have fun ... Leo.