[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.