Recursive #includes

Wayne A. Throop throopw at agarn.dg.com
Wed Mar 1 04:37:18 AEST 1989


> gwyn at smoke.BRL.MIL (Doug Gwyn )
>> leo at philmds.UUCP (Leo de Wit) 
>>> gwyn at brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) 

>>> 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.
> "make" has an inherent design problem in that it doesn't properly
> distinguish between logical and physical dependencies.

It seems to me that to claim both that it is technically correct and
that make's rules run into a problem here is to miss the point Leo has
to make.  Of course, I think Leo is also missing at least some of the
points Doug has to make.  Let me try to untangle what I see as partial
truth on each side.

First, dependence *is* indeed a transitive property.  But the
recommended use of make is not technically correct, as Doug himself
points out just after claiming that it is.  Make does not distinguish
between "needed to construct" and "needed to use as input".  Make has
only the concept "needed to construct".  Leo is pointing out that,
given only the concept "needed to construct", it is never correct to
say that a source "depends" upon another source.

But on the other hand, it is correct to say that since dependence is
transitive, the .o does not need to depend directly upon all include
files that the compiler will read.

It seems to me that the "correct" way (or at least a better way) of
dealing with trees of include files is to introduce a phantom object
which depends upon "this .h and the phantom objects of the .hs it
includes".  The .o would depend on "this .c and the phantom objects of
the .hs it includes".  By "phantom object", I mean something not
corresponding to a file in the file system.

In this scheme, as in make, there is only "needed to construct", and
therefore no source should depend upon another source directly.  But
the "construction" of the conceptual object of "include file foo is
ready to be read" CAN depend upon a source, namely include file foo.

The alternative that Doug suggests, of having more than one kind of
"needed for" seems overly complicated.  The scheme I suggest works
even when the relevant .h files are constructed on the fly themselves,
(assuming some modifications to make, of course).

( This scheme still doesn't deal with cyclic includes broken with
  #ifdef... but despite there being ways to deal with that as well,
  my personal feeling is "don't DO that" is a good remedy.  )

--
The nation that controls magnetism will control... The Universe!
                                        --- Dick Tracy
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw



More information about the Comp.lang.c mailing list