Path: utzoo!mnetor!uunet!husc6!cmcl2!brl-adm!umd5!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Re: Makefile Maker Message-ID: <9942@mimsy.UUCP> Date: 23 Dec 87 22:58:17 GMT References: <176@goofy.megatest.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 148 Keywords: make Makefile In article <176@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >... What you really want is something that keeps up with the >dependencies automatically as they change. ... Let's cause the >Makefile to update itself each time a dependency might have changed. We already have something like this in 4.3BSD. A number of the makefiles in /usr/src support the command `make depend'. Admittedly this requires manual intervention---one has to decide that it is time to update the dependency lists---but it works and is relatively simple. The makefiles distributed with 4.3BSD do this in an ugly way. Each makefile has something like this: depend: for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} depend); done for i in ${STD} ${NSTD} ${SETUID}; do \ cc -M $$i.c | sed 's/\.o//' | \ awk ' { if ($$1 != prev) \ { if (rec != "") print rec; rec = $$0; prev = $$1; } \ else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ else rec = rec " " $$2 } } \ END { print rec } '; done >makedep echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep echo '$$r makedep' >>eddep echo 'w' >>eddep cp Makefile Makefile.bak ed - Makefile < eddep rm eddep makedep echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile echo '# see make depend above' >>Makefile # DO NOT DELETE THIS LINE -- make depend uses it foo: foo.c /usr/include/stdio.h /usr/include/signal.h foo.h # DEPENDENCIES MUST END AT END OF FILE [etc] As it happens, all the ugliness can be, should be, and as of a number of months ago, has been, encapsulated in a program. This program is called `mkdep'; it is really just a shell script that runs cc -M. It has two options, `-f' (specify the name of the makefile) and `-p' (producing programs: do the sed command shown above, so that x depends on x.c and incl.h; otherwise x.o depends on x.c and incl.h). I am not sure I should post the script itself, but it is trivial, since everything you need do is shown above. Instead of the for loop, mkdep assumes you are naming .c files, so the Makefile entry now looks like this: depend: ldepend for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} depend); done ldepend: mkdep -p ${CFLAGS} ${CSRCS} # DO NOT DELETE THIS LINE -- mkdep uses it # DEPENDENCIES MUST END ... [etc] (Here `depend' has been split to provide a `change local dependencies only' target. `make depend' in an upper-level source directory such as /usr/src/ucb is time consuming, and deadly boring; `make ldepend' confines dependency generation to the current directory.) Disliking having to list both source files *and* programs (it seems inelegant and error prone), I created two small scripts called `addsuf' and `chgsuf', so that the `ldepend' target becomes ldepend: mkdep -p ${CFLAGS} `addsuf .c ${STD} ${NSTD}` or ldepend: mkdep ${CFLAGS} `chgsuf .o .c ${OBJS}` Since I wrote them, I know I can post them. Here are addsuf and chgsuf in their entirety: #! /bin/sh # # addsuf - add suffix to each argument # assumes no embedded spaces in arguments case $# in 0) echo "usage: addsuf suffix files" 1>&2; exit 1;; esac suf="$1" shift echo ${1+"$@"} | sed -e "s/ /$suf /g" -e "s/$/$suf/" #! /bin/sh # # chgsuf - change suffix in each argument # assumes no embedded spaces in arguments # oldsuf is a string, not an R.E. case $# in 0|1) echo "usage: chgsuf oldsuf newsuf files" 1>&2; exit 1;; esac sed="sed -e s/[/.^[\*]/\\\\&/g" oldsuf="`echo \"$1\" | $sed`" newsuf="`echo \"$2\" | $sed`" shift; shift echo ${1+"$@"} | sed -e "s/$oldsuf /$newsuf /g" -e "s/$oldsuf$/$newsuf/" Of course, there is still a problem for those for whom `cc -M' produces nothing useful. Fortunately, some time ago I wrote a shell script for use on our Suns, which then did not support a -M option for cc. Not long ago I moved it to our Pyramid, which still does not support cc -M (we run OSx release 2.5, as we have some trouble getting current sources). Here is that version: #! /bin/sh # # getdep - get dependency lists. # find cpp cpp=/lib/cpp # handle arguments incl= for i do case "$i" in -I*) incl="$incl $i";; -O|-c|-M|-D*|-U*) ;; *) # assume source file # put '$dep' in front of dependencies dep=`echo "$i" | sed -e 's,/,\\\\/,g' -e 's/\.c$/.o/'` # Find includes, remove leading numerics, remove ./, # remove double quotes, and remove trailing numerics. # Sort that, discarding duplicates, and add '$dep'. $cpp $incl "$i" | grep "^#" | sed -e 's/# [0-9]* //' -e 's,"./,",' -e 's/"\(.*\)"/\1/' \ -e 's/ [ 0-9]*$//' | sort -u | sed -e "s/^/$dep: /";; esac done -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris