A question on C programming style

cschmidt at lynx.northeastern.edu cschmidt at lynx.northeastern.edu
Sun Apr 21 09:00:35 AEST 1991


> I'm profoundly lazy, and I refuse to keep even simple Makefile
> dependencies up-to-date manually, let alone complicated ones which
> require chasing through several levels of #inclusion.  That's why I
> use an automatic dependency generator.  (For me, doing so has no
> disadvantages, because I wrote my own that behaves just as I expect it
> to.)

It was heartening to read this.  I have long believed that writing
MAKE scripts by hand is both too time consuming and too unreliable.
In one project with which I was associated, it was discovered AFTER
the product shipped that about 14 dependencies were missing from the
circa 500-line MAKE script.

My current solution is similar to yours, Steve, but with an unusual
twist: my dependency detector program never writes the dependency list
to disk.  Instead, it outputs a list of source files that need to be
compiled right now.  It then calls the compiler (if the list is not
empty).  The MAKE program is not used.  (Naturally, when I am
debugging a single module, I just call the compiler directly.)

One obvious advantage to this approach is that the dependency list is
always guaranteed to be up to date.  When using a conventional
dependency generator, there is a temptation to postpone using it.

You might think that this approach would be slower than using a
traditional MAKE program, but it turns out that it is actually faster
in many cases.  The MAKE program resolves dependencies one at a time.
If ten modules need to be compiled, MAKE calls the C compiler ten
times.  Using my dependency detector, the C compiler is called just
once; the names of the ten modules to be compiled are passed to the
compiler as a single parameter in the form of a "response file".

In any case, my dependency detector program employs these performance
improvement techniques:

o   The source file is not scanned for include directives if the
    object file does not exist, or if the object file's time stamp is
    older than that of the source file.

o   To avoid reading the entire source file for include directives,
    the program does not read beyond a certain optional pragma
    directive, which happens to be the same pragma directive that my
    header file generator recognizes as marking the start of the
    implementation section.

o   By default, the program does not check the time stamps of standard
    header files (those whose names are enclosed in angle brackets),
    but there is an optional command line switch to override this.

o   Once the time stamp of a header file is determined, that header
    file name and its time stamp are stored in a global list, in case
    another source file includes the same header file.  The time stamp
    assigned to a header file is either that header file's actual time
    stamp, or the time stamp of the newest header file specified in a
    nested include directive, whichever time stamp is newest.

o   Before scanning source files, the program notes the time stamp of
    the newest object file.  When determining the time stamp of a
    header file, the scanning for nested include directives stops if
    the program finds a header file with a time stamp that is newer
    than that of the newest object file.

I would be interested in any remarks you folks might have about this,
especially if you have had any experience designing or using a
dependency detector that uses this approach.

Christopher Schmidt
cschmidt at lynx.northeastern.edu



More information about the Comp.lang.c mailing list