From: throop@aurs01.UUCP (Wayne Throop)
Newsgroups: comp.lang.c
Subject: Re: 'make' woes (won't catch secondary dependancy)
Summary: unorthodox solution
Date: 2 Oct 92 19:23:00 GMT
Organization: Alcatel Network Systems, Raleigh NC

>> h1.h: h2.h
>>        touch h1.h
>>
>> That ought to work
>  It'll work, but IMHO, it can be a pain in the @$$ 

First of all, to say that a .h file depends on another .h file
just because it includes it is incorrect.  There is nothing about
the including .h file that actually changes on account of
the included file changing.  Remember "x depends on y" means
"some process needs to read y and (potentially) update x".

With that agreed (I hope):

>  IMHO, this is a bug in the specification of "make" that you need to
>  update the target file in order to propigate changes down the dependency
>  list.  There should really be a way to propigate changes based soley on
>  the files the target is dependant on.

No, make acts appropriately.  A rule can decide not to update an output
if it isn't necessary, and the subsequent rules would quite properly
not fire.  For example, suppose you edited a comment in a .c, or made a
change that the optimizer produced identical code for.  Suppose further
that your compiler noticed that the .o was the same.  Then, it could
legitimately leave the old timestamp on the old .o, and avoid having to
do a link.  If dates were checked recursively this would not be
possible.  (This more often comes up in real life in processing, say, a
table notation into .c and .h files: if the table only changes some of
the files, forcing compiles on all of them can be very wasteful.)

I think the real problem is that make does not allow for what I tend to
call "virtual objects" or "conceptual objects".  Make treats only files
in the file system.  If it kept a lookaside database (as, for example,
makes that do .KEEP_STATE must do), then it could form the concept of
"foo.c and all its included files" as a virtual entitiy, and associate
a date with it.

Of course, this capability can be simulated right now, by using files
in the file system to represent the "conceptual" objects.  Hence
following unorthodox solution to the problem.

( Note that the more usual solution, which is to use makedepend
  or whatnot to attach all the recursively encountered .h files to
  the .o dependency, will work.  But I assume that the original question
  was how to do it so the dependencies can be stated "locally", that is,
  each file stating only those it directly includes.  That's what the
  below does that output of normal makedepend does not.  Whether it is
  worth it...   somebody else can decide. )

        .SUFFIXES: .o .c+ .c .h+ .h 
        .h.h+:
                touch $*.h+
        .c.c+:
                touch $*.c+

        foo.o: foo.c+
                gcc -c -ansi -pedantic -O $*.c
        foo.c+: foo.c bar.h+
        bar.h+: bar.h baz.h+
        baz.h+: baz.h

Obviously, I'm using a slew of blah.[ch]+ files to represent locally
the maximum timestamp of any of the files lower down in the include
graph.  (I do have some trouble getting a .c+.o rule to fire
in the presense of the default ruleset, hence the explicit rule, sigh).

Here's how it works out:

        % make foo.o
        touch baz.h+
        touch bar.h+
        touch foo.c+
        gcc -c -ansi -pedantic -O foo.c
        % make foo.o
        `foo.o' is up to date.
        % touch bar.h
        % make foo.o
        touch bar.h+
        touch foo.c+
        gcc -c -ansi -pedantic -O foo.c
        % make foo.o
        `foo.o' is up to date.
        % touch baz.h
        % make foo.o
        touch baz.h+
        touch bar.h+
        touch foo.c+
        gcc -c -ansi -pedantic -O foo.c

Interestingly, the "touch" rules fireing off make it more clear which of
the .h files cause a recompile, and through which intermediates.

Wayne Throop       ...!mcnc!aurgate!throop