Document the grand totals reported by report-card tool
[dejagnu.git] / runtest.exp
blob078259a9c0c9ae936043379fb44d8fdec5c88053
1 # runtest.exp -- Test framework driver
2 # Copyright (C) 1992-2019, 2020, 2022, 2023 Free Software Foundation, Inc.
4 # This file is part of DejaGnu.
6 # DejaGnu is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # DejaGnu is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with DejaGnu; if not, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
20 # This file was written by Rob Savoye <rob@welcomehome.org>.
22 set frame_version       1.6.4-git
23 if {![info exists argv0]} {
24     send_error "Must use a version of Expect greater than 5.0\n"
25     exit 1
28 # trap some signals so we know whats happening. These definitions are only
29 # temporary until we read in the library stuff
31 trap { send_user "\ninterrupted by user\n"; exit 130 } SIGINT
32 trap { send_user "\nquit\n";                exit 131 } SIGQUIT
33 trap { send_user "\nterminated\n";          exit 143 } SIGTERM
36 # Initialize a few global variables used by all tests.
37 # `reset_vars' resets several of these, we define them here to document their
38 # existence.  In fact, it would be nice if all globals used by some interface
39 # of dejagnu proper were documented here.
41 # Keep these all lowercase.  Interface variables used by the various
42 # testsuites (eg: the gcc testsuite) should be in all capitals
43 # (eg: TORTURE_OPTIONS).
45 set mail_logs   0               ;# flag for mailing of summary and diff logs
46 set psum_file   "latest"        ;# file name of previous summary to diff against
48 set exit_status 0               ;# exit code returned by this program
50 set xfail_flag  0               ;# indicates that a failure is expected
51 set xfail_prms  0               ;# GNATS prms id number for this expected failure
52 set kfail_flag  0               ;# indicates that it is a known failure
53 set kfail_prms  0               ;# bug id for the description of the known failure
54 set sum_file    ""              ;# name of the file that contains the summary log
55 set base_dir    ""              ;# the current working directory
56 set xml_file    ""              ;# handle on the XML file if requested
57 set xml         0               ;# flag for requesting xml
58 set logname     ""              ;# the users login name
59 set prms_id     0               ;# GNATS prms id number
60 set bug_id      0               ;# optional bug id number
61 set dir         ""              ;# temp variable for directory names
62 set srcdir      "."             ;# source directory containing the test suite
63 set ignoretests ""              ;# list of tests to not execute
64 set objdir      "."             ;# directory where test case binaries live
65 set reboot      0
66 set multipass   ""              ;# list of passes and var settings
67 set errno       "";             ;#
68 set exit_error  1               ;# Toggle for whether to set the exit status
69                                 ;# on Tcl bugs in test case drivers.
71 # These describe the host and target environments.
73 set build_triplet  ""           ;# type of architecture to run tests on
74 set build_os       ""           ;# type of os the tests are running on
75 set build_vendor   ""           ;# vendor name of the OS or workstation the test are running on
76 set build_cpu      ""           ;# type of the cpu tests are running on
77 set host_triplet   ""           ;# type of architecture to run tests on, sometimes remotely
78 set host_os        ""           ;# type of os the tests are running on
79 set host_vendor    ""           ;# vendor name of the OS or workstation the test are running on
80 set host_cpu       ""           ;# type of the cpu tests are running on
81 set target_triplet ""           ;# type of architecture to run tests on, final remote
82 set target_os      ""           ;# type of os the tests are running on
83 set target_vendor  ""           ;# vendor name of the OS or workstation the test are running on
84 set target_cpu     ""           ;# type of the cpu tests are running on
85 set target_alias   ""           ;# standard abbreviation of target
86 set compiler_flags ""           ;# the flags used by the compiler
89 # These set configuration file names and are local to this file.
91 set local_init_file     site.exp        ;# testsuite-local init file name
92 set global_init_file    site.exp        ;# global init file name
95 # These are used to locate parts of the testsuite.
97 set testsuitedir        "testsuite"     ;# top-level testsuite source directory
98 set testbuilddir        "testsuite"     ;# top-level testsuite object directory
101 # Collected errors
103 namespace eval ::dejagnu::error {
104     # list of { file message errorCode errorInfo } lists
105     variable list [list]
108 # Various ccache versions provide incorrect debug info such as ignoring
109 # different current directory, breaking GDB testsuite.
110 set env(CCACHE_DISABLE) 1
111 unset -nocomplain env(CCACHE_NODISABLE)
114 # some convenience abbreviations
116 set hex "0x\[0-9A-Fa-f\]+"
117 set decimal "\[0-9\]+"
120 # set the base dir (current working directory)
122 set base_dir [pwd]
125 # These are set here instead of the init module so they can be overridden
126 # by command line options.
128 set all_flag    0
129 set binpath     ""
130 set debug       0
131 set options     ""
132 set outdir      "."
133 set reboot      1
134 set tracelevel  0
135 set verbose     0
136 set log_dialog  0
139 # verbose [-n] [-log] [--] message [level]
141 # Print MESSAGE if the verbose level is >= LEVEL.
142 # The default value of LEVEL is 1.
143 # "-n" says to not print a trailing newline.
144 # "-log" says to add the text to the log file even if it won't be printed.
145 # Note that the apparent behaviour of `send_user' dictates that if the message
146 # is printed it is also added to the log file.
147 # Use "--" if MESSAGE begins with "-".
149 # This is defined here rather than in framework.exp so we can use it
150 # while still loading in the support files.
152 proc verbose { args } {
153     global verbose
154     set newline 1
155     set logfile 0
157     set i 0
158     if { [string index [lindex $args 0] 0] eq "-" } {
159         for { set i 0 } { $i < [llength $args] } { incr i } {
160             if { [lindex $args $i] eq "--" } {
161                 incr i
162                 break
163             } elseif { [lindex $args $i] eq "-n" } {
164                 set newline 0
165             } elseif { [lindex $args $i] eq "-log" } {
166                 set logfile 1
167             } elseif { [lindex $args $i] eq "-x" } {
168                 set xml 1
169             } elseif { [string index [lindex $args $i] 0] eq "-" } {
170                 clone_output "ERROR: verbose: illegal argument: [lindex $args $i]"
171                 return
172             } else {
173                 break
174             }
175         }
176         if { [llength $args] == $i } {
177             clone_output "ERROR: verbose: nothing to print"
178             return
179         }
180     }
182     set level 1
183     if { [llength $args] > $i + 1 } {
184         set level [lindex $args [expr { $i + 1 }]]
185     }
186     set message [lindex $args $i]
188     if { $verbose >= $level } {
189         # We assume send_user also sends the text to the log file (which
190         # appears to be the case though the docs aren't clear on this).
191         if { $newline } {
192             send_user -- "$message\n"
193         } else {
194             send_user -- $message
195         }
196     } elseif { $logfile } {
197         if { $newline } {
198             send_log -- "$message\n"
199         } else {
200             send_log -- $message
201         }
202     }
206 # Transform a tool name to get the installed name.
207 # target_triplet is the canonical target name.  target_alias is the
208 # target name used when configure was run.
210 proc transform { name } {
211     global target_triplet
212     global target_alias
213     global host_triplet
214     global board
216     if { $target_triplet eq $host_triplet } {
217         return $name
218     }
219     if { $target_triplet eq "native" } {
220         return $name
221     }
222     if {[board_info host exists no_transform_name]} {
223         return $name
224     }
225     if { $target_triplet eq "" } {
226         return $name
227     } else {
228         if {[info exists board]} {
229             if {[board_info $board exists target_install]} {
230                 set target_install [board_info $board target_install]
231             }
232         }
233         if {[target_info exists target_install]} {
234             set target_install [target_info target_install]
235         }
236         if {$target_alias ne ""} {
237             set tmp $target_alias-$name
238         } elseif {[info exists target_install]} {
239             if { [lsearch -exact $target_install $target_alias] >= 0 } {
240                 set tmp $target_alias-$name
241             } else {
242                 set tmp "[lindex $target_install 0]-$name"
243             }
244         }
245         # There appears to be a possibility for tmp to be unset at this
246         # point, which will cause a Tcl error, but this can only occur if
247         # the init files invoke transform prior to defining target_alias,
248         # since the target_alias will be defaulted to the value of
249         # target_triplet before tests are run.  If target_triplet is also
250         # empty, this point will not be reached; see test above.
251         verbose "Transforming $name to $tmp"
252         return $tmp
253     }
257 # findfile arg0 [arg1] [arg2]
259 # Find a file and see if it exists. If you only care about the false
260 # condition, then you'll need to pass a null "" for arg1.
261 #       arg0 is the filename to look for. If the only arg,
262 #            then that's what gets returned. If this is the
263 #            only arg, then if it exists, arg0 gets returned.
264 #            if it doesn't exist, return only the prog name.
265 #       arg1 is optional, and it's what gets returned if
266 #            the file exists.
267 #       arg2 is optional, and it's what gets returned if
268 #            the file doesn't exist.
270 proc findfile { args } {
271     # look for the file
272     verbose "Seeing if [lindex $args 0] exists." 2
273     if {[file exists [lindex $args 0]]} {
274         if { [llength $args] > 1 } {
275             verbose "Found file, returning [lindex $args 1]"
276             return [lindex $args 1]
277         } else {
278             verbose "Found file, returning [lindex $args 0]"
279             return [lindex $args 0]
280         }
281     } else {
282         if { [llength $args] > 2 } {
283             verbose "Didn't find file [lindex $args 0], returning [lindex $args 2]"
284             return [lindex $args 2]
285         } else {
286             verbose "Didn't find file, returning [file tail [lindex $args 0]]"
287             return [transform [file tail [lindex $args 0]]]
288         }
289     }
293 # load_file [-1] [--] file1 [ file2 ... ]
295 # Utility to source a file.  All are sourced in order unless the flag "-1"
296 # is given in which case we stop after finding the first one.
297 # The result is 1 if a file was found, 0 if not.
298 # If a tcl error occurs while sourcing a file, we print an error message
299 # and exit.
301 proc load_file { args } {
302     set i 0
303     set only_one 0
304     if { [lindex $args $i] eq "-1" } {
305         set only_one 1
306         incr i
307     }
308     if { [lindex $args $i] eq "--" } {
309         incr i
310     }
312     set found 0
313     foreach file [lrange $args $i end] {
314         verbose "Looking for $file" 2
315         # In Tcl, "file exists" fails if the filename looks like
316         # ~/FILE and the environment variable HOME does not exist.
317         if {! [catch {file exists $file} result] && $result} {
318             set found 1
319             verbose "Found $file"
320             if { [catch "uplevel #0 source $file"] == 1 } {
321                 send_error "ERROR: tcl error sourcing $file.\n"
322                 global errorInfo
323                 if {[info exists errorInfo]} {
324                     send_error "$errorInfo\n"
325                 }
326                 exit 1
327             }
328             if { $only_one } {
329                 break
330             }
331         }
332     }
333     return $found
337 # search_and_load_file -- search DIRLIST looking for FILELIST.
338 # TYPE is used when displaying error and progress messages.
340 proc search_and_load_file { type filelist dirlist } {
341     set found 0
343     foreach dir $dirlist {
344         foreach initfile $filelist {
345             set filename [file join $dir $initfile]
346             verbose "Looking for $type $filename" 2
347             if {[file exists $filename]} {
348                 set found 1
349                 set error ""
350                 if { $type ne "library file" } {
351                     send_user "Using $filename as $type.\n"
352                 } else {
353                     verbose "Loading $filename"
354                 }
355                 if {[catch "uplevel #0 source $filename" error] == 1} {
356                     global errorInfo
357                     send_error "ERROR: tcl error sourcing $type $filename.\n$error\n"
358                     if {[info exists errorInfo]} {
359                         send_error "$errorInfo\n"
360                     }
361                     exit 1
362                 }
363                 break
364             }
365         }
366         if { $found } {
367             break
368         }
369     }
370     return $found
374 # Give a usage statement.
376 proc usage { } {
377     global tool
379     send_user "USAGE: runtest \[options...\]\n"
380     send_user "\t--all, -a\t\tPrint all test output to screen\n"
381     send_user "\t--build \[triplet\]\tThe canonical triplet of the build machine\n"
382     send_user "\t--debug\t\t\tSet expect debugging ON\n"
383     send_user "\t--directory name\tRun only the tests in directory 'name'\n"
384     send_user "\t--global_init \[name\]\tThe file to load for global configuration\n"
385     send_user "\t--help\t\t\tPrint help text\n"
386     send_user "\t--host \[triplet\]\tThe canonical triplet of the host machine\n"
387     send_user "\t--host_board \[name\]\tThe host board to use\n"
388     send_user "\t--ignore \[name(s)\]\tThe names of specific tests to ignore\n"
389     send_user "\t--local_init \[name\]\tThe file to load for local configuration\n"
390     send_user "\t--log_dialog\t\t\Emit Expect output on stdout\n"
391     send_user "\t--mail \[name(s)\]\tWhom to mail the results to\n"
392     send_user "\t--objdir \[name\]\t\tThe test suite binary directory\n"
393     send_user "\t--outdir \[name\]\t\tThe directory to put logs in\n"
394     send_user "\t--reboot\t\tReboot the target (if supported)\n"
395     send_user "\t--srcdir \[name\]\t\tThe test suite source code directory\n"
396     send_user "\t--status\t\tSet the exit status to fail on Tcl errors\n"
397     send_user "\t--strace \[number\]\tTurn on Expect tracing\n"
398     send_user "\t--target \[triplet\]\tThe canonical triplet of the target board\n"
399     send_user "\t--target_board \[name(s)\] The list of target boards to run tests on\n"
400     send_user "\t--tool \[name(s)\]\tRun tests on these tools\n"
401     send_user "\t--tool_exec \[name\]\tThe path to the tool executable to test\n"
402     send_user "\t--tool_opts \[options\]\tA list of additional options to pass to the tool\n"
403     send_user "\t--verbose, -v\t\tProduce verbose output\n"
404     send_user "\t--version, -V\t\tPrint all relevant version numbers\n"
405     send_user "\t--xml, -x\t\tWrite out an XML results file\n"
406     send_user "\t--D\[0-1\]\t\tTcl debugger\n"
407     send_user "\tscript.exp\[=arg(s)\]\tRun these tests only\n"
408     if { [info exists tool] } {
409         if { [info procs ${tool}_option_help] ne "" } {
410             ${tool}_option_help
411         }
412     }
416 # Parse the arguments the first time looking for these.  We will ultimately
417 # parse them twice.  Things are complicated because:
418 # - we want to parse --verbose early on
419 # - we don't want config files to override command line arguments
420 #   (eg: $base_dir/$local_init_file vs --host/--target)
421 # - we need some command line arguments before we can process some config files
422 #   (eg: --objdir before $objdir/$local_init_file, --host/--target before $DEJAGNU)
423 # The use of `arg_host_triplet' and `arg_target_triplet' lets us avoid parsing
424 # the arguments three times.
427 namespace eval ::dejagnu::command_line {
428     variable cmd_var_list [list]
430     proc save_cmd_var {name} {
431         variable cmd_var_list
433         upvar 1 $name target_var
434         lappend cmd_var_list $name $target_var
435     }
437     proc restore_cmd_vars {} {
438         variable cmd_var_list
440         foreach {name value} $cmd_var_list {
441             uplevel 1 [list set $name $value]
442         }
443         verbose "Variables set by command line arguments restored." 4
444     }
446     proc dump_cmd_vars {} {
447         variable cmd_var_list
449         verbose "Variables set by command line arguments:" 4
450         foreach {name value} $cmd_var_list {
451             verbose "  $name -> $value" 4
452         }
453     }
456 set arg_host_triplet ""
457 set arg_target_triplet ""
458 set arg_build_triplet ""
459 set argc [ llength $argv ]
460 for { set i 0 } { $i < $argc } { incr i } {
461     set option [lindex $argv $i]
463     # make all options have two hyphens
464     switch -glob -- $option {
465         "--*" {
466         }
467         "-*" {
468             set option "-$option"
469         }
470     }
472     # split out the argument for options that take them
473     switch -glob -- $option {
474         "--*=*" {
475             regexp {^[^=]*=(.*)$} $option nil optarg
476         }
477         "--bu*" -
478         "--g*" -
479         "--ho*" -
480         "--ig*"  -
481         "--loc*" -
482         "--m*"  -
483         "--ob*" -
484         "--ou*" -
485         "--sr*" -
486         "--str*" -
487         "--ta*" -
488         "--di*" -
489         "--to*" {
490             incr i
491             set optarg [lindex $argv $i]
492         }
493     }
495     switch -glob -- $option {
496         "--V*" -
497         "--vers*" {                     # (--version) version numbers
498             send_user "DejaGnu version\t$frame_version\n"
499             send_user "Expect version\t[exp_version]\n"
500             send_user "Tcl version\t[ info tclversion ]\n"
501             exit 0
502         }
504         "--bu*" {                       # (--build) the build host configuration
505             set arg_build_triplet $optarg
506             ::dejagnu::command_line::save_cmd_var arg_build_triplet
507             continue
508         }
510         "--g*" {                        # (--global_init) the global init file name
511             set global_init_file $optarg
512             ::dejagnu::command_line::save_cmd_var global_init_file
513             continue
514         }
516         "--host_bo*" {
517             set host_board $optarg
518             ::dejagnu::command_line::save_cmd_var host_board
519             continue
520         }
522         "--ho*" {                       # (--host) the host configuration
523             set arg_host_triplet $optarg
524             ::dejagnu::command_line::save_cmd_var arg_host_triplet
525             continue
526         }
528         "--loc*" {                      # (--local_init) the local init file name
529             set local_init_file $optarg
530             ::dejagnu::command_line::save_cmd_var local_init_file
531             continue
532         }
534         "--ob*" {                       # (--objdir) where the test case object code lives
535             set objdir $optarg
536             ::dejagnu::command_line::save_cmd_var objdir
537             continue
538         }
540         "--sr*" {                       # (--srcdir) where the testsuite source code lives
541             set srcdir $optarg
542             ::dejagnu::command_line::save_cmd_var srcdir
543             continue
544         }
546         "--target_bo*" {
547             set target_list $optarg
548             ::dejagnu::command_line::save_cmd_var target_list
549             continue
550         }
552         "--ta*" {                       # (--target) the target configuration
553             set arg_target_triplet $optarg
554             ::dejagnu::command_line::save_cmd_var arg_target_triplet
555             continue
556         }
558         "--tool_opt*" {
559             set TOOL_OPTIONS $optarg
560             ::dejagnu::command_line::save_cmd_var TOOL_OPTIONS
561             continue
562         }
564         "--tool_exec*" {
565             set TOOL_EXECUTABLE $optarg
566             ::dejagnu::command_line::save_cmd_var TOOL_EXECUTABLE
567             continue
568         }
570         "--to*" {                       # (--tool) specify tool name
571             set tool $optarg
572             set comm_line_tool $optarg
573             ::dejagnu::command_line::save_cmd_var tool
574             ::dejagnu::command_line::save_cmd_var comm_line_tool
575             continue
576         }
578         "--di*" {
579             set cmdline_dir_to_run $optarg
580             ::dejagnu::command_line::save_cmd_var cmdline_dir_to_run
581             continue
582         }
584         "--v" -
585         "--verb*" {                     # (--verbose) verbose output
586             incr verbose
587             continue
588         }
590         "[A-Z0-9_-.]*=*" { # process makefile style args like CC=gcc, etc...
591             if {[regexp "^(\[A-Z0-9_-\]+)=(.*)$" $option junk var val]} {
592                 set $var $val
593                 verbose "$var is now $val"
594                 append makevars "set $var $val;" ;# FIXME: Used anywhere?
595                 unset junk var val
596             } else {
597                 send_error "Illegal variable specification:\n"
598                 send_error "$option\n"
599             }
600             continue
601         }
603     }
605 verbose "Verbose level is $verbose"
607 verbose [concat "Initial working directory is" [pwd]]
609 ::dejagnu::command_line::dump_cmd_vars
612 # get the users login name
614 if { $logname eq "" } {
615     if {[info exists env(USER)]} {
616         set logname $env(USER)
617     } else {
618         if {[info exists env(LOGNAME)]} {
619             set logname $env(LOGNAME)
620         } else {
621             # try getting it with whoami
622             catch "set logname [exec whoami]" tmp
623             if {[string match "*couldn't find*to execute*" $tmp]} {
624                 # try getting it with who am i
625                 unset tmp
626                 catch "set logname [exec who am i]" tmp
627                 if {[string match "*Command not found*" $tmp]} {
628                     send_user "ERROR: couldn't get the users login name\n"
629                     set logname "Unknown"
630                 } else {
631                     set logname [lindex [split $logname " !"] 1]
632                 }
633             }
634         }
635     }
638 verbose "Login name is $logname"
641 # lookfor_file -- try to find a file by searching up multiple directory levels
643 proc lookfor_file { dir name } {
644     foreach x [list . .. ../.. ../../.. ../../../..] {
645         verbose $dir/$x/$name 2
646         if {[file exists [file join $dir $name]]} {
647             return [file join $dir $name]
648         }
649         set dir [remote_file build dirname $dir]
650     }
651     return ""
655 # load_lib -- load a library by sourcing it
657 # If there a multiple files with the same name, stop after the first one found.
658 # The order is first look in the install dir, then in a parallel dir in the
659 # source tree (up one or two levels), then in the current dir.
661 proc load_lib { file } {
662     global verbose execpath tool
663     global libdir libdirs srcdir testsuitedir base_dir
664     global loaded_libs
666     if {[info exists loaded_libs($file)]} {
667         return
668     }
670     set loaded_libs($file) ""
671     set search_dirs [list ../lib $libdir $libdir/lib]
672     lappend search_dirs [file dirname [file dirname $srcdir]]/dejagnu/lib
673     lappend search_dirs $testsuitedir/lib
674     lappend search_dirs $execpath/lib "."
675     lappend search_dirs [file dirname [file dirname [file dirname $srcdir]]]/dejagnu/lib
676     if {[info exists libdirs]} {
677         lappend search_dirs $libdirs
678     }
679     if { [search_and_load_file "library file" $file $search_dirs ] == 0 } {
680         send_error "ERROR: Couldn't find library file $file.\n"
681         exit 1
682     }
686 # Begin sourcing the config files.
687 # All are sourced in order.
689 # Search order:
690 #    (local)    $base_dir/$local_init_file -> $objdir/$local_init_file ->
691 #    (global)   installed($global_init_file) -> $DEJAGNU -> $HOME/.dejagnurc
693 # For the normal case, we expect $base_dir/$local_init_file to set
694 # host_triplet and target_triplet.
697 load_file [file join $base_dir $local_init_file]
699 # Ensure that command line parameters override testsuite init files.
700 ::dejagnu::command_line::restore_cmd_vars
703 # If objdir didn't get set in $base_dir/$local_init_file, set it to
704 # $base_dir.  Make sure we source $objdir/$local_init_file in case
705 # $base_dir/$local_init_file doesn't exist and objdir was given on the
706 # command line.
709 if { $objdir eq "." || $objdir eq $srcdir } {
710     set objdir $base_dir
711 } else {
712     load_file [file join $objdir $local_init_file]
715 # Ensure that command line parameters override testsuite init files.
716 ::dejagnu::command_line::restore_cmd_vars
719 # Find the testsuite.
722 # The DejaGnu manual has always stated that a testsuite must be in a
723 # testsuite/ subdirectory.
725 verbose "Finding testsuite ..." 3
726 verbose "\$base_dir -> $base_dir" 3
727 verbose "\$srcdir -> $srcdir" 3
728 verbose "\$objdir -> $objdir" 3
729 verbose [concat "file tail \$srcdir -> " [file tail $srcdir]] 3
730 verbose [concat "file join \$srcdir testsuite -> " \
731              [file join $srcdir testsuite]] 3
732 verbose [concat "file isdirectory [file join \$srcdir testsuite] -> " \
733              [file isdirectory [file join $srcdir testsuite]]] 3
734 verbose [concat "file tail \$base_dir -> " [file tail $base_dir]] 3
736 if { [file tail $srcdir] eq "testsuite" } {
737     # Subdirectory case -- $srcdir includes testsuite/
738     set testsuitedir $srcdir
739     set testbuilddir $objdir
740 } elseif { [file tail $srcdir] ne "testsuite"
741            && [file isdirectory [file join $srcdir testsuite]] } {
742     # Top-level case -- testsuite in $srcdir/testsuite/
743     set testsuitedir [file join $srcdir testsuite]
744     set testbuilddir [file join $objdir testsuite]
745 } elseif { $srcdir eq "." && [file tail $base_dir] eq "testsuite" } {
746     # Development scaffold case -- testsuite in ".", but "." is "testsuite"
747     set testsuitedir $base_dir
748     set testbuilddir $base_dir
749 } else {
750     if { $testsuitedir eq "testsuite" && $testbuilddir eq "testsuite" } {
751         # Broken legacy case -- testsuite not actually in testsuite/
752         # Produce a warning, but continue.
753         send_error "WARNING: testsuite is not in a testsuite/ directory.\n"
754         set testsuitedir $srcdir
755         set testbuilddir $objdir
756     } else {
757         # Custom case -- all variables are assumed to have been set correctly
758     }
761 verbose "Finding testsuite ... done" 3
763 # Well, this just demonstrates the real problem...
764 if {![info exists tool_root_dir]} {
765     set tool_root_dir [file dirname $objdir]
766     if {[file exists [file join $tool_root_dir testsuite]]} {
767         set tool_root_dir [file dirname $tool_root_dir]
768     }
771 verbose "Using test sources in $srcdir"
772 verbose "Using test binaries in $objdir"
773 verbose "Testsuite root is $testsuitedir"
774 verbose "Tool root directory is $tool_root_dir"
776 set execpath [file dirname $argv0]
778 # The runtest.exp file is installed directly in libdir.
779 # Conveniently, the source tree layout is the same as the installed libdir.
780 set libdir [file dirname $argv0]
781 if {[info exists env(DEJAGNULIBS)]} {
782     set libdir $env(DEJAGNULIBS)
784 # list of extra search directories used by load_lib to look for libs
785 set libdirs {}
787 verbose "Using $libdir to find libraries"
790 # If the host or target was given on the command line, override the above
791 # config files.  We allow $DEJAGNU to massage them though in case it would
792 # ever want to do such a thing.
794 if { $arg_host_triplet ne "" } {
795     set host_triplet $arg_host_triplet
797 if { $arg_build_triplet ne "" } {
798     set build_triplet $arg_build_triplet
801 # If we only specify --host, then that must be the build machine too,
802 # and we're stuck using the old functionality of a simple cross test.
803 if {[expr { $build_triplet eq ""  &&  $host_triplet ne "" } ]} {
804     set build_triplet $host_triplet
806 # If we only specify --build, then we'll use that as the host too.
807 if {[expr { $build_triplet ne "" && $host_triplet eq "" } ]} {
808     set host_triplet $build_triplet
810 unset arg_host_triplet arg_build_triplet
813 # If the build machine type hasn't been specified by now, use config.guess.
816 if {[expr {$build_triplet eq "" && $host_triplet eq ""}]} {
817     # find config.guess
818     foreach dir [list $libdir $libdir/libexec $libdir/.. $execpath $srcdir $srcdir/.. $srcdir/../..] {
819         verbose "Looking for $dir/config.guess" 2
820         if {[file exists [file join $dir config.guess]]} {
821             set config_guess [file join $dir config.guess]
822             verbose "Found [file join $dir config.guess]"
823             break
824         }
825     }
827     # get the canonical triplet
828     if {![info exists config_guess]} {
829         send_error "ERROR: Couldn't find config.guess program.\n"
830         exit 1
831     }
832     if { [info exists ::env(CONFIG_SHELL)] } {
833         if { [catch {exec $::env(CONFIG_SHELL) $config_guess} build_triplet] } {
834             if { [lindex $::errorCode 0] eq "CHILDSTATUS" } {
835                 send_error "ERROR: Running config.guess with\
836                                         CONFIG_SHELL=$::env(CONFIG_SHELL)\
837                                         exited on code\
838                                         [lindex $::errorCode 2].\n"
839             } else {
840                 send_error "ERROR: Running config.guess with\
841                                         CONFIG_SHELL=$::env(CONFIG_SHELL)\
842                                         produced error:\n"
843                 send_error "        $::errorCode\n"
844             }
845         }
846     } elseif { [info exists ::env(SHELL)] } {
847         if { [catch {exec $::env(SHELL) $config_guess} build_triplet] } {
848             if { [lindex $::errorCode 0] eq "CHILDSTATUS" } {
849                 send_error "ERROR: Running config.guess with\
850                                         SHELL=$::env(SHELL)\
851                                         exited on code\
852                                         [lindex $::errorCode 2].\n"
853             } else {
854                 send_error "ERROR: Running config.guess with\
855                                         SHELL=$::env(SHELL)\
856                                         produced error:\n"
857                 send_error "        $::errorCode\n"
858             }
859         }
860     } else {
861         if { [catch {exec $config_guess} build_triplet] } {
862             if { [lindex $::errorCode 0] eq "CHILDSTATUS" } {
863                 send_error "ERROR: Running config.guess exited on code\
864                                         [lindex $::errorCode 2].\n"
865             } else {
866                 send_error "ERROR: Running config.guess produced error:\n"
867                 send_error "        $::errorCode\n"
868             }
869         }
870     }
871     if { ![regexp -- {^[[:alnum:]_.]+(-[[:alnum:]_.]+)+$} $build_triplet] } {
872         send_error "ERROR: Running config.guess produced bogus build triplet:\n"
873         send_error "        $build_triplet\n"
874         send_error "       (Perhaps you need to set CONFIG_SHELL or\
875                                 SHELL in your environment\n"
876         send_error "        to the absolute file name of a POSIX shell?)\n"
877         exit 1
878     }
879     verbose "Assuming build host is $build_triplet"
880     if { $host_triplet eq "" } {
881         set host_triplet $build_triplet
882     }
886 # Figure out the target. If the target hasn't been specified, then we have to
887 # assume we are native.
889 if { $arg_target_triplet ne "" } {
890     set target_triplet $arg_target_triplet
891 } elseif { $target_triplet eq "" } {
892     set target_triplet $build_triplet
893     verbose "Assuming native target is $target_triplet" 2
895 unset arg_target_triplet
897 # Default target_alias to target_triplet.
899 if {$target_alias eq ""} {
900     set target_alias $target_triplet
903 proc get_local_hostname { } {
904     if {[catch "info hostname" hb]} {
905         set hb ""
906     } else {
907         regsub "\\..*$" $hb "" hb
908     }
909     verbose "hostname=$hb" 3
910     return $hb
914 # We put these here so that they can be overridden later by site.exp or
915 # friends.
917 # Set up the target as machine NAME. We also load base-config.exp as a
918 # default configuration. The config files are sourced with the global
919 # variable $board set to the name of the current target being defined.
921 proc setup_target_hook { whole_name name } {
922     global board
923     global host_board
925     if {[info exists host_board]} {
926         set hb $host_board
927     } else {
928         set hb [get_local_hostname]
929     }
931     set board $whole_name
933     global board_type
934     set board_type "target"
936     load_config base-config.exp
937     if {![load_board_description $name $whole_name $hb]} {
938         if { $name ne "unix" } {
939             perror "couldn't load description file for $name"
940             exit 1
941         } else {
942             load_generic_config "unix"
943         }
944     }
946     if {[board_info $board exists generic_name]} {
947         load_tool_target_config [board_info $board generic_name]
948     }
950     unset board
951     unset board_type
953     push_target $whole_name
955     if { [info procs ${whole_name}_init] ne "" } {
956         ${whole_name}_init $whole_name
957     }
959     if { ![isnative] && ![isremote target] } {
960         global env build_triplet target_triplet
961         if { (![info exists env(DEJAGNU)]) && ($build_triplet ne $target_triplet) } {
962             warning "Assuming target board is the local machine (which is probably wrong).\nYou may need to set your DEJAGNU environment variable."
963         }
964     }
968 # Clean things up afterwards.
970 proc cleanup_target_hook { name } {
971     global tool
972     # Clean up the target board.
973     if { [info procs ${name}_exit] ne "" } {
974         ${name}_exit
975     }
976     # We also call the tool exit routine here.
977     if {[info exists tool]} {
978         if { [info procs ${tool}_exit] ne "" } {
979             ${tool}_exit
980         }
981     }
982     remote_close target
983     pop_target
986 proc setup_host_hook { name } {
987     global board
988     global board_info
989     global board_type
991     set board $name
992     set board_type "host"
994     load_board_description $name
995     unset board
996     unset board_type
997     push_host $name
998     if { [info procs ${name}_init] ne "" } {
999         ${name}_init $name
1000     }
1003 proc setup_build_hook { name } {
1004     global board
1005     global board_info
1006     global board_type
1008     set board $name
1009     set board_type "build"
1011     load_board_description $name
1012     unset board
1013     unset board_type
1014     push_build $name
1015     if { [info procs ${name}_init] ne "" } {
1016         ${name}_init $name
1017     }
1021 # Find and load the global config file if it exists.
1022 # The global config file is used to set the connect mode and other
1023 # parameters specific to each particular target.
1024 # These files assume the host and target have been set.
1027 if { [load_file -- [file join $libdir $global_init_file]] == 0 } {
1028     # If $DEJAGNU isn't set either then there isn't any global config file.
1029     # Warn the user as there really should be one.
1030     if { ! [info exists env(DEJAGNU)] } {
1031         send_error "WARNING: Couldn't find the global config file.\n"
1032     }
1035 if {[info exists env(DEJAGNU)]} {
1036     if { [load_file -- $env(DEJAGNU)] == 0 } {
1037         # It may seem odd to only issue a warning if there isn't a global
1038         # config file, but issue an error if $DEJAGNU is erroneously defined.
1039         # Since $DEJAGNU is set there is *supposed* to be a global config file,
1040         # so the current behaviour seems reasonable.
1041         send_error "ERROR: global config file $env(DEJAGNU) not found.\n"
1042         exit 1
1043     }
1044     if {![info exists boards_dir]} {
1045         set boards_dir "[file dirname $env(DEJAGNU)]/boards"
1046     }
1049 # Load user .dejagnurc file last as the ultimate override.
1050 load_file ~/.dejagnurc
1052 if {![info exists boards_dir]} {
1053     set boards_dir ""
1057 # parse out the config parts of the triplet name
1060 # build values
1061 if { $build_cpu eq "" } {
1062     regsub -- "-.*-.*" $build_triplet "" build_cpu
1064 if { $build_vendor eq "" } {
1065     regsub -- "^\[a-z0-9\]*-" $build_triplet "" build_vendor
1066     regsub -- "-.*" $build_vendor "" build_vendor
1068 if { $build_os eq "" } {
1069     regsub -- ".*-.*-" $build_triplet "" build_os
1072 # host values
1073 if { $host_cpu eq "" } {
1074     regsub -- "-.*-.*" $host_triplet "" host_cpu
1076 if { $host_vendor eq "" } {
1077     regsub -- "^\[a-z0-9\]*-" $host_triplet "" host_vendor
1078     regsub -- "-.*" $host_vendor "" host_vendor
1080 if { $host_os eq "" } {
1081     regsub -- ".*-.*-" $host_triplet "" host_os
1084 # target values
1085 if { $target_cpu eq "" } {
1086     regsub -- "-.*-.*" $target_triplet "" target_cpu
1088 if { $target_vendor eq "" } {
1089     regsub -- "^\[a-z0-9\]*-" $target_triplet "" target_vendor
1090     regsub -- "-.*" $target_vendor "" target_vendor
1092 if { $target_os eq "" } {
1093     regsub -- ".*-.*-" $target_triplet "" target_os
1097 # Load the primary tool initialization file.
1100 proc load_tool_init { file } {
1101     global srcdir testsuitedir
1102     global loaded_libs
1104     if {[info exists loaded_libs(tool/$file)]} {
1105         return
1106     }
1108     set loaded_libs(tool/$file) ""
1110     lappend searchpath [file join $testsuitedir lib tool]
1111     lappend searchpath [file join $testsuitedir lib]
1112     # for legacy testsuites that might have files in lib/ instead of
1113     # testsuite/lib/ in the package source tree; deprecated
1114     lappend searchpath [file join $srcdir lib]
1116     if { ![search_and_load_file "tool init file" [list $file] $searchpath] } {
1117         warning "Couldn't find tool init file"
1118     }
1122 # load the testing framework libraries
1124 load_lib utils.exp
1125 load_lib framework.exp
1126 load_lib debugger.exp
1127 load_lib remote.exp
1128 load_lib target.exp
1129 load_lib targetdb.exp
1130 load_lib libgloss.exp
1132 # Initialize the test counters and reset them to 0.
1133 init_testcounts
1134 reset_vars
1137 # Parse the command line arguments.
1140 # Load the tool initialization file. Allow the --tool option to override
1141 # what's set in the site.exp file.
1142 if {[info exists comm_line_tool]} {
1143     set tool $comm_line_tool
1146 if {[info exists tool]} {
1147     load_tool_init ${tool}.exp
1150 set argc [ llength $argv ]
1151 for { set i 0 } { $i < $argc } { incr i } {
1152     set option [ lindex $argv $i ]
1154     # make all options have two hyphens
1155     switch -glob -- $option {
1156         "--*" {
1157         }
1158         "-*" {
1159             set option "-$option"
1160         }
1161     }
1163     # split out the argument for options that take them
1164     switch -glob -- $option {
1165         "--*=*" {
1166             regexp {^[^=]*=(.*)$} $option nil optarg
1167         }
1168         "--bu*" -
1169         "--g*" -
1170         "--ho*" -
1171         "--ig*"  -
1172         "--loc*" -
1173         "--m*"  -
1174         "--ob*" -
1175         "--ou*" -
1176         "--sr*" -
1177         "--str*" -
1178         "--ta*" -
1179         "--di*" -
1180         "--to*" {
1181             incr i
1182             set optarg [lindex $argv $i]
1183         }
1184     }
1186     switch -glob -- $option {
1187         "--v*" {                        # (--verbose) verbose output
1188             # Already parsed.
1189             continue
1190         }
1192         "--g*" {                        # (--global_init) the global init file name
1193             # Already parsed (and no longer useful).  The file has been loaded.
1194             continue
1195         }
1197         "--loc*" {                      # (--local_init) the local init file name
1198             # Already parsed (and no longer useful).  The file has been loaded.
1199             continue
1200         }
1202         "--bu*" {                       # (--build) the build host configuration
1203             # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1204             continue
1205         }
1207         "--ho*" {                       # (--host) the host configuration
1208             # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1209             continue
1210         }
1212         "--target_bo*" {
1213             # Set it again, father knows best.
1214             set target_list $optarg
1215             continue
1216         }
1218         "--ta*" {                       # (--target) the target configuration
1219             # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1220             continue
1221         }
1223         "--a*" {                        # (--all) print all test output to screen
1224             set all_flag 1
1225             verbose "Print all test output to screen"
1226             continue
1227         }
1229         "--di*" {
1230             # Already parsed (and don't set again).  Let $DEJAGNU rename it.
1231             continue
1232         }
1235         "--de*" {                       # (--debug) expect internal debugging
1236             if {[file exists ./dbg.log]} {
1237                 catch [file delete -force -- dbg.log]
1238             }
1239             if { $verbose > 2 } {
1240                 exp_internal -f dbg.log 1
1241             } else {
1242                 exp_internal -f dbg.log 0
1243             }
1244             verbose "Expect Debugging is ON"
1245             continue
1246         }
1248         "--D[01]" {                     # (-Debug) turn on Tcl debugger
1249             # The runtest shell script handles this option, but it
1250             # still appears in the options in the Tcl code.
1251             verbose "Tcl debugger is ON"
1252             continue
1253         }
1255         "--m*" {                        # (--mail) mail the output
1256             set mailing_list $optarg
1257             set mail_logs 1
1258             verbose "Mail results to $mailing_list"
1259             continue
1260         }
1262         "--r*" {                        # (--reboot) reboot the target
1263             set reboot 1
1264             verbose "Will reboot the target (if supported)"
1265             continue
1266         }
1268         "--ob*" {                       # (--objdir) where the test case object code lives
1269             # Already parsed, but parse again to make sure command line
1270             # options override any config file.
1271             set objdir $optarg
1272             verbose "Using test binaries in $objdir"
1273             continue
1274         }
1276         "--ou*" {                       # (--outdir) where to put the output files
1277             set outdir $optarg
1278             verbose "Test output put in $outdir"
1279             continue
1280         }
1282         "--log_dialog*" {
1283             incr log_dialog
1284             continue
1285         }
1287         "*.exp" {                       #  specify test names to run
1288             set all_runtests($option) ""
1289             verbose "Running only tests $option"
1290             continue
1291         }
1293         "*.exp=*" {                     #  specify test names to run
1294             set tmp [split $option "="]
1295             set all_runtests([lindex $tmp 0]) [lindex $tmp 1]
1296             verbose "Running only tests $option"
1297             unset tmp
1298             continue
1299         }
1301         "--ig*" {                       #  (--ignore) specify test names to exclude
1302             set ignoretests $optarg
1303             verbose "Ignoring test $ignoretests"
1304             continue
1305         }
1307         "--sr*" {                       # (--srcdir) where the testsuite source code lives
1308             # Already parsed, but parse again to make sure command line
1309             # options override any config file.
1311             set srcdir $optarg
1312             continue
1313         }
1315         "--str*" {                      # (--strace) expect trace level
1316             set tracelevel $optarg
1317             strace $tracelevel
1318             verbose "Source Trace level is now $tracelevel"
1319             continue
1320         }
1322         "--sta*" {                      # (--status) exit status flag
1323             # preserved for compatability, do nothing
1324             continue
1325         }
1327         "--tool_opt*" {
1328             continue
1329         }
1331         "--tool_exec*" {
1332             set TOOL_EXECUTABLE $optarg
1333             continue
1334         }
1336         "--to*" {                       # (--tool) specify tool name
1337             set tool $optarg
1338             verbose "Testing $tool"
1339             continue
1340         }
1342         "--x*" {
1343             set xml 1
1344             verbose "XML logging turned on"
1345             continue
1346         }
1348         "--he*" {                       # (--help) help text
1349             usage
1350             exit 0
1351         }
1353         "[A-Z0-9_-.]*=*" { # skip makefile style args like CC=gcc, etc... (processed in first pass)
1354             continue
1355         }
1357         default {
1358             if {[info exists tool]} {
1359                 if { [info procs ${tool}_option_proc] ne "" } {
1360                     if {[${tool}_option_proc $option]} {
1361                         continue
1362                     }
1363                 }
1364             }
1365             send_error "\nIllegal Argument \"$option\"\n"
1366             send_error "try \"runtest --help\" for option list\n"
1367             exit 1
1368         }
1369     }
1373 # check for a few crucial variables
1375 if {![info exists tool]} {
1376     send_error "WARNING: No tool specified\n"
1377     set tool ""
1381 # initialize a few Tcl variables to something other than their default
1383 if { $verbose > 2 || $log_dialog } {
1384     log_user 1
1385 } else {
1386     log_user 0
1389 set timeout 10
1394 # open log files
1396 open_logs
1398 # print the config info
1399 clone_output "Test run by $logname on [timestamp -format %c]"
1400 if {[is3way]} {
1401     clone_output "Target is $target_triplet"
1402     clone_output "Host   is $host_triplet"
1403     clone_output "Build  is $build_triplet"
1404 } else {
1405     if {[isnative]} {
1406         clone_output "Native configuration is $target_triplet"
1407     } else {
1408         clone_output "Target is $target_triplet"
1409         clone_output "Host   is $host_triplet"
1410     }
1413 clone_output "\n\t\t=== $tool tests ===\n"
1416 # Look for the generic board configuration file. It searches in several
1417 # places: $libdir/config, $libdir/../config, and $boards_dir.
1420 proc load_generic_config { name } {
1421     global libdir
1422     global board
1423     global board_info
1424     global boards_dir
1425     global board_type
1427     if {[info exists board]} {
1428         if {![info exists board_info($board,generic_name)]} {
1429             set board_info($board,generic_name) $name
1430         }
1431     }
1433     if {[info exists board_type]} {
1434         set type "for $board_type"
1435     } else {
1436         set type ""
1437     }
1439     set dirlist [concat $libdir/config [file dirname $libdir]/config $boards_dir]
1440     set result [search_and_load_file "generic interface file $type" $name.exp $dirlist]
1442     return $result
1446 # Load the tool-specific target description.
1448 proc load_config { args } {
1449     global testsuitedir
1451     set found 0
1453     return [search_and_load_file "tool-and-target-specific interface file" $args [list $testsuitedir/config $testsuitedir/../config $testsuitedir/../../config $testsuitedir/../../../config]]
1457 # Find the files that set up the configuration for the target. There
1458 # are assumed to be two of them; one defines a basic set of
1459 # functionality for the target that can be used by all tool
1460 # testsuites, and the other defines any necessary tool-specific
1461 # functionality. These files are loaded via load_config.
1463 # These used to all be named $target_abbrev-$tool.exp, but as the
1464 # $tool variable goes away, it's now just $target_abbrev.exp.  First
1465 # we look for a file named with both the abbrev and the tool names.
1466 # Then we look for one named with just the abbrev name. Finally, we
1467 # look for a file called default, which is the default actions, as
1468 # some tools could be purely host based. Unknown is mostly for error
1469 # trapping.
1472 proc load_tool_target_config { name } {
1473     global target_os libdir testsuitedir
1475     set found [load_config $name.exp $target_os.exp "default.exp" "unknown.exp"]
1477     if { $found == 0 } {
1478         send_error "WARNING: Couldn't find tool config file for $name, using default.\n"
1479         # If we can't load the tool init file, this must be a simple natively hosted
1480         # test suite, so we use the default procs for Unix.
1481         if { [search_and_load_file "library file" default.exp [list $libdir $libdir/config [file dirname [file dirname $testsuitedir]]/dejagnu/config $testsuitedir/config . [file dirname [file dirname [file dirname $testsuitedir]]]/dejagnu/config]] == 0 } {
1482             send_error "ERROR: Couldn't find default tool init file.\n"
1483             exit 1
1484         }
1485     }
1489 # Find the file that describes the machine specified by board_name.
1492 proc load_board_description { board_name args } {
1493     global libdir
1494     global board
1495     global board_info
1496     global boards_dir
1497     global board_type
1499     set dejagnu ""
1501     if { [llength $args] > 0 } {
1502         set whole_name [lindex $args 0]
1503     } else {
1504         set whole_name $board_name
1505     }
1507     set board_info($whole_name,name) $whole_name
1508     if {![info exists board]} {
1509         set board $whole_name
1510         set board_set 1
1511     } else {
1512         set board_set 0
1513     }
1515     set dirlist {}
1516     if { [llength $args] > 1 } {
1517         set suffix [lindex $args 1]
1518         if { $suffix ne "" } {
1519             foreach x $boards_dir {
1520                 lappend dirlist $x/$suffix
1521             }
1522             lappend dirlist $libdir/baseboards/$suffix
1523         }
1524     }
1525     set dirlist [concat $dirlist $boards_dir]
1526     lappend dirlist $libdir/baseboards
1527     verbose "dirlist is $dirlist"
1528     if {[info exists board_type]} {
1529         set type "for $board_type"
1530     } else {
1531         set type ""
1532     }
1533     if {![info exists board_info($whole_name,isremote)]} {
1534         set board_info($whole_name,isremote) 1
1535         if {[info exists board_type]} {
1536             if { $board_type eq "build" } {
1537                 set board_info($whole_name,isremote) 0
1538             }
1539         }
1540         if { $board_name eq [get_local_hostname] } {
1541             set board_info($whole_name,isremote) 0
1542         }
1543     }
1544     search_and_load_file "standard board description file $type" standard.exp $dirlist
1545     set found [search_and_load_file "board description file $type" $board_name.exp $dirlist]
1546     if { $board_set != 0 } {
1547         unset board
1548     }
1550     return $found
1554 # Find the base-level file that describes the machine specified by args. We
1555 # only look in one directory, $libdir/baseboards.
1558 proc load_base_board_description { board_name } {
1559     global libdir
1560     global board
1561     global board_info
1562     global board_type
1564     set board_set 0
1565     set board_info($board_name,name) $board_name
1566     if {![info exists board]} {
1567         set board $board_name
1568         set board_set 1
1569     }
1570     if {[info exists board_type]} {
1571         set type "for $board_type"
1572     } else {
1573         set type ""
1574     }
1575     if {![info exists board_info($board_name,isremote)]} {
1576         set board_info($board_name,isremote) 1
1577         if {[info exists board_type]} {
1578             if { $board_type eq "build" } {
1579                 set board_info($board_name,isremote) 0
1580             }
1581         }
1582     }
1584     if { $board_name eq [get_local_hostname] } {
1585         set board_info($board_name,isremote) 0
1586     }
1587     set found [search_and_load_file "board description file $type" $board_name.exp [list $libdir/baseboards]]
1588     if { $board_set != 0 } {
1589         unset board
1590     }
1592     return $found
1596 # Source the testcase in TEST_FILE_NAME.
1599 proc runtest { test_file_name } {
1600     global prms_id
1601     global bug_id
1602     global test_result
1603     global errcnt warncnt
1604     global errorCode
1605     global errorInfo
1606     global tool
1607     global testdir
1609     clone_output "Running $test_file_name ..."
1610     set prms_id 0
1611     set bug_id  0
1612     set errcnt  0
1613     set warncnt 0
1614     set test_result ""
1616     # set testdir so testsuite file -test has a starting point
1617     set testdir [file dirname $test_file_name]
1619     if {[file exists $test_file_name]} {
1620         set timestart [timestamp]
1622         if {[info exists tool]} {
1623             if { [info procs ${tool}_init] ne "" } {
1624                 ${tool}_init $test_file_name
1625             }
1626         }
1628         if { [catch "uplevel #0 source $test_file_name" msg] == 1 } {
1629             # If we have a Tcl error, propagate the exit status so
1630             # that 'make' (if it invokes runtest) notices the error.
1631             global exit_status exit_error
1632             # exit error is set by the --status command line option
1633             if { $exit_status == 0 } {
1634                 set exit_status 2
1635             }
1636             set new_error [list $test_file_name $msg]
1637             # We can't call `perror' here, it resets `errorInfo'
1638             # before we want to look at it.  Also remember that perror
1639             # increments `errcnt'.  If we do call perror we'd have to
1640             # reset errcnt afterwards.
1641             clone_output "ERROR: tcl error sourcing $test_file_name."
1642             if {[info exists errorCode]} {
1643                 clone_output "ERROR: tcl error code $errorCode"
1644                 lappend new_error $errorCode
1645             } else {
1646                 lappend new_error [list]
1647             }
1648             if {[info exists errorInfo]} {
1649                 clone_output "ERROR: $errorInfo"
1650                 lappend new_error $errorInfo
1651                 unset errorInfo
1652             } else {
1653                 lappend new_error [list]
1654             }
1655             lappend ::dejagnu::error::list $new_error
1656             unresolved "testcase '$test_file_name' aborted due to Tcl error"
1657         }
1659         if {[info exists tool]} {
1660             if { [info procs ${tool}_finish] ne "" } {
1661                 ${tool}_finish
1662             }
1663         }
1664         set timeend [timestamp]
1665         set timediff [expr {$timeend - $timestart}]
1666         verbose -log "testcase $test_file_name completed in $timediff seconds" 4
1667     } else {
1668         # This should never happen, but maybe if the file got removed
1669         # between the `find' above and here.
1670         perror "$test_file_name does not exist." 0
1671     }
1674 # Trap some signals so we know what's happening.  These replace the previous
1675 # ones because we've now loaded the library stuff.
1677 if {![exp_debug]} {
1678     foreach sig {{SIGINT {interrupted by user} 130} \
1679                      {SIGQUIT {interrupted by user} 131} \
1680                      {SIGTERM {terminated} 143}} {
1681         set signal [lindex $sig 0]
1682         set str [lindex $sig 1]
1683         set code [lindex $sig 2]
1684         trap "send_error \"got a \[trap -name\] signal, $str \\n\"; set exit_status $code; log_and_exit;" $signal
1685         verbose "setting trap for $signal to $str" 1
1686     }
1687     unset signal str sig
1691 # Given a list of targets, process any iterative lists.
1693 proc process_target_variants { target_list } {
1694     set result {}
1695     foreach x $target_list {
1696         if {[regexp "\\(" $x]} {
1697             regsub {^.*\(([^()]*)\)$} $x {\1} variant_list
1698             regsub {\([^(]*$} $x "" x
1699             set list [process_target_variants $x]
1700             set result {}
1701             foreach x $list {
1702                 set result [concat $result [iterate_target_variants $x [split $variant_list ","]]]
1703             }
1704         } elseif {[regexp "\{" $x]} {
1705             regsub "^.*\{(\[^\{\}\]*)\}$" $x {\1} variant_list
1706             regsub "\{\[^\{\]*$" $x "" x
1707             set list [process_target_variants $x]
1708             foreach x $list {
1709                 foreach i [split $variant_list ","] {
1710                     set name $x
1711                     if { $i ne "" } {
1712                         append name "/" $i
1713                     }
1714                     lappend result $name
1715                 }
1716             }
1717         } else {
1718             lappend result $x
1719         }
1720     }
1721     return $result
1724 proc iterate_target_variants { target variants } {
1725     return [iterate_target_variants_two $target $target $variants]
1729 # Given a list of variants, produce the list of all possible combinations.
1731 proc iterate_target_variants_two { orig_target target variants } {
1733     if { [llength $variants] == 0 } {
1734         return [list $target]
1735     } else {
1736         if { [llength $variants] > 1 } {
1737             set result [iterate_target_variants_two $orig_target $target [lrange $variants 1 end]]
1738         } else {
1739             if { $target ne $orig_target } {
1740                 set result [list $target]
1741             } else {
1742                 set result {}
1743             }
1744         }
1745         if { [lindex $variants 0] ne "" } {
1746             append target "/" [lindex $variants 0]
1747             return [concat $result [iterate_target_variants_two $orig_target $target [lrange $variants 1 end]]]
1748         } else {
1749             return [concat $result $target]
1750         }
1751     }
1754 setup_build_hook [get_local_hostname]
1756 if {[info exists host_board]} {
1757     setup_host_hook $host_board
1758 } else {
1759     set hb [get_local_hostname]
1760     if { $hb ne "" } {
1761         setup_host_hook $hb
1762     }
1766 # main test execution loop
1769 if {[info exists errorInfo]} {
1770     unset errorInfo
1774 # make sure we have only single path delimiters
1775 regsub -all {([^/])//*} $srcdir {\1/} srcdir
1776 regsub -all {([^/])//*} $objdir {\1/} objdir
1777 regsub -all {([^/])//*} $testsuitedir {\1/} testsuitedir
1778 regsub -all {([^/])//*} $testbuilddir {\1/} testbuilddir
1780 if {![info exists target_list]} {
1781     # Make sure there is at least one target machine. It's probably a Unix box,
1782     # but that's just a guess.
1783     set target_list { "unix" }
1784 } else {
1785     verbose "target list is $target_list"
1789 # Iterate through the list of targets.
1791 global current_target
1793 set target_list [process_target_variants $target_list]
1795 set target_count [llength $target_list]
1797 clone_output "Schedule of variations:"
1798 foreach current_target $target_list {
1799     clone_output "    $current_target"
1801 clone_output ""
1804 foreach current_target $target_list {
1805     verbose "target is $current_target"
1806     set current_target_name $current_target
1807     set tlist [split $current_target /]
1808     set current_target [lindex $tlist 0]
1809     set board_variant_list [lrange $tlist 1 end]
1811     # Set the counts for this target to 0.
1812     reset_vars
1813     clone_output "Running target $current_target_name"
1815     setup_target_hook $current_target_name $current_target
1817     # If multiple passes requested, set them up.  Otherwise prepare just one.
1818     # The format of `MULTIPASS' is a list of elements containing
1819     # "{ name var1=value1 ... }" where `name' is a generic name for the pass and
1820     # currently has no other meaning.
1822     global env
1824     if { [info exists MULTIPASS] } {
1825         set multipass $MULTIPASS
1826     }
1827     if { $multipass eq "" } {
1828         set multipass { "" }
1829     }
1831     # If PASS is specified, we want to run only the tests specified.
1832     # Its value should be a number or a list of numbers that specify
1833     # the passes that we want to run.
1834     if {[info exists PASS]} {
1835         set pass $PASS
1836     } else {
1837         set pass ""
1838     }
1840     if {$pass ne ""} {
1841         set passes [list]
1842         foreach p $pass {
1843             foreach multipass_elem $multipass {
1844                 set multipass_name [lindex $multipass_elem 0]
1845                 if {$p == $multipass_name} {
1846                     lappend passes $multipass_elem
1847                     break
1848                 }
1849             }
1850         }
1851         set multipass $passes
1852     }
1854     foreach pass $multipass {
1856         # multipass_name is set for `record_test' to use (see framework.exp).
1857         if { [lindex $pass 0] ne "" } {
1858             set multipass_name [lindex $pass 0]
1859             clone_output "Running pass `$multipass_name' ..."
1860         } else {
1861             set multipass_name ""
1862         }
1863         set restore ""
1864         foreach varval [lrange $pass 1 end] {
1865             set tmp [string first "=" $varval]
1866             set var [string range $varval 0 [expr {$tmp - 1}]]
1867             # Save previous value.
1868             if {[info exists $var]} {
1869                 lappend restore "$var [list [eval concat \$$var]]"
1870             } else {
1871                 lappend restore $var
1872             }
1873             # Handle "CFLAGS=$CFLAGS foo".
1874             eval set $var \[string range \"$varval\" [expr {$tmp + 1}] end\]
1875             verbose "$var is now [eval concat \$$var]"
1876             unset tmp var
1877         }
1879         # look for the top level testsuites. if $tool doesn't
1880         # exist and there are no subdirectories in $testsuitedir, then
1881         # we print a warning and default to srcdir.
1882         set test_top_dirs [lsort [getdirs -all $testsuitedir $tool*]]
1883         if { $test_top_dirs eq "" } {
1884             send_error "WARNING: could not find testsuite; trying $srcdir.\n"
1885             set test_top_dirs [list $srcdir]
1886         } else {
1887             # JYG:
1888             # DejaGNU's notion of test tree and test files is very
1889             # general:
1890             # given $testsuitedir and $tool, any subdirectory (at any
1891             # level deep) with the "$tool" prefix starts a test tree
1892             # given a test tree, any *.exp file underneath (at any
1893             # level deep) is a test file.
1894             #
1895             # For test tree layouts with $tool prefix on
1896             # both a parent and a child directory, we need to eliminate
1897             # the child directory entry from test_top_dirs list.
1898             # e.g. gdb.hp/gdb.base-hp/ would result in two entries
1899             # in the list: gdb.hp, gdb.hp/gdb.base-hp.
1900             # If the latter not eliminated, test files under
1901             # gdb.hp/gdb.base-hp would be run twice (since test files
1902             # are gathered from all sub-directories underneath a
1903             # directory).
1904             #
1905             # Since $tool may be g++, etc. which could confuse
1906             # regexp, we cannot do the simpler test:
1907             #     ...
1908             #     if [regexp "$testsuitedir/.*$tool.*/.*$tool.*" $dir]
1909             #     ...
1910             # instead, we rely on the fact that test_top_dirs is
1911             # a sorted list of entries, and any entry that contains
1912             # the previous valid test top dir entry in its own pathname
1913             # must be excluded.
1915             set temp_top_dirs [list]
1916             set prev_dir ""
1917             foreach dir $test_top_dirs {
1918                 if { $prev_dir eq ""
1919                      || [string first $prev_dir/ $dir] == -1 } {
1920                     # the first top dir entry, or an entry that
1921                     # does not share the previous entry's entire
1922                     # pathname, record it as a valid top dir entry.
1923                     #
1924                     lappend temp_top_dirs $dir
1925                     set prev_dir $dir
1926                 }
1927             }
1928             set test_top_dirs $temp_top_dirs
1929         }
1930         verbose "Top level testsuite dirs are $test_top_dirs" 2
1931         set testlist ""
1932         if {[array exists all_runtests]} {
1933             foreach x [array names all_runtests] {
1934                 verbose "trying to glob $testsuitedir/$x" 2
1935                 set s [glob -nocomplain $testsuitedir/$x]
1936                 if { $s ne "" } {
1937                     set testlist [concat $testlist $s]
1938                 }
1939             }
1940         }
1941         #
1942         # If we have a list of tests, run all of them.
1943         #
1944         if { $testlist ne "" } {
1945             foreach test_name $testlist {
1946                 if { $ignoretests ne "" } {
1947                     if { 0 <= [lsearch $ignoretests [file tail $test_name]]} {
1948                         continue
1949                     }
1950                 }
1952                 # set subdir to the tail of the dirname after $srcdir,
1953                 # for the driver files that want it.  XXX this is silly.
1954                 # drivers should get a single var, not $srcdir/$subdir
1955                 set subdir [relative_filename $srcdir \
1956                                 [file dirname $test_name]]
1958                 # XXX not the right thing to do.
1959                 set runtests [list [file tail $test_name] ""]
1961                 runtest $test_name
1962             }
1963         } else {
1964             #
1965             # Go digging for tests.
1966             #
1967             foreach dir $test_top_dirs {
1968                 if { $dir ne $testsuitedir } {
1969                     # Ignore this directory if is a directory to be
1970                     # ignored.
1971                     if {[info exists ignoredirs] && $ignoredirs ne ""} {
1972                         set found 0
1973                         foreach directory $ignoredirs {
1974                             if {[string match *$directory* $dir]} {
1975                                 set found 1
1976                                 break
1977                             }
1978                         }
1979                         if { $found } {
1980                             continue
1981                         }
1982                     }
1984                     # Run the test if dir_to_run was specified as a
1985                     # value (for example in MULTIPASS) and the test
1986                     # directory matches that directory.
1987                     if {[info exists dir_to_run] && $dir_to_run ne ""} {
1988                         # JYG: dir_to_run might be a space delimited list
1989                         # of directories.  Look for match on each item.
1990                         set found 0
1991                         foreach directory $dir_to_run {
1992                             if {[string match *$directory* $dir]} {
1993                                 set found 1
1994                                 break
1995                             }
1996                         }
1997                         if {!$found} {
1998                             continue
1999                         }
2000                     }
2002                     # Run the test if cmdline_dir_to_run was specified
2003                     # by the user using --directory and the test
2004                     # directory matches that directory
2005                     if {[info exists cmdline_dir_to_run] \
2006                             && $cmdline_dir_to_run ne ""} {
2007                         # JYG: cmdline_dir_to_run might be a space delimited
2008                         # list of directories.  Look for match on each item.
2009                         set found 0
2010                         foreach directory $cmdline_dir_to_run {
2011                             # Look for a directory that ends with the
2012                             # provided --directory name.
2013                             if {[string match $directory $dir]
2014                                 || [string match "*/$directory" $dir]} {
2015                                 set found 1
2016                                 break
2017                             }
2018                         }
2019                         if {!$found} {
2020                             continue
2021                         }
2022                     }
2024                     foreach test_name [lsort [find $dir *.exp]] {
2025                         if { $test_name eq "" } {
2026                             continue
2027                         }
2028                         # Ignore this one if asked to.
2029                         if { $ignoretests ne "" } {
2030                             if { 0 <= [lsearch $ignoretests [file tail $test_name]]} {
2031                                 continue
2032                             }
2033                         }
2035                         # Get the path after the $srcdir so we know
2036                         # the subdir we're in.
2037                         set subdir [relative_filename $srcdir \
2038                                         [file dirname $test_name]]
2039                         # Check to see if the range of tests is limited,
2040                         # set `runtests' to a list of two elements: the script name
2041                         # and any arguments ("" if none).
2042                         if {[array exists all_runtests]} {
2043                             verbose "searching for $test_name in [array names all_runtests]" 2
2044                             if { 0 > [lsearch [array names all_runtests] [file tail $test_name]]} {
2045                                 if { 0 > [lsearch [array names all_runtests] $test_name] } {
2046                                     continue
2047                                 }
2048                             }
2049                             set runtests [list [file tail $test_name] $all_runtests([file tail $test_name])]
2050                         } else {
2051                             set runtests [list [file tail $test_name] ""]
2052                         }
2053                         runtest $test_name
2054                     }
2055                 }
2056             }
2057         }
2059         # Restore the variables set by this pass.
2060         foreach varval $restore {
2061             if { [llength $varval] > 1 } {
2062                 verbose "Restoring [lindex $varval 0] to [lindex $varval 1]" 4
2063                 set [lindex $varval 0] [lindex $varval 1]
2064             } else {
2065                 verbose "Restoring [lindex $varval 0] to `unset'" 4
2066                 unset -- [lindex $varval 0]
2067             }
2068         }
2069     }
2070     cleanup_target_hook $current_target
2071     if { $target_count > 1 } {
2072         log_summary
2073     }
2076 log_and_exit