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