[TableGen] Correct Namespace lookup with AltNames in AsmWriterEmitter
[oota-llvm.git] / utils / TableGen / tdtags
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
20 SELF=${0##*/}
21
22 usage() {
23 cat <<END
24 Usage: $SELF [ <options> ] tdfile
25    or: $SELF [ <options> ] -x recipe [arg ...]
26 OPTIONS
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.
34 END
35   usage_recipes
36 }
37
38 usage_recipes() {
39 cat <<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.
48 END
49 }
50
51 help() {
52 cat <<END
53 NAME
54   $SELF - generate ctags(1)-compatible index files for tblgen .td source
55
56 SYNOPSIS
57   $SELF [ options ] -x recipe [arg ...]
58   $SELF [ options ] [file ...]
59
60 DESCRIPTION
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
67 OPTIONS
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
90 RECIPES
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.
102 END
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 #
116 TMP=${TMPDIR:-/tmp}/$SELF:$$
117 trap "rm -f $TMP*" 0
118 trap exit 1 2 13 15
119 >$TMP:D
120
121 td_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.
131 e() {
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.
137 dir_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.
151 td_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.
198 td_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.
259 td_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.
267 do_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.
277 do_recurse()
278 {
279   td_find "$PWD"
280   td_dirs
281 }
282
283 # Generate tags for all .td files in LLVM.
284 do_all()
285 {
286   td_find "$LLVM_SRC_ROOT"
287   td_dirs
288 }
289
290 # Generate tags for each directory in the worklist $TMP:W.
291 td_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.
301 td_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.
311 do_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.
340 llvm_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.
351 LC_ALL=C
352 export LC_ALL
353
354 # Globals.
355 TBLGEN=llvm-tblgen
356 LLVM_SRC_ROOT=
357
358 # Command options.
359 OPT_TAGSFILE=tags
360 OPT_RECIPES=0
361 OPT_APPEND=0
362 OPT_VERBOSE=0
363 OPT_NOTBLGENERR=0
364
365 while getopts 'af:hxqvHI:' opt
366 do
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
395 done
396 shift $((OPTIND - 1))
397
398 # Handle the case where tdtags is a simple ctags(1)-like wrapper for tblgen.
399 if [ $OPT_RECIPES -eq 0 ]
400 then
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 $?
412 fi
413
414 # Find the directory at the top of the enclosing LLVM source tree.
415 if ! LLVM_SRC_ROOT=$(llvm_src_root && pwd)
416 then
417   printf >&2 '%s: Run from within the LLVM source tree.\n' "$SELF"
418   exit 3
419 fi
420
421 # Select canned actions.
422 RECIPE="$1"
423 case "$RECIPE" in
424 all)
425   shift
426   do_all
427   ;;
428 .|cwd|here)
429   shift
430   do_here
431   ;;
432 recurse)
433   shift
434   do_recurse
435   ;;
436 target)
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   ;;
451 esac
452
453 exit $?