corbin@maxzilla.Encore.COM (10/12/89)
Does anyone have an idea of how to handle nexted include file dependencies in make? Given that test includes test.h, test.h include test1.h and test1.h include test2.h. When test2.h is touched test.c will not get rebuilt given the follow make dependencies: test.c: test.h test.h: test1.h test1.h: test2.h Can this be done in make or is test.c: test.h test1.h test2.h the only way it will work. The problem with the second example is that I'm working on a product with hundreds of files and maintaining dependencies manuallly is tedious and error prone. I would like to do automatic dependency generation. I have a grep/sed/awk script that will generate the first example by scanning all the sources (.s .c .h). I'm just learning sed/awk and it would probably take me weeks to figure out how to generate the second case. Does anyone have such a tool/script that would take a list of files and generate dependencies or any ideas on how to solve the problem? Stephen Corbin {bu-cs,decvax,necntc,talcott}!encore!corbin corbin@encore.COM Stephen Corbin {bu-cs,decvax,necntc,talcott}!encore!corbin corbin@encore.COM
erikb@cs.vu.nl (Erik Baalbergen) (10/12/89)
In article <10115@encore.Encore.COM> corbin@maxzilla.UUCP () writes: > >Can this be done in make or is > >test.c: test.h test1.h test2.h > >the only way it will work. In fact, it's test.o: test.h test1.h test2.h > >The problem with the second example is that I'm working on a product >with hundreds of files and maintaining dependencies manuallly is tedious >and error prone. I would like to do automatic dependency generation. Lots of "mkdep"s, "makedep"s, and "makedependencies"s are floating around in the world. There may be one on your system. Some cc's are equiped with a "-M" option. "cc -M f.c" then produces make dependency lines in the right format. (-M causes cpp to print out the names of the files which are included.) The "make-dependencies" or "cc -M" can then be used from within the Makefile: -- start Makefile -- depend: sed '/^#THE FOLLOWING LINES ARE GENERATED/,$$d' Makefile > Makefile.new echo '#THE FOLLOWING LINES ARE GENERATED' >> Makefile.new $(MKDEP) $(CSRC) >> Makefile.new mv Makefile.new Makefile #THE FOLLOWING LINES ARE GENERATED # don't put any hand-written stuff here -- end Makefile -- The command "make depend" will create a new Makefile with the dependencies appearing after the "#THE FOLLOWING LINES ARE GENERATED" line. Erik Baalbergen (erikb@cs.vu.nl) -- Erik H. Baalbergen <erikb@cs.vu.nl> Vrije Universiteit / Dept. of Maths. & Comp. Sc. De Boelelaan 1081 1081 HV Amsterdam / The Netherlands tel. +31 20 548 8080
cpcahil@virtech.UUCP (Conor P. Cahill) (10/12/89)
In article <10115@encore.Encore.COM>, corbin@maxzilla.Encore.COM writes: > Does anyone have an idea of how to handle nexted include file > dependencies in make? Given that test includes test.h, test.h > include test1.h and test1.h include test2.h. When test2.h is > touched test.c will not get rebuilt given the follow make dependencies: > > test.c: test.h > test.h: test1.h > test1.h: test2.h > > Can this be done in make or is > > test.c: test.h test1.h test2.h There is a problem in both of these dependencies. A "dependency" is an item that is required to build the target. The *.h files are not dependencies for the .c file. The *.h files and the .c file are dependencies for the .o file (or executable, if there are no other .c files and you set up the makefile appropriatly). The first example has one include file dependent upon the other, but that is not a true dependency since test1.h is not needed to build test.h (it is necessary to interpret/process test.h, but that is in the build step for the object file, not the include file) > I have a grep/sed/awk script that will generate the first example by > scanning all the sources (.s .c .h). I'm just learning sed/awk and it > would probably take me weeks to figure out how to generate the second case. 2 points. 1. are you just hard coding the nested include, or are you actually parsing the files and only including the needed files. For example if your program runs int: #ifdef USE_SGTTY #include <sgtty.h> #else #include <termio.h> #endif do you properly interpret this as a single include of the appropriate file? 2. The imake program source (on the X11 release tape) does include a shell (I think) that uses cpp to parse the file and then scans the output to properly generate the dependency list. There probably are other PD/Shareware/FSF software to do the same. -- +-----------------------------------------------------------------------+ | Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 ! | Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 | +-----------------------------------------------------------------------+
chris@mimsy.UUCP (Chris Torek) (10/13/89)
In article <10115@encore.Encore.COM> corbin@maxzilla.Encore.COM writes: >Does anyone have an idea of how to handle nexted include file >dependencies in make? Given that test includes test.h, test.h >include test1.h and test1.h include test2.h. When test2.h is >touched test.c will not get rebuilt given the follow make dependencies: > >test.c: test.h >test.h: test1.h >test1.h: test2.h Of course not---because this list is wrong. test.h does *not* depend on test1.h, and test1.h does *not* depend on test2.h. To see this, think about what you must do if you change test2.h. You do *not* need to apply some command sequence to rebuild test1.h. You do, however, have to apply some command sequence to build things that include any of test.h, test1.h, or test2.h. Now, if test.c included `tconc.h', and tconc.h were to be built by concatenating test.h and t12conc.h, and t12conc.h were to be built by concatenating test1.h and test2.h, you could correctly write: test.c: tconc.h tconc.h: test.h t12conc.h cat test.h t12conc.h > $@ t12conc.h: test1.h test2.h cat test1.h test2.h > $@ Now if you change test2.h, you really *do* have to apply some command sequence to build t12conc.h, and once you have done that, you again really do have to apply some command sequence to build tconc.h, and then again apply some command sequence to build test.o. >Can this be done in make or is > >test.c: test.h test1.h test2.h > >the only way it will work. > >The problem with the second example is that I'm working on a product >with hundreds of files and maintaining dependencies manuallly is tedious >and error prone. I would like to do automatic dependency generation. If you have `mkdep', this is easy. If not, build mkdep. There are several ways to build it: (best way) apply a C preprocessor to the source code; have it print a list of files included by each source file. On reasonably current BSD releases, `cc -M' does this. (More current releases have `mkdep'.) (next best way) apply the C preprocessor to the source code. Extract `#line' directives from the result, and build a list of files included by each source file. See shell script below. (not as good) use grep to extract all `#include' lines. Transform file names to path names. Recursively extract `#include' lines from these paths. This goofs on `#ifdef/#include/#endif' sequences, e.g. Here are the shell scripts. cat >getdep.sh <<'END' #! /bin/sh # getdep - get dependency lists. # find cpp cpp=unknown for where in /lib /usr/lib /bin /usr/bin; do if test -f $where/cpp; then cpp=$where/cpp; break; fi done if test $cpp = unknown; then echo "I cannot find cpp, sorry" 1>&2; exit 1 fi # handle arguments incl= for i do case "$i" in -I*) incl="$incl $i";; # you may have to add more cases below -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" | sed -e ' /^#/!d s/# [0-9]* // s,"./,", s/"\(.*\)"/\1/ s/ [ 0-9]*$//' | sort -u | sed -e "s/^/$dep: /";; esac done END cat >mkdep.sh <<'ENDEND' #! /bin/sh - # # Copyright (c) 1987 Regents of the University of California. # All rights reserved. # # Redistribution and use in source and binary forms are permitted # provided that the above copyright notice and this paragraph are # duplicated in all such forms and that any documentation, # advertising materials, and other materials related to such # distribution and use acknowledge that the software was developed # by the University of California, Berkeley. The name of the # University may not be used to endorse or promote products derived # from this software without specific prior written permission. # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # @(#)mkdep.sh 5.13 (Berkeley) 8/19/88 # # modified at Univ of Maryland # PATH=/bin:/usr/bin:/usr/ucb export PATH D=.depend # default dependency file is .depend while : do case "$1" in # -f allows you to select a makefile name -f) D=$2 shift; shift ;; # the -p flag produces "program: program.c" style dependencies # so .o's don't get produced -p) SED='s;\.o;;' shift ;; *) break ;; esac done if [ $# = 0 ] ; then echo 'usage: mkdep [-p] [-f depend_file] [cc_flags] file ...' exit 1 fi TMP=/tmp/mkdep$$ trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 rm -f $TMP case $D in .depend) style=new;; *) if grep -s "DO NOT DELETE THIS LINE" $D; then style=old elif [ -f $D -a ! -w $D ]; then echo "mkdep: no writeable file \"$D\"" exit 1 fi;; esac exec >$TMP case $style in old) cp $D $D.bak sed -e '/DO NOT DELETE THIS LINE/,$d' < $D cat << _EOF_ # DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. _EOF_ esac # If your compiler has -M, use it here instead of getdep.sh. # cc -M $* | /usr/local/lib/getdep $* | sed " s; \./; ;g $SED" | 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 }' case $style in old) cat << _EOF_ # IF YOU PUT ANYTHING HERE IT WILL GO AWAY _EOF_ esac # copy to preserve permissions cp $TMP $D rm -f $TMP exit 0 ENDEND cat >make.sh <<'END' #! /bin/sh if [ -f .depend ]; then if [ -f makefile ]; then f="-f makefile -f .depend" else f="-f Makefile -f .depend" fi for i do case "$i" in -f*) f=;; esac done else f= fi exec /bin/make $f ${1+"$@"} MACHINE=${MACHINE-`machine`} END -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
gregg@cbnewsc.ATT.COM (gregg.g.wonderly) (10/13/89)
From article <10115@encore.Encore.COM>, by corbin@maxzilla.Encore.COM: > Does anyone have such a tool/script that would take a list of files > and generate dependencies or any ideas on how to solve the problem? An easy way to do this is to make use of "cc -E" to get the listing with the filenames on the "# line" lines. Through the use of the following pipe line of commands, you can get the names of all of the files that a file includes without having to do recursive greps. defs="all -Dthis and -Dthat required" ifiles="all -Idir1 -Idir2 required" file="input .c file" cc -E $defs $ifiles $file | \ grep '^#' | \ sed '/^#ident/d' | sed "1,\$s/^[^\"]*\"//;s/\"\$//;/`basename $file`/d;/y.tab.c/d" | \ sort -u The output will be the absolute path names and relative path names of ALL included files relative to the current directory and/or the -I directory names (relative or absolute). "cc -E" works on most UN*Xs, if it doesn't on yours, you will need to find an alternative way. This has worked for me for quite some time... -- ----- gregg.g.wonderly@att.com (AT&T bell laboratories)
chris@mimsy.UUCP (Chris Torek) (10/13/89)
In article <20139@mimsy.UUCP> I wrote: >Now, if test.c included `tconc.h', and tconc.h were to be built by >concatenating test.h and t12conc.h, and t12conc.h were to be built by >concatenating test1.h and test2.h, you could correctly write: > > test.c: tconc.h > tconc.h: test.h t12conc.h > cat test.h t12conc.h > $@ > t12conc.h: test1.h test2.h > cat test1.h test2.h > $@ Oops, I completely missed the fact that it is not test.c, but rather test.o, which depends on (is built from the changed version of) tconc.h, so the first line should read test.o: tconc.h Implicit rules add implicit dependencies, so that test.o: test.c is not actually required, unless there is an explicit action below, such as cc -DFOO ${CFLAGS} -c $@.c -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris