xref: /freebsd/contrib/bmake/mkdeps.sh (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1:
2# NAME:
3#	mkdeps - generate dependencies
4#
5# SYNOPSIS:
6#	mkdeps [options] file ...
7#
8# DESCRIPTION:
9#	This script updates "makefile" with dependencies for
10#	"file"(s).  It borrows ideas from various makedepend scripts
11#	and should be compatible with most.
12#
13#	By default we use grep to extract include file names from
14#	source files.  We source an "rc" file '$Mydir/.${Myname}rc' which
15#	can contain variable assignments such as:
16#.nf
17#
18#	cpp_c=/usr/lib/cpp
19#	cpp_cc=g++ -E
20#	...
21#
22#.fi
23#	If the variable 'cpp_$suffix' is set, we use it as our cpp in
24#	place of grep.  The program referenced by these variables are
25#	expected to produce output like:
26#.nf
27#
28#	# 10 \"/usr/include/stdio.h\" 1
29#
30#.fi
31#	This allows us to skip most of our processing.  For lex,yacc
32#	and other source files, grep is probably just as quick and
33#	certainly more portable.
34#
35#	If the "rc" file does not exist, we create it and attempt to
36#	find cpp or an equivalent cc invocation to assign to 'cpp_c'.
37#
38# AUTHOR:
39#	Simon J. Gerraty <sjg@zen.void.oz.au>
40#
41
42# RCSid:
43#	$Id: mkdeps.sh,v 1.24 2022/09/09 18:44:56 sjg Exp $
44#
45#	@(#) Copyright (c) 1993 Simon J. Gerraty
46#
47#	This file is provided in the hope that it will
48#	be of use.  There is absolutely NO WARRANTY.
49#	Permission to copy, redistribute or otherwise
50#	use this file is hereby granted provided that
51#	the above copyright notice and this notice are
52#	left intact.
53#
54#	Please send copies of changes and bug-fixes to:
55#	sjg@zen.void.oz.au
56#
57
58Myname=`basename $0 .sh`
59Mydir=`dirname $0`
60
61case `echo -n .` in
62-n*)	N=; C="\c";;
63*)	N=-n; C=;;
64esac
65
66cc_include=-I/usr/include
67
68TF=/tmp/dep.$$
69EF=/tmp/deperr.$$
70> $EF
71
72case "$*" in
73*-n*)				# don't use rc file
74  rc=/dev/null
75  norc=yes;;
76*)
77  rc=$Mydir/.${Myname}rc
78  ;;
79esac
80
81update=
82Include=include
83
84if [ x"$norc" = x -a -f $rc ]; then
85  . $rc
86else
87  # if /usr/lib/cpp or equivalent is available it is better than
88  # grepping .c files.
89  # See what (if anything) works on this system...
90  echo : > $rc
91  echo "# pre-processor for .c files" >> $rc
92  # try a couple of sane places first
93  for d in /usr/libexec /usr/lib /usr/bin /lib /usr/ccs/bin
94  do
95    cpp_c=$d/cpp
96    [ -x $cpp_c ] && break
97  done
98
99  if [ -x $cpp_c ]; then
100    echo cpp_c=$cpp_c >> $rc
101  else
102    cpp_c=
103    # rats see if cc can be used
104    echo "#include <stdio.h>" > /tmp/f$$.c
105    echo "main() { return 0; }" >> /tmp/f$$.c
106    # try some sensible args to cc
107    for arg in -E -P -M
108    do
109      ok=`${REALCC:-${CC:-cc}} $arg /tmp/f$$.c 2>/dev/null | grep '^#.*stdio.h' | tail -1`
110      case "$ok" in
111      "") ;;
112      *)
113        cpp_c="${REALCC:-${CC:-cc}} $arg"
114        echo cpp_c="'$cpp_c'" >> $rc
115        break;;
116      esac
117    done
118    rm -f /tmp/f$$.c
119  fi
120fi
121
122# some Linux systems have deprecated egrep in favor of grep -E
123# but not everyone supports that
124case "`echo bmake | egrep 'a|b' 2>&1`" in
125bmake) ;;
126*) egrep() { grep -E "$@"; }
127esac
128
129clean_up() {
130  trap "" 2 3
131  trap 0
132  if [ -s $EF ]; then
133          egrep -vi "included from|warning" $EF > ${EF}2
134          if [ -s ${EF}2 ]; then
135	          cat $EF >&2
136                  rm -f .depend
137                  ests=1
138	  fi
139  fi
140  rm -f $TF $EF*
141  exit ${ests:-0}
142}
143
144# this lot does not work on HPsUX - complain to Hp.
145trap clean_up 0
146trap exit 2 3
147
148get_incs() {
149  case "$cpp" in
150  grep)
151    # set IGNORE="<" to skip system includes
152    egrep '^#[ 	]*include' $* | egrep -v "$IGNORE" | \
153      sed -e 's/^.*include[^"<]*["<]//' -e 's/[">].*//g';;
154  *)
155    # $cpp (eg. /usr/lib/cpp or cc -E) should produce output like:
156    # 1 "/usr/include/stdio.h" 2
157    # set IGNORE=/usr/include to skip system includes
158    $cpp $cpp_opts $cc_include $* 2>> $EF | egrep '^#.*\.h"' | sed 's,^#.*"\(.*\)".*,\1,' |
159      egrep -v "$IGNORE" | sort -u;;
160  esac
161}
162
163gen_deps() {
164  llen=$1
165  shift
166
167  for ifile in $*
168  do
169    case "$cpp" in
170    grep)
171      # this lot is not needed if not using grep.
172      for dir in $srcdir $dirlist /usr/include
173      do
174        [ -f "$dir/$ifile" ] && break
175      done
176
177      if [ ! -f "$dir/$ifile" ]; then
178        # produce a useful error message (useful to emacs or error)
179        iline=`grep -n ".*include.*[\"<]$ifile[\">]" $file | cut -d: -f1`
180        echo "\"$file\", line $iline: cannot find include file \"$ifile\"" >> $EF
181        # no point adding to dependency list as the resulting makefile
182        # would not work anyway...
183        continue
184      fi
185      ifile=$dir/$ifile
186
187      # check whether we have done it yet
188      case `grep "$ifile" $TF` in
189      "") echo "$ifile" >> $TF;;
190      *)	continue;;		# no repeats...
191      esac
192      ;;
193    esac
194
195    len=`expr "$ifile " : '.*'`
196    if [ "`expr $llen + $len`" -gt ${width:-76} ]; then
197      echo "\\" >> .depend
198      echo $N "	$C" >> .depend
199      llen=8
200    fi
201    echo $N "$ifile $C" >> .depend
202    llen=`expr $llen + $len`
203
204    case "$cpp" in
205    grep)
206      # this lot is not needed unless using grep.
207      ilist=`get_incs $ifile` # recurse needed?
208      [ "$ilist" ] && llen=`gen_deps $llen $ilist`
209      ;;
210    esac
211  done
212  echo $llen
213}
214
215for f in makefile Makefile
216do
217  test -s $f && { MAKEFILE=$f; break; }
218done
219
220MAKEFILE=${MAKEFILE:-makefile}
221IGNORE=${IGNORE:-"^-"}		# won't happen
222obj=o
223cpp_opts=			# incase cpp != grep
224vpath=
225append=
226progDep=
227
228set -- `getopt "AanNV:s:w:o:I:D:b:f:i:p" "$@"`
229for key in "$@"
230do
231  case $key in
232  --)	shift; break;;
233  -A)	Include=;;		# cat .depend >> $MAKEFILE
234  -a)	append=yes; shift;;
235  -n)	shift;;			# ignore rc
236  -N)	update=no; shift;;	# don't update $MAKEFILE
237  -I)	cpp_opts="$cpp_opts$1$2 "; dirlist="$dirlist $2"; shift 2;;
238  -o)	obj=$2; shift 2;;
239  -s)	shift 2;;		# can't handle it anyway...
240  -w)	width=$2; shift 2;;
241  -f)	MAKEFILE=$2; shift 2;;
242  -b)	BASEDIR=$2; shift 2;;
243  -i)	IGNORE="$2"; shift 2;;	# ignore headers matching this...
244  -D)	cpp_opts="$cpp_opts$1$2 "; shift 2;;
245  -V)	VPATH="$2"; shift 2;;	# where to look for files
246  -p)	progDep=yes; shift;;
247  esac
248done
249
250[ "$VPATH" ] && vpath=`IFS=:; set -- $VPATH; echo $*`
251
252[ "$append" ] || > .depend
253
254for file in $*
255do
256  cpp=
257  suffix=`expr $file : '.*\.\([^.]*\)'`
258
259  eval cpp=\"\${cpp_${suffix}:-grep}\"
260
261  if [ ! -f $file -a "$vpath" ]; then
262    for d in . $vpath
263    do
264      [ -f $d/$file ] && { file=$d/$file; break; }
265    done
266  fi
267  srcdir=`dirname $file`
268  base=`basename $file .$suffix`
269
270  ilist=`get_incs $file`
271
272  if [ "$ilist" ]; then
273    > $TF
274    if [ "$progDep" ]; then
275      echo "$base:	$file \\" >> .depend
276    else
277      echo "$base.$obj:	$file \\" >> .depend
278    fi
279    echo $N "	$C" >> .depend
280    llen=8
281    llen=`gen_deps $llen $ilist`
282    echo >> .depend
283    echo >> .depend
284  elif [ "$progDep" ]; then
285    echo "$base:	$file" >> .depend
286    echo >> .depend
287  fi
288done
289
290if [ -s .depend ]; then
291  # ./foo.h looks ugly
292  mv .depend $TF
293  { test "$BASEDIR" && sed -e "s;$BASEDIR;\$(BASEDIR);g" $TF || cat $TF; } |
294    sed 's;\([^.]\)\./;\1;g' > .depend
295
296  #
297  # Save the manually updated section of the makefile
298  #
299  if [ x$update != xno ]; then
300    trap "" 2			# don't die if we got this far
301
302    # if make doesn't support include, then append our deps...
303    depended=`grep 'include.*\.depend' $MAKEFILE`
304    test "$depended" && clean_up
305
306    sed '/^# DO NOT DELETE.*depend.*$/,$d' < $MAKEFILE > $TF
307    mv $TF $MAKEFILE
308    cat <<! >> $MAKEFILE
309# DO NOT DELETE THIS LINE -- make depend depends on it
310# Do not edit anything below, it was added automagically by $Myname.
311
312!
313
314    case "$Include" in
315    "")	cat .depend >> $MAKEFILE;;
316    .include)	echo '.include ".depend"' >> $MAKEFILE;;
317    include)	echo include .depend >> $MAKEFILE;;
318    esac
319  fi
320fi
321clean_up
322