[LispM-Hackers] Makedepend discovery

James A. Crippen james@UnLambda.COM
Mon, 21 May 2001 13:03:11 -0800 (AKDT)


I just learned after spending some quality time with the GNU Make manual
(for work) that one can do a 'makedepend' to extract dependency
information from a source file by reciting the incantation

  $ cc -M -Ipath/to/include/directory foo.c

which will generate output on stdout similar to

foo.o: foo.c /usr/include/stdio.h /usr/include/features.h \
 /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
 /usr/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/include/stddef.h \
 /usr/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/include/stdarg.h \
 /usr/include/bits/types.h /usr/include/libio.h \
 /usr/include/_G_config.h /usr/include/bits/stdio_lim.h \
 /usr/include/syslog.h /usr/include/sys/syslog.h \
 ...

which seems like what one wants.  (Note that this example doesn't show the
paths extracted from ""-style includes, but rest assured that they are
generated as well.)  The GNU Make manual continues by claiming that this
is supported by "most modern C compilers" whatever that means.  It then
says:

  With old make programs it was traditional practice to use this compiler
  feature to generate prerequisites on demand with a command like 'make
  depend'.  That command would create a file 'depend' containing all the
  automatically-generated prerequisites; then the makefile could use
  include to read them in.

  In GNU make the feature of remaking makefiles makes this practice
  obsolete -- you need never tell make to explicitly regenerate the
  prerequisites because it always regenerates any makefile that is out of
  date.

  The practice we recommend for automatic prerequisite generation is to
  have one makefile corresponding to each source file.  For each source
  file '/name/.c' there is a makefile '/name/.d' which lists what files
  the object file '/name/.o' depends on. That way only the source files
  that have changed need to be rescanned to produce the new prerequisites.

  Here is the pattern rule to generate a file of prerequisites (ie, a
  makefile) called '/name/.d' from a C source file called '/name/.c'.

      %.d: %.c
              set -e; $(CC) -M $(CPPFLAGS) $< \
                        | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
                      [ -s $@ ] || rm -f $@

  The '-e' flag to the shell makes it exit immediately if the
  $(CC) command fails (exits with a nonzero status). ...

  With the GNU C compiler you may wish to use the '-MM' flag instead of
  '-M'.  This omits prerequisites on system header files.

  The purpose of the sed command is to translate (for example)

      main.o : main.c defs.h

  into

      main.o main.d : main.c defs.h

  This makes each '.d' file depend on all the source and header files that
  the corresponding '.o' file depends on.  make then knows it must
  regenerate the prerequisites whenever any of the source or header files
  changes.

  Once you've defined the rule to remake the '.d' files you then use the
  include directive to read them all in.  For example:

      sources = foo.c bar.c

      include $(sources:.c=.d)

Whew.  I've got COBOL fingers.  But this seems to me like a much better
solution for our dependency handling than checking in a static dependency
file that needs to be updated by people who have the correct magic
program.

If the '-M' option is truly portable to most compilers then this could be
a very workable solution.  And I rather like the per-file dependency
method rather than the one big honking dependency file method.  Although
I'd probably use '.dep' as a suffix rather than '.d' to make its purpose
more obvious.

So, does this sound like a good idea to people?  If so then I'll hack it
in and test it.

'james

-- 
James A. Crippen <james@unlambda.com> ,-./-.  Anchorage, Alaska,
Lambda Unlimited: Recursion 'R' Us   |  |/  | USA, 61.2069 N, 149.766 W,
Y = \f.(\x.f(xx)) (\x.f(xx))         |  |\  | Earth, Sol System,
Y(F) = F(Y(F))                        \_,-_/  Milky Way.