xref: /minix3/external/bsd/llvm/dist/llvm/utils/TableGen/tdtags (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
1#!/bin/sh
2#===-- tdtags - TableGen tags wrapper ---------------------------*- sh -*-===#
3# vim:set sts=2 sw=2 et:
4#===----------------------------------------------------------------------===#
5#
6#                     The LLVM Compiler Infrastructure
7#
8# This file is distributed under the University of Illinois Open Source
9# License. See LICENSE.TXT for details.
10#
11#===----------------------------------------------------------------------===#
12#
13# This is a wrapper script to simplify generating ctags(1)-compatible index
14# files for target .td files. Run tdtags -H for more documentation.
15#
16# For portability, this script is intended to conform to IEEE Std 1003.1-2008.
17#
18#===----------------------------------------------------------------------===#
19
20SELF=${0##*/}
21
22usage() {
23cat <<END
24Usage: $SELF [ <options> ] tdfile
25   or: $SELF [ <options> ] -x recipe [arg ...]
26OPTIONS
27  -H          Display further help.
28  -a          Append the tags to an existing tags file.
29  -f <file>   Write tags to the specified file (defaults to 'tags').
30  -I <dir>    Add the directory to the search path for tblgen include files.
31  -x <recipe> Generate tags file(s) for a common use case:
32  -q          Suppress $TBLGEN error messages.
33  -v          Be verbose; report progress.
34END
35  usage_recipes
36}
37
38usage_recipes() {
39cat <<END
40     all      - Generate an index in each directory that contains .td files
41                in the LLVM source tree.
42     here     - Generate an index for all .td files in the current directory.
43     recurse  - Generate an index in each directory that contains .td files
44                in and under the current directory.
45     target [<target> ...]
46              - Generate a tags file for each specified LLVM code generator
47                target, or if none are specified, all targets.
48END
49}
50
51help() {
52cat <<END
53NAME
54  $SELF - generate ctags(1)-compatible index files for tblgen .td source
55
56SYNOPSIS
57  $SELF [ options ] -x recipe [arg ...]
58  $SELF [ options ] [file ...]
59
60DESCRIPTION
61  With the '-x' option, $SELF produces one or more tags files for a
62  particular common use case. See the RECIPES section below for details.
63
64  Without the '-x' option, $SELF provides a ctags(1)-like interface to
65  $TBLGEN.
66
67OPTIONS
68  -a          Append newly generated tags to those already in an existing
69              tags file. Without ths option, any and all existing tags are
70              replaced. NOTE: When building a mixed tags file, using ${SELF}
71              for tblgen tags and ctags(1) for other languages, it is best
72              to run ${SELF} first without '-a', and ctags(1) second with '-a',
73              because ctags(1) handling is more capable.
74  -f <file>   Use the name <file> for the tags file, rather than the default
75              "tags". If the <file> is "-", then the tag index is written to
76              standard output.
77  -H          Display this document.
78  -I <dir>    Add the directory <dir> to the search path for 'include'
79              statements in tblgen source.
80  -x          Run a canned recipe, rather than operate on specified files.
81              When '-x' is present, the first non-option argument is the
82              name of a recipe, and any further arguments are arguments to
83              that recipe. With no arguments, lists the available recipes.
84  -q          Suppress $TBLGEN error messages. Not all .td files are well-
85              formed outside a specific context, so recipes will sometimes
86              produce error messages for certain .td files. These errors
87              do not affect the indices produced for valid files.
88  -v          Be verbose; report progress.
89
90RECIPES
91  $SELF -x all
92              Produce a tags file in every directory in the LLVM source tree
93              that contains any .td files.
94  $SELF -x here
95              Produce a tags file from .td files in the current directory.
96  $SELF -x recurse
97              Produce a tags file in every directory that contains any .td
98              files, in and under the current directory.
99  $SELF -x target [<target> ...]
100              Produce a tags file for each named code generator target, or
101              if none are named, for all code generator targets.
102END
103}
104
105# Temporary file management.
106#
107# Since SUS sh(1) has no arrays, this script makes extensive use of
108# temporary files. The follow are 'global' and used to carry information
109# across functions:
110#   $TMP:D    Include directories.
111#   $TMP:I    Included files.
112#   $TMP:T    Top-level files, that are not included by another.
113#   $TMP:W    Directories in which to generate tags (Worklist).
114# For portability to OS X, names must not differ only in case.
115#
116TMP=${TMPDIR:-/tmp}/$SELF:$$
117trap "rm -f $TMP*" 0
118trap exit 1 2 13 15
119>$TMP:D
120
121td_dump()
122{
123  if [ $OPT_VERBOSE -gt 1 ]
124  then
125    printf '===== %s =====\n' "$1"
126    cat <"$1"
127  fi
128}
129
130# Escape the arguments, taken as a whole.
131e() {
132  printf '%s' "$*" |
133    sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/"
134}
135
136# Determine whether the given directory contains at least one .td file.
137dir_has_td() {
138  for i in $1/*.td
139  do
140    [ -f "$i" ] && return 0
141  done
142  return 1
143}
144
145# Partition the supplied list of files, plus any files included from them,
146# into two groups:
147#   $TMP:T    Top-level files, that are not included by another.
148#   $TMP:I    Included files.
149# Add standard directories to the include paths in $TMP:D if this would
150# benefit the any of the included files.
151td_prep() {
152  >$TMP:E
153  >$TMP:J
154  for i in *.td
155  do
156    [ "x$i" = 'x*.td' ] && return 1
157    if [ -f "$i" ]
158    then
159      printf '%s\n' "$i" >>$TMP:E
160      sed -n -e 's/include[[:space:]]"\(.*\)".*/\1/p' <"$i" >>$TMP:J
161    else
162      printf >&2 '%s: "%s" not found.\n' "$SELF" "$i"
163      exit 7
164    fi
165  done
166  sort -u <$TMP:E >$TMP:X
167  sort -u <$TMP:J >$TMP:I
168  # A file that exists but is not included is toplevel.
169  comm -23 $TMP:X $TMP:I >$TMP:T
170  td_dump $TMP:T
171  td_dump $TMP:I
172  # Check include files.
173  while read i
174  do
175    [ -f "$i" ] && continue
176    while read d
177    do
178      [ -f "$d/$i" ] && break
179    done <$TMP:D
180    if [ -z "$d" ]
181    then
182      # See whether this include file can be found in a common location.
183      for d in $LLVM_SRC_ROOT/include \
184               $LLVM_SRC_ROOT/tools/clang/include
185      do
186        if [ -f "$d/$i" ]
187        then
188          printf '%s\n' "$d" >>$TMP:D
189          break
190        fi
191      done
192    fi
193  done <$TMP:I
194  td_dump $TMP:D
195}
196
197# Generate tags for the list of files in $TMP:T.
198td_tag() {
199  # Collect include directories.
200  inc=
201  while read d
202  do
203    inc="${inc}${inc:+ }$(e "-I=$d")"
204  done <$TMP:D
205
206  if [ $OPT_VERBOSE -ne 0 ]
207  then
208    printf >&2 'In "%s",\n' "$PWD"
209  fi
210
211  # Generate tags for each file.
212  n=0
213  while read i
214  do
215    if [ $OPT_VERBOSE -ne 0 ]
216    then
217      printf >&2 '  generating tags from "%s"\n' "$i"
218    fi
219    n=$((n + 1))
220    t=$(printf '%s:A:%05u' "$TMP" $n)
221    eval $TBLGEN --gen-ctags $inc "$i" >$t 2>$TMP:F
222    [ $OPT_NOTBLGENERR -eq 1 ] || cat $TMP:F
223  done <$TMP:T
224
225  # Add existing tags if requested.
226  if [ $OPT_APPEND -eq 1 -a -f "$OPT_TAGSFILE" ]
227  then
228    if [ $OPT_VERBOSE -ne 0 ]
229    then
230      printf >&2 '  and existing tags from "%s"\n' "$OPT_TAGSFILE"
231    fi
232    n=$((n + 1))
233    t=$(printf '%s:A:%05u' "$TMP" $n)
234    sed -e '/^!_TAG_/d' <"$OPT_TAGSFILE" | sort -u >$t
235  fi
236
237  # Merge tags.
238  if [ $n = 1 ]
239  then
240    mv -f "$t" $TMP:M
241  else
242    sort -m -u $TMP:A:* >$TMP:M
243  fi
244
245  # Emit tags.
246  if [ x${OPT_TAGSFILE}x = x-x ]
247  then
248    cat $TMP:M
249  else
250    if [ $OPT_VERBOSE -ne 0 ]
251    then
252      printf >&2 '  into "%s".\n' "$OPT_TAGSFILE"
253    fi
254    mv -f $TMP:M "$OPT_TAGSFILE"
255  fi
256}
257
258# Generate tags for the current directory.
259td_here() {
260  td_prep
261  [ -s $TMP:T ] || return 1
262  td_tag
263}
264
265# Generate tags for the current directory, and report an error if there are
266# no .td files present.
267do_here()
268{
269  if ! td_here
270  then
271    printf >&2 '%s: Nothing to do here.\n' "$SELF"
272    exit 1
273  fi
274}
275
276# Generate tags for all .td files under the current directory.
277do_recurse()
278{
279  td_find "$PWD"
280  td_dirs
281}
282
283# Generate tags for all .td files in LLVM.
284do_all()
285{
286  td_find "$LLVM_SRC_ROOT"
287  td_dirs
288}
289
290# Generate tags for each directory in the worklist $TMP:W.
291td_dirs()
292{
293  while read d
294  do
295    (cd "$d" && td_here)
296  done <$TMP:W
297}
298
299# Find directories containing .td files within the specified directory,
300# and record them in the worklist $TMP:W.
301td_find()
302{
303  find -L "$1" -type f -name '*.td' |
304    sed -e 's:/[^/]*$::' |
305    sort -u >$TMP:W
306  td_dump $TMP:W
307}
308
309# Generate tags for the specified code generator targets, or
310# if there are no arguments, all targets.
311do_targets() {
312  cd $LLVM_SRC_ROOT/lib/Target
313  if [ -z "$*" ]
314  then
315    td_find "$PWD"
316  else
317    # Check that every specified argument is a target directory;
318    # if not, list all target directories.
319    for d
320    do
321      if [ -d "$d" ] && dir_has_td "$d"
322      then
323        printf '%s/%s\n' "$PWD" "$d"
324      else
325        printf >&2 '%s: "%s" is not a target. Targets are:\n' "$SELF" "$d"
326        for d in *
327        do
328          [ -d "$d" ] || continue
329          dir_has_td "$d" && printf >&2 '  %s\n' "$d"
330        done
331        exit 2
332      fi
333    done >$TMP:W
334  fi
335  td_dirs
336}
337
338# Change to the directory at the top of the enclosing LLVM source tree,
339# if possible.
340llvm_src_root() {
341  while [ "$PWD" != / ]
342  do
343    # Use this directory if multiple notable subdirectories are present.
344    [ -d include/llvm -a -d lib/Target ] && return 0
345    cd ..
346  done
347  return 1
348}
349
350# Ensure sort(1) behaves consistently.
351LC_ALL=C
352export LC_ALL
353
354# Globals.
355TBLGEN=llvm-tblgen
356LLVM_SRC_ROOT=
357
358# Command options.
359OPT_TAGSFILE=tags
360OPT_RECIPES=0
361OPT_APPEND=0
362OPT_VERBOSE=0
363OPT_NOTBLGENERR=0
364
365while getopts 'af:hxqvHI:' opt
366do
367  case $opt in
368  a)
369    OPT_APPEND=1
370    ;;
371  f)
372    OPT_TAGSFILE="$OPTARG"
373    ;;
374  x)
375    OPT_RECIPES=1
376    ;;
377  q)
378    OPT_NOTBLGENERR=1
379    ;;
380  v)
381    OPT_VERBOSE=$((OPT_VERBOSE + 1))
382    ;;
383  I)
384    printf '%s\n' "$OPTARG" >>$TMP:D
385    ;;
386  [hH])
387    help
388    exit 0
389    ;;
390  *)
391    usage >&2
392    exit 4
393    ;;
394  esac
395done
396shift $((OPTIND - 1))
397
398# Handle the case where tdtags is a simple ctags(1)-like wrapper for tblgen.
399if [ $OPT_RECIPES -eq 0 ]
400then
401  if [ -z "$*" ]
402  then
403    help >&2
404    exit 5
405  fi
406  for i
407  do
408    printf '%s\n' "$i"
409  done >$TMP:T
410  td_tag
411  exit $?
412fi
413
414# Find the directory at the top of the enclosing LLVM source tree.
415if ! LLVM_SRC_ROOT=$(llvm_src_root && pwd)
416then
417  printf >&2 '%s: Run from within the LLVM source tree.\n' "$SELF"
418  exit 3
419fi
420
421# Select canned actions.
422RECIPE="$1"
423case "$RECIPE" in
424all)
425  shift
426  do_all
427  ;;
428.|cwd|here)
429  shift
430  do_here
431  ;;
432recurse)
433  shift
434  do_recurse
435  ;;
436target)
437  shift
438  do_targets "$@"
439  ;;
440*)
441  if [ -n "$RECIPE" ]
442  then
443    shift
444    printf >&2 '%s: Unknown recipe "-x %s". ' "$SELF" "$RECIPE"
445  fi
446  printf >&2 'Recipes:\n'
447  usage_recipes >&2
448  printf >&2 'Run "%s -H" for help.\n' "$SELF"
449  exit 6
450  ;;
451esac
452
453exit $?
454