#!/bin/sh # # Copyright (c) 1996, 1998 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Lonhyn T. Jasinskyj. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the NetBSD # Foundation, Inc. and its contributors. # 4. Neither the name of The NetBSD Foundation nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # # This is a shell script that behaves rather like the makedepend(1) # that comes with X11 except that it also understands VPATH # # makedepend-sh takes three sets of arguments. It parse the line of # arguments left to right and until it encounters a '--' it # applies command line switches to itself. After the first '--' all # args are accumulated and will be used as arguments to a C preprocessor # (such as cc -E). All arguments after the second '--' are filenames, # usually object files. More formally: # # makedepend [-a] [-s varname] [-v] [-f file] [-p preprocessor] [-V pathlist] # [-e scriptfile] [-m mrulesfile [-x excludeobjs]] -- # [preprocessor args] -- file1 [file2 [...]] # # Flags: # # -a # append to the end of the output file (usually Makefile) instead # of replacing anything following a marker that looks like: # "# DO NOT DELETE THIS LINE -- makedepend-sh depends on it" # Appending is generally not the desired behavior but may be # useful if makedepend needs multiple, different invocations. # # -s varname # generate a 'varname = filenames...' line in the output that is # derived from the files given to makedepend. In this way a list # of object files can be given and they will be searched for # (possibly in a VPATH) and then their full pathnames will be # given computed and accumulated in a 'varname=' line. Thus, in a # Makefile the writer need only write 'OBJS=' (and possibly # give a VPATH if the source and object trees are seperate) and # makedepend will do the rest. It is often useful to choose # varname as "SRCS" or "CSRCS". Only C files are candidates # for inclusion in the source list. # # -v # be verbose, can be repeated for more verbosity. # # -f file # instead of using Makefile, write to this file # # -m mrulesfile # a file in the style of a Makefile containing suffix rules # with transformations. Since stock make is incapable of # applying a transformation rule if both files are not # in the local directory, a specific rules has to be generated # by makedepend in this case. If the -m flag is given the # appropriate suffix rule will be extracted and an explicit # command will be generated. # # -x excludeobjs # if the -m flag is given then this should contain a list # of objects that should not have a rule generated for them. # # -i ignorefiles # these files will simply be ignored, this is useful if you # give makedepend a list of files to process but not all of # the files exist yet. # # -p preprocessor # the command to invoke the preprocessor if 'cc -E' is not # appropriate. Normally one should quote this (e.g. -p "gcc -E") # # -V pathlist # the path is a colon-seperated list of paths that will be searched # for the source file. Normally only '.' is searched. # # -e scriptfile # the regular expression is treated as the path of an arbitrary # sed program that will be applied to the list of dependencies. # This will happen after all of the dependencies are composed # but before they are appended or any effects of the -s flag # are added. This is useful for excluding files in "/usr/include" # and "gcc-lib". # # -c cksumfile # compute a checksum (using "cksum") of this file. If a # file called .dep_cksum exists in the local directory then # also compare the new cksum output with the contents of that # file. If they are the same and a file called .depends also # exists locally then one need not redo the makedepend # dependency processing and can instead take .depends and # either append it to the Makefile or replace the previous # dependencies (as appropriate depending on the -a flag) # Finally, if new dependencies are generated, place a copy in # the file given as cksumfile. # # -- # # -preprocessor_args # whatever arguments appear in this section get passed on to the # pre-processor. # # -- # # file1 [file2 [...]] # the filenames given to makedepend. These are often object files # whose names will first be transformed to source files by # replacing final '.o' with '.c'. These will then be sought in # either '.' or a list of paths given with the -V flag. # # # Output: # # For each file listed makedepend will output: # # 1. if the file was an object file, then a line like # file.o: dirname/file.c # # 2. multiple lines of the form: # dirname/file.c: inc1.h inc2.h # dirname/file.c: inc3.h inc4.h # etc. # # 3. if the -s flag was given, then a set of lines like # SRCS = \ # dirname/file1.c \ # dirname/file2.c \ # etc. # # 4. if the -m flag is give then for each source file that is # not in the local directory, an explicit rule will be # generated. The actions will be derived from a parsed # makefile-style file. # P=`basename $0`; export P CPP="cc -E" MARKER="# DO NOT DELETE THIS LINE -- makedepend-sh depends on it" CKSUM=cksum CKSUM_STORE=.dep_cksum DEPEND_STORE=.depends init_mode() { mode="md_args"; } incr_mode() { if [ "$mode" = "md_args" ] ; then mode="cc_args"; else if [ "$mode" = "cc_args" ] ; then mode="fn_args"; fi fi } append_arg() { case "$mode" in md_*) arg_md="$arg_md $1" ;; cc_*) arg_cc="$arg_cc $1" ;; fn_*) arg_fn="$arg_fn $1" ;; esac } append_srcs() { append_to="$1" srcs_file="$2" # # since there is no way to echo a backslash reliably # with builtin echo or /bin/echo (not knowing their pedigree) # echo must be avoided for output. Use printf or, in this case, awk. # cat $srcs_file | \ awk 'BEGIN { printf("\n#\n# '$mksrcs' generated by makedepend\n#\n'$mksrcs' = ")} \ {} { for (i = 1; i <= NF; i++) { printf("\\\n %s ", $i) }} \ END { printf("\n\n") }' >> $append_to } append_rules() { append_to="$1" rules_in="$2" ( \ echo; echo '#'; \ echo '# generated rules for source files that are not local'; \ echo '# to this directory.'; \ echo '#'; \ cat $rules_in; \ echo; echo; echo) >> $append_to } generate_awk() { cat > $1 < $mkrule_scr . $mkrule_scr if test "$verbose" -gt 1; then (echo "make rules are:"; echo "==============="; \ cat $mkrule_scr; echo "===============") | sed -e "s/^/$P: /" fi } # # exists_rule(): true if a rule exists for this src and product suffix # exists_rule() { # src and product suffixes s_sfx=$1 p_sfx=$1 rulename=\$mkrule__${s_sfx}_${prod_sfx} test -n "`eval echo $rulename`" && return 0 return 1 } # # called with a var name as an arg this will produce a line of # shell code to be evaluated. Thus to set the variable FOO to # the name of the next available temp file use # eval `mktemp FOO` # This is necessary to get the auto-increment of tmp_id since # things in single quotes are normally run in sub-shells # mktemp() { export tmp_id tmp_id=`expr ${tmp_id:-0} + 1` name=/tmp/mkdep.$$.${tmp_id} echo "$1=$name; tmp_id=$tmp_id" } # # explicit_rule(): # this will take arguments with information about the source # file and the product to be generated. It then decides whether # an explicit rule needs to be made and if so adds it to a file # which can then be tacked onto the make file later. # explicit_rule() { src="$1" obj="$2" srcdir="$3" rulefile="$4" excludes="$5" test "$srcdir" = '.' && return src_suffix=`echo $src | sed -n -e 's/.*\.\([^.][^.]*\)$/\1/p'` obj_suffix=`echo $obj | sed -n -e 's/.*\.\([^.][^.]*\)$/\1/p'` # figure out the name of the variable where the action is stored rulename=\$mkrule__${src_suffix}_${obj_suffix} # # go and see if this object is one of the excluded objects, if # so, bag this phase # for x in $excludes; do test "$x" = "$obj" && { test "$verbose" -gt 1 && \ echo $P: skipping explicit rule for: $obj; \ return; \ } done # # generate the explicit rule and add it to the rulefile if we # have a suffix transformation # if test -n "`eval echo $rulename`"; then echo ${obj}: ${srcdir}/${src} >> $rulefile # # use POSIX printf to get the newlines right, must use double quotes. # also replace all occurences of '$<' with the name of the # source file since '$<' is only appropriate in inference # rules and '$?' is not a correct substitute when the target # depends on multiple files, including .h files. # eval printf \"$rulename\" | \ sed -e "s;\$<;$srcdir/$src;g" >> $rulefile fi } in_list_p() { f="$1" ignores="$2" for x in $ignores; do test "$x" = "$f" && return 0 done return 1 } # # see if we already have a file of dependencies and see if it is # usable (i.e. the cksum on the cksumfile is still the same) # have_usable_depends() { ckmatchfile="$1" if test -n "$ckmatchfile" -a -s "$CKSUM_STORE" -a -f "$DEPEND_STORE"; then $CKSUM $ckmatchfile > $CKS 2> /dev/null && \ diff "$CKSUM_STORE" "$CKS" > /dev/null 2>&1 || \ return 1 # no usable dependencies prestored test "$verbose" -gt 0 && echo $P: using dependencies from previous run return 0 fi # return FALSE return 1 } # # maybe_store_depends: # we should squirrel away the dependencies that have been generated # if the user has specified a -c flag on the command line (i.e. a # file to checksum against). If that is the case then store the # dependencies in DEPEND_STORE and calculate a new checksum into # CKSUM_STORE. # maybe_store_depends() { ckmatchfile="$1" depsfile="$2" if test -n "$ckmatchfile" ; then $CKSUM "$ckmatchfile" > $CKS 2> /dev/null && \ test -s "$CKS" || return 1 # only store if different diff "$CKS" "$CKSUM_STORE" > /dev/null 2>&1 || cdiff=yes diff "$depsfile" "$DEPEND_STORE" > /dev/null 2>&1 || ddiff=yes if test "$cdiff" = yes -o "$ddiff" = yes; then cp "$CKS" "$CKSUM_STORE" && cp "$depsfile" "$DEPEND_STORE" || \ return 1 test "$verbose" -gt 0 && echo $P: stored new dependencies for reuse fi fi # success unless we botched things above and returned a 1 return 0 } # # gen_depends(): # generate the depend information into the file named in TMP. # gen_depends() { # # go through the source files. Find each in VPATH # do the compile there and accumulate the dependencies # true > $TMP # truncate TMP for f in $arg_fn; do # let us assume that all products are '.o' files prod_sfx='o' # figure out the stem: i.e. /a/b/c/foo.o --> foo stem=`echo $f | sed -e 's/.o$//'` # did we actually find a source file found_src=no # if this file is in the ignore list, skip it in_list_p "$f" "$ignobjs" && { test "$verbose" -gt 0 && \ echo $P: ignoring file: $f; continue; } # # go through each possible directory and try each possible # source file # for d in $VPATH; do # # as soon as we find the first src file, we can go onto the # next argument (i.e. object file) # test "$found_src" = yes && break for src_sfx in $mksuffixes; do # cannot make a file from itself test "$prod_sfx" = "$src_sfx" && continue # # if we were given rules and there is no rule for this # transformation then skip this suffix combination # test -n "$mrules" && exists_rule $src_sfx $prod_sfx || continue s=${stem}.${src_sfx} test "$verbose" -gt 2 && echo "$P: checking for: $d/$s" if [ -f "$d/$s" ]; then found_src=yes test "$verbose" -gt 0 && echo $P: processing $d/$s case "$src_sfx" in c*|C*) # # This is a file that is a candidate for cpp: # # process the output of cpp and massage it, then sort # it uniquely and as a final step remove the trailing # numbers or any other cruft that various compilers # might generate. Then remove any lines that # make the file depend on itself by removing any # dependencies on files not ending in .h or .H # # also add it to the list of srcs # test -n "$mksrcs" && echo $d/$s >> $SRCS test "$verbose" -lt 2 && errout='2> /dev/null' eval $CPP $arg_cc $d/$s $errout | \ sed -n -e "s;^\# [0-9][0-9 ]*\"\(/.*\)\";$f: \1;p" | \ grep -v "//$" | \ grep -v "$s\$" | \ sed -e 's;\([^ :]*: [^ ]*\).*;\1;' \ >> $TMP ;; *) test "$verbose" -gt 1 && echo "$P: no preprocessing for $s" ;; esac # # explicit rules can be generated for all sorts of sources # explicit_rule "$s" "$f" "$d" "$RULES" "$xobjs" break fi done done test "$found_src" = no && echo Did not find the source for: $f done # # optionally invoke a user-specified sed script on the output. In either # case, sort the output uniquely first. # if test -n "$sedprog"; then sort -u < "$TMP" | sed -f "$sedprog" > "$TMP"_a mv "$TMP"_a "$TMP" 2>&1 > /dev/null else sort -u -o "$TMP" "$TMP" fi # # now see if we want the SRCS= line and generation of # explicit rules per file for source files not in our # current directory # test -n "$mksrcs" && test -r "$SRCS" && append_srcs "$TMP" "$SRCS" # # if we wanted explicit rules then these have been diverted to # a seperate file, include them now # test -n "$mrules" && test -r "$RULES" && append_rules "$TMP" "$RULES" } # # this is the beginning of the main routine # init_mode eval `mktemp TMP` eval `mktemp RULES` eval `mktemp SRCS` eval `mktemp CKS` VP=.; export VP mksrcs=""; export mksrcs MF=Makefile; export MF append=no; export append verbose=0; export verbose sedprog=""; export sedprog mrules=""; export mrules xobjs=""; export xobjs ignobjs=""; export ignobjs cksumfile=""; export cksumfile trap '/bin/rm /tmp/mkdep.$$.* > /dev/null 2>&1' 0 1 2 3 15 while [ $# -gt 0 ] ; do if [ "$mode" = "md_args" ]; then # # these are arguments to the makedepend script itself # case "$1" in -V*) shift; VP=$1 ;; # VPATH -s*) shift; mksrcs=$1 ;; # generate a SRCS= line based on OBJS -f*) shift; MF=$1 ;; # dependfile name -p*) shift; CPP="$1" ;; # pre-processor to use -e*) shift; sedprog="$1" ;; -c*) shift; cksumfile="$1" ;; # file to cksum (e.g. Makefile.in) -m*) shift; mrules="$1" ;; # the make rules file -x*) shift; xobjs="$1" ;; # no rules for this list of objs -i*) shift; ignobjs="$1" ;; # list of objs to be ignored -a*) append=yes ;; -v*) verbose=`expr $verbose + 1` ;; --) incr_mode ;; *) echo $P: Illegal argument \'"$1"\' >&2; exit 1 ;; esac shift else case "$1" in --) incr_mode ;; *) append_arg "$1" ;; esac shift; fi done if test -n "$xobjs" -a -z "$mrules"; then echo $P: cannot use -x without -m >&2 exit 1 fi if test "$append" = yes -a -n "$mrules"; then echo $P: cannot use append mode if -m is specified >$2 echo $P: since multiple action definitions are prohibited >&2 exit 1 fi test -n "$mrules" && eval_mrules $mrules VPATH="`echo .:$VP | sed -e 's/:/ /g'`" test "$verbose" -gt 1 && echo "$P: CFLAGS are: $arg_cc" test "$verbose" -gt 1 && echo "$P: VPATH dirs are: $VPATH" # # the list of suffixes is either found in the make rules # and set by calling eval_mrules() earlier, or # if we did not process any, then '.c' will do # mksuffixes=${mksuffixes:-'c'} # # if we find that we can avoid generation of new dependency # rules by looking in prestored rules then do that. This # way, even though Makefile was regenerated and rules # removed we can use the old ones if Makefile.in was # not changed. Ideally, make would have an include directive # but that is not universally the case. # have_usable_depends "$cksumfile" && cp "$DEPEND_STORE" "$TMP" || gen_depends if [ "$append" = "yes" ]; then # if the marker is already in the file, do not put a second one in grep "^$MARKER" $MF > /dev/null 2>&1 || echo "$MARKER" >> $MF cat $TMP >> $MF else if grep "^$MARKER" $MF > /dev/null 2>&1 ; then # # we delete and then add since there may be no line .+1 if # the marker was the last line # tmp_mf="/tmp/mf.$$" sed "/^$MARKER/d" $MF > $tmp_mf; mv $tmp_mf $MF fi echo $MARKER >> $MF cat $TMP >> $MF fi # # decide whether we are using the checksum shortcut and storing depends # and if so store the new checksum and new depends # maybe_store_depends "$cksumfile" "$TMP" || \ echo $P: error storing dependencies for later use /bin/rm $TMP > /dev/null 2>&1