Recursive #includes

Leo de Wit leo at philmds.UUCP
Mon Feb 27 04:11:01 AEST 1989


In article <9727 at smoke.BRL.MIL> gwyn at brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) 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.



More information about the Comp.lang.c mailing list