mirror of https://gitee.com/Nocallback/dejagnu.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2068 lines
56 KiB
2068 lines
56 KiB
# runtest.exp -- Test framework driver
|
|
# Copyright (C) 1992-2019, 2020 Free Software Foundation, Inc.
|
|
#
|
|
# This file is part of DejaGnu.
|
|
#
|
|
# DejaGnu is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# DejaGnu is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with DejaGnu; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
# This file was written by Rob Savoye <rob@welcomehome.org>.
|
|
|
|
set frame_version 1.6.3-rc4
|
|
if {![info exists argv0]} {
|
|
send_error "Must use a version of Expect greater than 5.0\n"
|
|
exit 1
|
|
}
|
|
|
|
# trap some signals so we know whats happening. These definitions are only
|
|
# temporary until we read in the library stuff
|
|
#
|
|
trap { send_user "\ninterrupted by user\n"; exit 130 } SIGINT
|
|
trap { send_user "\nquit\n"; exit 131 } SIGQUIT
|
|
trap { send_user "\nterminated\n"; exit 143 } SIGTERM
|
|
|
|
#
|
|
# Initialize a few global variables used by all tests.
|
|
# `reset_vars' resets several of these, we define them here to document their
|
|
# existence. In fact, it would be nice if all globals used by some interface
|
|
# of dejagnu proper were documented here.
|
|
#
|
|
# Keep these all lowercase. Interface variables used by the various
|
|
# testsuites (eg: the gcc testsuite) should be in all capitals
|
|
# (eg: TORTURE_OPTIONS).
|
|
#
|
|
set mail_logs 0 ;# flag for mailing of summary and diff logs
|
|
set psum_file "latest" ;# file name of previous summary to diff against
|
|
|
|
set exit_status 0 ;# exit code returned by this program
|
|
|
|
set xfail_flag 0 ;# indicates that a failure is expected
|
|
set xfail_prms 0 ;# GNATS prms id number for this expected failure
|
|
set kfail_flag 0 ;# indicates that it is a known failure
|
|
set kfail_prms 0 ;# bug id for the description of the known failure
|
|
set sum_file "" ;# name of the file that contains the summary log
|
|
set base_dir "" ;# the current working directory
|
|
set xml_file "" ;# handle on the XML file if requested
|
|
set xml 0 ;# flag for requesting xml
|
|
set logname "" ;# the users login name
|
|
set prms_id 0 ;# GNATS prms id number
|
|
set bug_id 0 ;# optional bug id number
|
|
set dir "" ;# temp variable for directory names
|
|
set srcdir "." ;# source directory containing the test suite
|
|
set ignoretests "" ;# list of tests to not execute
|
|
set objdir "." ;# directory where test case binaries live
|
|
set reboot 0
|
|
set multipass "" ;# list of passes and var settings
|
|
set errno ""; ;#
|
|
set exit_error 1 ;# Toggle for whether to set the exit status
|
|
;# on Tcl bugs in test case drivers.
|
|
#
|
|
# These describe the host and target environments.
|
|
#
|
|
set build_triplet "" ;# type of architecture to run tests on
|
|
set build_os "" ;# type of os the tests are running on
|
|
set build_vendor "" ;# vendor name of the OS or workstation the test are running on
|
|
set build_cpu "" ;# type of the cpu tests are running on
|
|
set host_triplet "" ;# type of architecture to run tests on, sometimes remotely
|
|
set host_os "" ;# type of os the tests are running on
|
|
set host_vendor "" ;# vendor name of the OS or workstation the test are running on
|
|
set host_cpu "" ;# type of the cpu tests are running on
|
|
set target_triplet "" ;# type of architecture to run tests on, final remote
|
|
set target_os "" ;# type of os the tests are running on
|
|
set target_vendor "" ;# vendor name of the OS or workstation the test are running on
|
|
set target_cpu "" ;# type of the cpu tests are running on
|
|
set target_alias "" ;# standard abbreviation of target
|
|
set compiler_flags "" ;# the flags used by the compiler
|
|
|
|
#
|
|
# These set configuration file names and are local to this file.
|
|
#
|
|
set local_init_file site.exp ;# testsuite-local init file name
|
|
set global_init_file site.exp ;# global init file name
|
|
|
|
#
|
|
# These are used to locate parts of the testsuite.
|
|
#
|
|
set testsuitedir "testsuite" ;# top-level testsuite source directory
|
|
set testbuilddir "testsuite" ;# top-level testsuite object directory
|
|
|
|
#
|
|
# Collected errors
|
|
#
|
|
namespace eval ::dejagnu::error {
|
|
# list of { file message errorCode errorInfo } lists
|
|
variable list [list]
|
|
}
|
|
|
|
# Various ccache versions provide incorrect debug info such as ignoring
|
|
# different current directory, breaking GDB testsuite.
|
|
set env(CCACHE_DISABLE) 1
|
|
unset -nocomplain env(CCACHE_NODISABLE)
|
|
|
|
#
|
|
# some convenience abbreviations
|
|
#
|
|
set hex "0x\[0-9A-Fa-f\]+"
|
|
set decimal "\[0-9\]+"
|
|
|
|
#
|
|
# set the base dir (current working directory)
|
|
#
|
|
set base_dir [pwd]
|
|
|
|
#
|
|
# These are set here instead of the init module so they can be overridden
|
|
# by command line options.
|
|
#
|
|
set all_flag 0
|
|
set binpath ""
|
|
set debug 0
|
|
set options ""
|
|
set outdir "."
|
|
set reboot 1
|
|
set tracelevel 0
|
|
set verbose 0
|
|
set log_dialog 0
|
|
|
|
#
|
|
# verbose [-n] [-log] [--] message [level]
|
|
#
|
|
# Print MESSAGE if the verbose level is >= LEVEL.
|
|
# The default value of LEVEL is 1.
|
|
# "-n" says to not print a trailing newline.
|
|
# "-log" says to add the text to the log file even if it won't be printed.
|
|
# Note that the apparent behaviour of `send_user' dictates that if the message
|
|
# is printed it is also added to the log file.
|
|
# Use "--" if MESSAGE begins with "-".
|
|
#
|
|
# This is defined here rather than in framework.exp so we can use it
|
|
# while still loading in the support files.
|
|
#
|
|
proc verbose { args } {
|
|
global verbose
|
|
set newline 1
|
|
set logfile 0
|
|
|
|
set i 0
|
|
if { [string index [lindex $args 0] 0] eq "-" } {
|
|
for { set i 0 } { $i < [llength $args] } { incr i } {
|
|
if { [lindex $args $i] eq "--" } {
|
|
incr i
|
|
break
|
|
} elseif { [lindex $args $i] eq "-n" } {
|
|
set newline 0
|
|
} elseif { [lindex $args $i] eq "-log" } {
|
|
set logfile 1
|
|
} elseif { [lindex $args $i] eq "-x" } {
|
|
set xml 1
|
|
} elseif { [string index [lindex $args $i] 0] eq "-" } {
|
|
clone_output "ERROR: verbose: illegal argument: [lindex $args $i]"
|
|
return
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
if { [llength $args] == $i } {
|
|
clone_output "ERROR: verbose: nothing to print"
|
|
return
|
|
}
|
|
}
|
|
|
|
set level 1
|
|
if { [llength $args] > $i + 1 } {
|
|
set level [lindex $args [expr { $i + 1 }]]
|
|
}
|
|
set message [lindex $args $i]
|
|
|
|
if { $verbose >= $level } {
|
|
# We assume send_user also sends the text to the log file (which
|
|
# appears to be the case though the docs aren't clear on this).
|
|
if { $newline } {
|
|
send_user -- "$message\n"
|
|
} else {
|
|
send_user -- $message
|
|
}
|
|
} elseif { $logfile } {
|
|
if { $newline } {
|
|
send_log -- "$message\n"
|
|
} else {
|
|
send_log -- $message
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# Transform a tool name to get the installed name.
|
|
# target_triplet is the canonical target name. target_alias is the
|
|
# target name used when configure was run.
|
|
#
|
|
proc transform { name } {
|
|
global target_triplet
|
|
global target_alias
|
|
global host_triplet
|
|
global board
|
|
|
|
if { $target_triplet eq $host_triplet } {
|
|
return $name
|
|
}
|
|
if { $target_triplet eq "native" } {
|
|
return $name
|
|
}
|
|
if {[board_info host exists no_transform_name]} {
|
|
return $name
|
|
}
|
|
if { $target_triplet eq "" } {
|
|
return $name
|
|
} else {
|
|
if {[info exists board]} {
|
|
if {[board_info $board exists target_install]} {
|
|
set target_install [board_info $board target_install]
|
|
}
|
|
}
|
|
if {[target_info exists target_install]} {
|
|
set target_install [target_info target_install]
|
|
}
|
|
if {[info exists target_alias]} {
|
|
set tmp $target_alias-$name
|
|
} elseif {[info exists target_install]} {
|
|
if { [lsearch -exact $target_install $target_alias] >= 0 } {
|
|
set tmp $target_alias-$name
|
|
} else {
|
|
set tmp "[lindex $target_install 0]-$name"
|
|
}
|
|
}
|
|
verbose "Transforming $name to $tmp"
|
|
return $tmp
|
|
}
|
|
}
|
|
|
|
#
|
|
# findfile arg0 [arg1] [arg2]
|
|
#
|
|
# Find a file and see if it exists. If you only care about the false
|
|
# condition, then you'll need to pass a null "" for arg1.
|
|
# arg0 is the filename to look for. If the only arg,
|
|
# then that's what gets returned. If this is the
|
|
# only arg, then if it exists, arg0 gets returned.
|
|
# if it doesn't exist, return only the prog name.
|
|
# arg1 is optional, and it's what gets returned if
|
|
# the file exists.
|
|
# arg2 is optional, and it's what gets returned if
|
|
# the file doesn't exist.
|
|
#
|
|
proc findfile { args } {
|
|
# look for the file
|
|
verbose "Seeing if [lindex $args 0] exists." 2
|
|
if {[file exists [lindex $args 0]]} {
|
|
if { [llength $args] > 1 } {
|
|
verbose "Found file, returning [lindex $args 1]"
|
|
return [lindex $args 1]
|
|
} else {
|
|
verbose "Found file, returning [lindex $args 0]"
|
|
return [lindex $args 0]
|
|
}
|
|
} else {
|
|
if { [llength $args] > 2 } {
|
|
verbose "Didn't find file [lindex $args 0], returning [lindex $args 2]"
|
|
return [lindex $args 2]
|
|
} else {
|
|
verbose "Didn't find file, returning [file tail [lindex $args 0]]"
|
|
return [transform [file tail [lindex $args 0]]]
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# load_file [-1] [--] file1 [ file2 ... ]
|
|
#
|
|
# Utility to source a file. All are sourced in order unless the flag "-1"
|
|
# is given in which case we stop after finding the first one.
|
|
# The result is 1 if a file was found, 0 if not.
|
|
# If a tcl error occurs while sourcing a file, we print an error message
|
|
# and exit.
|
|
#
|
|
proc load_file { args } {
|
|
set i 0
|
|
set only_one 0
|
|
if { [lindex $args $i] eq "-1" } {
|
|
set only_one 1
|
|
incr i
|
|
}
|
|
if { [lindex $args $i] eq "--" } {
|
|
incr i
|
|
}
|
|
|
|
set found 0
|
|
foreach file [lrange $args $i end] {
|
|
verbose "Looking for $file" 2
|
|
# In Tcl, "file exists" fails if the filename looks like
|
|
# ~/FILE and the environment variable HOME does not exist.
|
|
if {! [catch {file exists $file} result] && $result} {
|
|
set found 1
|
|
verbose "Found $file"
|
|
if { [catch "uplevel #0 source $file"] == 1 } {
|
|
send_error "ERROR: tcl error sourcing $file.\n"
|
|
global errorInfo
|
|
if {[info exists errorInfo]} {
|
|
send_error "$errorInfo\n"
|
|
}
|
|
exit 1
|
|
}
|
|
if { $only_one } {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return $found
|
|
}
|
|
|
|
#
|
|
# search_and_load_file -- search DIRLIST looking for FILELIST.
|
|
# TYPE is used when displaying error and progress messages.
|
|
#
|
|
proc search_and_load_file { type filelist dirlist } {
|
|
set found 0
|
|
|
|
foreach dir $dirlist {
|
|
foreach initfile $filelist {
|
|
set filename [file join $dir $initfile]
|
|
verbose "Looking for $type $filename" 2
|
|
if {[file exists $filename]} {
|
|
set found 1
|
|
set error ""
|
|
if { $type ne "library file" } {
|
|
send_user "Using $filename as $type.\n"
|
|
} else {
|
|
verbose "Loading $filename"
|
|
}
|
|
if {[catch "uplevel #0 source $filename" error] == 1} {
|
|
global errorInfo
|
|
send_error "ERROR: tcl error sourcing $type $filename.\n$error\n"
|
|
if {[info exists errorInfo]} {
|
|
send_error "$errorInfo\n"
|
|
}
|
|
exit 1
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if { $found } {
|
|
break
|
|
}
|
|
}
|
|
return $found
|
|
}
|
|
|
|
#
|
|
# Give a usage statement.
|
|
#
|
|
proc usage { } {
|
|
global tool
|
|
|
|
send_user "USAGE: runtest \[options...\]\n"
|
|
send_user "\t--all, -a\t\tPrint all test output to screen\n"
|
|
send_user "\t--build \[triplet\]\tThe canonical triplet of the build machine\n"
|
|
send_user "\t--debug\t\t\tSet expect debugging ON\n"
|
|
send_user "\t--directory name\tRun only the tests in directory 'name'\n"
|
|
send_user "\t--global_init \[name\]\tThe file to load for global configuration\n"
|
|
send_user "\t--help\t\t\tPrint help text\n"
|
|
send_user "\t--host \[triplet\]\tThe canonical triplet of the host machine\n"
|
|
send_user "\t--host_board \[name\]\tThe host board to use\n"
|
|
send_user "\t--ignore \[name(s)\]\tThe names of specific tests to ignore\n"
|
|
send_user "\t--local_init \[name\]\tThe file to load for local configuration\n"
|
|
send_user "\t--log_dialog\t\t\Emit Expect output on stdout\n"
|
|
send_user "\t--mail \[name(s)\]\tWhom to mail the results to\n"
|
|
send_user "\t--objdir \[name\]\t\tThe test suite binary directory\n"
|
|
send_user "\t--outdir \[name\]\t\tThe directory to put logs in\n"
|
|
send_user "\t--reboot\t\tReboot the target (if supported)\n"
|
|
send_user "\t--srcdir \[name\]\t\tThe test suite source code directory\n"
|
|
send_user "\t--status\t\tSet the exit status to fail on Tcl errors\n"
|
|
send_user "\t--strace \[number\]\tTurn on Expect tracing\n"
|
|
send_user "\t--target \[triplet\]\tThe canonical triplet of the target board\n"
|
|
send_user "\t--target_board \[name(s)\] The list of target boards to run tests on\n"
|
|
send_user "\t--tool \[name(s)\]\tRun tests on these tools\n"
|
|
send_user "\t--tool_exec \[name\]\tThe path to the tool executable to test\n"
|
|
send_user "\t--tool_opts \[options\]\tA list of additional options to pass to the tool\n"
|
|
send_user "\t--verbose, -v\t\tProduce verbose output\n"
|
|
send_user "\t--version, -V\t\tPrint all relevant version numbers\n"
|
|
send_user "\t--xml, -x\t\tWrite out an XML results file\n"
|
|
send_user "\t--D\[0-1\]\t\tTcl debugger\n"
|
|
send_user "\tscript.exp\[=arg(s)\]\tRun these tests only\n"
|
|
if { [info exists tool] } {
|
|
if { [info procs ${tool}_option_help] ne "" } {
|
|
${tool}_option_help
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# Parse the arguments the first time looking for these. We will ultimately
|
|
# parse them twice. Things are complicated because:
|
|
# - we want to parse --verbose early on
|
|
# - we don't want config files to override command line arguments
|
|
# (eg: $base_dir/$local_init_file vs --host/--target)
|
|
# - we need some command line arguments before we can process some config files
|
|
# (eg: --objdir before $objdir/$local_init_file, --host/--target before $DEJAGNU)
|
|
# The use of `arg_host_triplet' and `arg_target_triplet' lets us avoid parsing
|
|
# the arguments three times.
|
|
#
|
|
|
|
namespace eval ::dejagnu::command_line {
|
|
variable cmd_var_list [list]
|
|
|
|
proc save_cmd_var {name} {
|
|
variable cmd_var_list
|
|
|
|
upvar 1 $name target_var
|
|
lappend cmd_var_list $name $target_var
|
|
}
|
|
|
|
proc restore_cmd_vars {} {
|
|
variable cmd_var_list
|
|
|
|
foreach {name value} $cmd_var_list {
|
|
uplevel 1 set $name $value
|
|
}
|
|
verbose "Variables set by command line arguments restored." 4
|
|
}
|
|
|
|
proc dump_cmd_vars {} {
|
|
variable cmd_var_list
|
|
|
|
verbose "Variables set by command line arguments:" 4
|
|
foreach {name value} $cmd_var_list {
|
|
verbose " $name -> $value" 4
|
|
}
|
|
}
|
|
}
|
|
|
|
set arg_host_triplet ""
|
|
set arg_target_triplet ""
|
|
set arg_build_triplet ""
|
|
set argc [ llength $argv ]
|
|
for { set i 0 } { $i < $argc } { incr i } {
|
|
set option [lindex $argv $i]
|
|
|
|
# make all options have two hyphens
|
|
switch -glob -- $option {
|
|
"--*" {
|
|
}
|
|
"-*" {
|
|
set option "-$option"
|
|
}
|
|
}
|
|
|
|
# split out the argument for options that take them
|
|
switch -glob -- $option {
|
|
"--*=*" {
|
|
regexp {^[^=]*=(.*)$} $option nil optarg
|
|
}
|
|
"--bu*" -
|
|
"--g*" -
|
|
"--ho*" -
|
|
"--ig*" -
|
|
"--loc*" -
|
|
"--m*" -
|
|
"--ob*" -
|
|
"--ou*" -
|
|
"--sr*" -
|
|
"--str*" -
|
|
"--ta*" -
|
|
"--di*" -
|
|
"--to*" {
|
|
incr i
|
|
set optarg [lindex $argv $i]
|
|
}
|
|
}
|
|
|
|
switch -glob -- $option {
|
|
"--V*" -
|
|
"--vers*" { # (--version) version numbers
|
|
send_user "DejaGnu version\t$frame_version\n"
|
|
send_user "Expect version\t[exp_version]\n"
|
|
send_user "Tcl version\t[ info tclversion ]\n"
|
|
exit 0
|
|
}
|
|
|
|
"--bu*" { # (--build) the build host configuration
|
|
set arg_build_triplet $optarg
|
|
::dejagnu::command_line::save_cmd_var arg_build_triplet
|
|
continue
|
|
}
|
|
|
|
"--g*" { # (--global_init) the global init file name
|
|
set global_init_file $optarg
|
|
::dejagnu::command_line::save_cmd_var global_init_file
|
|
continue
|
|
}
|
|
|
|
"--host_bo*" {
|
|
set host_board $optarg
|
|
::dejagnu::command_line::save_cmd_var host_board
|
|
continue
|
|
}
|
|
|
|
"--ho*" { # (--host) the host configuration
|
|
set arg_host_triplet $optarg
|
|
::dejagnu::command_line::save_cmd_var arg_host_triplet
|
|
continue
|
|
}
|
|
|
|
"--loc*" { # (--local_init) the local init file name
|
|
set local_init_file $optarg
|
|
::dejagnu::command_line::save_cmd_var local_init_file
|
|
continue
|
|
}
|
|
|
|
"--ob*" { # (--objdir) where the test case object code lives
|
|
set objdir $optarg
|
|
::dejagnu::command_line::save_cmd_var objdir
|
|
continue
|
|
}
|
|
|
|
"--sr*" { # (--srcdir) where the testsuite source code lives
|
|
set srcdir $optarg
|
|
::dejagnu::command_line::save_cmd_var srcdir
|
|
continue
|
|
}
|
|
|
|
"--target_bo*" {
|
|
set target_list $optarg
|
|
::dejagnu::command_line::save_cmd_var target_list
|
|
continue
|
|
}
|
|
|
|
"--ta*" { # (--target) the target configuration
|
|
set arg_target_triplet $optarg
|
|
::dejagnu::command_line::save_cmd_var arg_target_triplet
|
|
continue
|
|
}
|
|
|
|
"--tool_opt*" {
|
|
set TOOL_OPTIONS $optarg
|
|
::dejagnu::command_line::save_cmd_var TOOL_OPTIONS
|
|
continue
|
|
}
|
|
|
|
"--tool_exec*" {
|
|
set TOOL_EXECUTABLE $optarg
|
|
::dejagnu::command_line::save_cmd_var TOOL_EXECUTABLE
|
|
continue
|
|
}
|
|
|
|
"--to*" { # (--tool) specify tool name
|
|
set tool $optarg
|
|
set comm_line_tool $optarg
|
|
::dejagnu::command_line::save_cmd_var tool
|
|
::dejagnu::command_line::save_cmd_var comm_line_tool
|
|
continue
|
|
}
|
|
|
|
"--di*" {
|
|
set cmdline_dir_to_run $optarg
|
|
::dejagnu::command_line::save_cmd_var cmdline_dir_to_run
|
|
continue
|
|
}
|
|
|
|
"--v" -
|
|
"--verb*" { # (--verbose) verbose output
|
|
incr verbose
|
|
continue
|
|
}
|
|
|
|
"[A-Z0-9_-.]*=*" { # process makefile style args like CC=gcc, etc...
|
|
if {[regexp "^(\[A-Z0-9_-\]+)=(.*)$" $option junk var val]} {
|
|
set $var $val
|
|
verbose "$var is now $val"
|
|
append makevars "set $var $val;" ;# FIXME: Used anywhere?
|
|
unset junk var val
|
|
} else {
|
|
send_error "Illegal variable specification:\n"
|
|
send_error "$option\n"
|
|
}
|
|
continue
|
|
}
|
|
|
|
}
|
|
}
|
|
verbose "Verbose level is $verbose"
|
|
|
|
verbose [concat "Initial working directory is" [pwd]]
|
|
|
|
::dejagnu::command_line::dump_cmd_vars
|
|
|
|
#
|
|
# get the users login name
|
|
#
|
|
if { $logname eq "" } {
|
|
if {[info exists env(USER)]} {
|
|
set logname $env(USER)
|
|
} else {
|
|
if {[info exists env(LOGNAME)]} {
|
|
set logname $env(LOGNAME)
|
|
} else {
|
|
# try getting it with whoami
|
|
catch "set logname [exec whoami]" tmp
|
|
if {[string match "*couldn't find*to execute*" $tmp]} {
|
|
# try getting it with who am i
|
|
unset tmp
|
|
catch "set logname [exec who am i]" tmp
|
|
if {[string match "*Command not found*" $tmp]} {
|
|
send_user "ERROR: couldn't get the users login name\n"
|
|
set logname "Unknown"
|
|
} else {
|
|
set logname [lindex [split $logname " !"] 1]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
verbose "Login name is $logname"
|
|
|
|
#
|
|
# lookfor_file -- try to find a file by searching up multiple directory levels
|
|
#
|
|
proc lookfor_file { dir name } {
|
|
foreach x [list . .. ../.. ../../.. ../../../..] {
|
|
verbose $dir/$x/$name 2
|
|
if {[file exists [file join $dir $name]]} {
|
|
return [file join $dir $name]
|
|
}
|
|
set dir [remote_file build dirname $dir]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
#
|
|
# load_lib -- load a library by sourcing it
|
|
#
|
|
# If there a multiple files with the same name, stop after the first one found.
|
|
# The order is first look in the install dir, then in a parallel dir in the
|
|
# source tree (up one or two levels), then in the current dir.
|
|
#
|
|
proc load_lib { file } {
|
|
global verbose execpath tool
|
|
global libdir libdirs srcdir testsuitedir base_dir
|
|
global loaded_libs
|
|
|
|
if {[info exists loaded_libs($file)]} {
|
|
return
|
|
}
|
|
|
|
set loaded_libs($file) ""
|
|
set search_dirs [list ../lib $libdir $libdir/lib]
|
|
lappend search_dirs [file dirname [file dirname $srcdir]]/dejagnu/lib
|
|
lappend search_dirs $testsuitedir/lib
|
|
lappend search_dirs $execpath/lib "."
|
|
lappend search_dirs [file dirname [file dirname [file dirname $srcdir]]]/dejagnu/lib
|
|
if {[info exists libdirs]} {
|
|
lappend search_dirs $libdirs
|
|
}
|
|
if { [search_and_load_file "library file" $file $search_dirs ] == 0 } {
|
|
send_error "ERROR: Couldn't find library file $file.\n"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
#
|
|
# Begin sourcing the config files.
|
|
# All are sourced in order.
|
|
#
|
|
# Search order:
|
|
# (local) $base_dir/$local_init_file -> $objdir/$local_init_file ->
|
|
# (global) installed($global_init_file) -> $DEJAGNU -> $HOME/.dejagnurc
|
|
#
|
|
# For the normal case, we expect $base_dir/$local_init_file to set
|
|
# host_triplet and target_triplet.
|
|
#
|
|
|
|
load_file [file join $base_dir $local_init_file]
|
|
|
|
# Ensure that command line parameters override testsuite init files.
|
|
::dejagnu::command_line::restore_cmd_vars
|
|
|
|
#
|
|
# If objdir didn't get set in $base_dir/$local_init_file, set it to
|
|
# $base_dir. Make sure we source $objdir/$local_init_file in case
|
|
# $base_dir/$local_init_file doesn't exist and objdir was given on the
|
|
# command line.
|
|
#
|
|
|
|
if { $objdir eq "." || $objdir eq $srcdir } {
|
|
set objdir $base_dir
|
|
} else {
|
|
load_file [file join $objdir $local_init_file]
|
|
}
|
|
|
|
# Ensure that command line parameters override testsuite init files.
|
|
::dejagnu::command_line::restore_cmd_vars
|
|
|
|
#
|
|
# Find the testsuite.
|
|
#
|
|
|
|
# The DejaGnu manual has always stated that a testsuite must be in a
|
|
# testsuite/ subdirectory.
|
|
|
|
verbose "Finding testsuite ..." 3
|
|
verbose "\$base_dir -> $base_dir" 3
|
|
verbose "\$srcdir -> $srcdir" 3
|
|
verbose "\$objdir -> $objdir" 3
|
|
verbose [concat "file tail \$srcdir -> " [file tail $srcdir]] 3
|
|
verbose [concat "file join \$srcdir testsuite -> " \
|
|
[file join $srcdir testsuite]] 3
|
|
verbose [concat "file isdirectory [file join \$srcdir testsuite] -> " \
|
|
[file isdirectory [file join $srcdir testsuite]]] 3
|
|
verbose [concat "file tail \$base_dir -> " [file tail $base_dir]] 3
|
|
|
|
if { [file tail $srcdir] eq "testsuite" } {
|
|
# Subdirectory case -- $srcdir includes testsuite/
|
|
set testsuitedir $srcdir
|
|
set testbuilddir $objdir
|
|
} elseif { [file tail $srcdir] ne "testsuite"
|
|
&& [file isdirectory [file join $srcdir testsuite]] } {
|
|
# Top-level case -- testsuite in $srcdir/testsuite/
|
|
set testsuitedir [file join $srcdir testsuite]
|
|
set testbuilddir [file join $objdir testsuite]
|
|
} elseif { $srcdir eq "." && [file tail $base_dir] eq "testsuite" } {
|
|
# Development scaffold case -- testsuite in ".", but "." is "testsuite"
|
|
set testsuitedir $base_dir
|
|
set testbuilddir $base_dir
|
|
} else {
|
|
if { $testsuitedir eq "testsuite" && $srcdir eq "." && $objdir eq "." } {
|
|
# Broken legacy case -- testsuite not actually in testsuite/
|
|
# Produce a warning, but continue.
|
|
send_error "WARNING: testsuite is not in a testsuite/ directory.\n"
|
|
set testsuitedir $srcdir
|
|
set testbuilddir $objdir
|
|
} else {
|
|
# Custom case -- all variables are assumed to have been set correctly
|
|
}
|
|
}
|
|
|
|
verbose "Finding testsuite ... done" 3
|
|
|
|
# Well, this just demonstrates the real problem...
|
|
if {![info exists tool_root_dir]} {
|
|
set tool_root_dir [file dirname $objdir]
|
|
if {[file exists [file join $tool_root_dir testsuite]]} {
|
|
set tool_root_dir [file dirname $tool_root_dir]
|
|
}
|
|
}
|
|
|
|
verbose "Using test sources in $srcdir"
|
|
verbose "Using test binaries in $objdir"
|
|
verbose "Testsuite root is $testsuitedir"
|
|
verbose "Tool root directory is $tool_root_dir"
|
|
|
|
set execpath [file dirname $argv0]
|
|
|
|
# The runtest.exp file is installed directly in libdir.
|
|
# Conveniently, the source tree layout is the same as the installed libdir.
|
|
set libdir [file dirname $argv0]
|
|
if {[info exists env(DEJAGNULIBS)]} {
|
|
set libdir $env(DEJAGNULIBS)
|
|
}
|
|
# list of extra search directories used by load_lib to look for libs
|
|
set libdirs {}
|
|
|
|
verbose "Using $libdir to find libraries"
|
|
|
|
#
|
|
# If the host or target was given on the command line, override the above
|
|
# config files. We allow $DEJAGNU to massage them though in case it would
|
|
# ever want to do such a thing.
|
|
#
|
|
if { $arg_host_triplet ne "" } {
|
|
set host_triplet $arg_host_triplet
|
|
}
|
|
if { $arg_build_triplet ne "" } {
|
|
set build_triplet $arg_build_triplet
|
|
}
|
|
|
|
# If we only specify --host, then that must be the build machine too,
|
|
# and we're stuck using the old functionality of a simple cross test.
|
|
if {[expr { $build_triplet eq "" && $host_triplet ne "" } ]} {
|
|
set build_triplet $host_triplet
|
|
}
|
|
# If we only specify --build, then we'll use that as the host too.
|
|
if {[expr { $build_triplet ne "" && $host_triplet eq "" } ]} {
|
|
set host_triplet $build_triplet
|
|
}
|
|
unset arg_host_triplet arg_build_triplet
|
|
|
|
#
|
|
# If the build machine type hasn't been specified by now, use config.guess.
|
|
#
|
|
|
|
if {[expr {$build_triplet eq "" && $host_triplet eq ""}]} {
|
|
# find config.guess
|
|
foreach dir [list $libdir $libdir/libexec $libdir/.. $execpath $srcdir $srcdir/.. $srcdir/../..] {
|
|
verbose "Looking for $dir/config.guess" 2
|
|
if {[file exists [file join $dir config.guess]]} {
|
|
set config_guess [file join $dir config.guess]
|
|
verbose "Found [file join $dir config.guess]"
|
|
break
|
|
}
|
|
}
|
|
|
|
# get the canonical triplet
|
|
if {![info exists config_guess]} {
|
|
send_error "ERROR: Couldn't find config.guess program.\n"
|
|
exit 1
|
|
}
|
|
if { [info exists ::env(CONFIG_SHELL)] } {
|
|
if { [catch {exec $::env(CONFIG_SHELL) $config_guess} build_triplet] } {
|
|
if { [lindex $::errorCode 0] eq "CHILDSTATUS" } {
|
|
send_error "ERROR: Running config.guess with\
|
|
CONFIG_SHELL=$::env(CONFIG_SHELL)\
|
|
exited on code\
|
|
[lindex $::errorCode 2].\n"
|
|
} else {
|
|
send_error "ERROR: Running config.guess with\
|
|
CONFIG_SHELL=$::env(CONFIG_SHELL)\
|
|
produced error:\n"
|
|
send_error " $::errorCode\n"
|
|
}
|
|
}
|
|
} elseif { [info exists ::env(SHELL)] } {
|
|
if { [catch {exec $::env(SHELL) $config_guess} build_triplet] } {
|
|
if { [lindex $::errorCode 0] eq "CHILDSTATUS" } {
|
|
send_error "ERROR: Running config.guess with\
|
|
SHELL=$::env(SHELL)\
|
|
exited on code\
|
|
[lindex $::errorCode 2].\n"
|
|
} else {
|
|
send_error "ERROR: Running config.guess with\
|
|
SHELL=$::env(SHELL)\
|
|
produced error:\n"
|
|
send_error " $::errorCode\n"
|
|
}
|
|
}
|
|
} else {
|
|
if { [catch {exec $config_guess} build_triplet] } {
|
|
if { [lindex $::errorCode 0] eq "CHILDSTATUS" } {
|
|
send_error "ERROR: Running config.guess exited on code\
|
|
[lindex $::errorCode 2].\n"
|
|
} else {
|
|
send_error "ERROR: Running config.guess produced error:\n"
|
|
send_error " $::errorCode\n"
|
|
}
|
|
}
|
|
}
|
|
if { ![regexp -- {^[[:alnum:]_.]+(-[[:alnum:]_.]+)+$} $build_triplet] } {
|
|
send_error "ERROR: Running config.guess produced bogus build triplet:\n"
|
|
send_error " $build_triplet\n"
|
|
send_error " (Perhaps you need to set CONFIG_SHELL or\
|
|
SHELL in your environment\n"
|
|
send_error " to the absolute file name of a POSIX shell?)\n"
|
|
exit 1
|
|
}
|
|
verbose "Assuming build host is $build_triplet"
|
|
if { $host_triplet eq "" } {
|
|
set host_triplet $build_triplet
|
|
}
|
|
}
|
|
|
|
#
|
|
# Figure out the target. If the target hasn't been specified, then we have to
|
|
# assume we are native.
|
|
#
|
|
if { $arg_target_triplet ne "" } {
|
|
set target_triplet $arg_target_triplet
|
|
} elseif { $target_triplet eq "" } {
|
|
set target_triplet $build_triplet
|
|
verbose "Assuming native target is $target_triplet" 2
|
|
}
|
|
unset arg_target_triplet
|
|
#
|
|
# Default target_alias to target_triplet.
|
|
#
|
|
if {![info exists target_alias]} {
|
|
set target_alias $target_triplet
|
|
}
|
|
|
|
proc get_local_hostname { } {
|
|
if {[catch "info hostname" hb]} {
|
|
set hb ""
|
|
} else {
|
|
regsub "\\..*$" $hb "" hb
|
|
}
|
|
verbose "hostname=$hb" 3
|
|
return $hb
|
|
}
|
|
|
|
#
|
|
# We put these here so that they can be overridden later by site.exp or
|
|
# friends.
|
|
#
|
|
# Set up the target as machine NAME. We also load base-config.exp as a
|
|
# default configuration. The config files are sourced with the global
|
|
# variable $board set to the name of the current target being defined.
|
|
#
|
|
proc setup_target_hook { whole_name name } {
|
|
global board
|
|
global host_board
|
|
|
|
if {[info exists host_board]} {
|
|
set hb $host_board
|
|
} else {
|
|
set hb [get_local_hostname]
|
|
}
|
|
|
|
set board $whole_name
|
|
|
|
global board_type
|
|
set board_type "target"
|
|
|
|
load_config base-config.exp
|
|
if {![load_board_description $name $whole_name $hb]} {
|
|
if { $name ne "unix" } {
|
|
perror "couldn't load description file for $name"
|
|
exit 1
|
|
} else {
|
|
load_generic_config "unix"
|
|
}
|
|
}
|
|
|
|
if {[board_info $board exists generic_name]} {
|
|
load_tool_target_config [board_info $board generic_name]
|
|
}
|
|
|
|
unset board
|
|
unset board_type
|
|
|
|
push_target $whole_name
|
|
|
|
if { [info procs ${whole_name}_init] ne "" } {
|
|
${whole_name}_init $whole_name
|
|
}
|
|
|
|
if { ![isnative] && ![isremote target] } {
|
|
global env build_triplet target_triplet
|
|
if { (![info exists env(DEJAGNU)]) && ($build_triplet ne $target_triplet) } {
|
|
warning "Assuming target board is the local machine (which is probably wrong).\nYou may need to set your DEJAGNU environment variable."
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# Clean things up afterwards.
|
|
#
|
|
proc cleanup_target_hook { name } {
|
|
global tool
|
|
# Clean up the target board.
|
|
if { [info procs ${name}_exit] ne "" } {
|
|
${name}_exit
|
|
}
|
|
# We also call the tool exit routine here.
|
|
if {[info exists tool]} {
|
|
if { [info procs ${tool}_exit] ne "" } {
|
|
${tool}_exit
|
|
}
|
|
}
|
|
remote_close target
|
|
pop_target
|
|
}
|
|
|
|
proc setup_host_hook { name } {
|
|
global board
|
|
global board_info
|
|
global board_type
|
|
|
|
set board $name
|
|
set board_type "host"
|
|
|
|
load_board_description $name
|
|
unset board
|
|
unset board_type
|
|
push_host $name
|
|
if { [info procs ${name}_init] ne "" } {
|
|
${name}_init $name
|
|
}
|
|
}
|
|
|
|
proc setup_build_hook { name } {
|
|
global board
|
|
global board_info
|
|
global board_type
|
|
|
|
set board $name
|
|
set board_type "build"
|
|
|
|
load_board_description $name
|
|
unset board
|
|
unset board_type
|
|
push_build $name
|
|
if { [info procs ${name}_init] ne "" } {
|
|
${name}_init $name
|
|
}
|
|
}
|
|
|
|
#
|
|
# Find and load the global config file if it exists.
|
|
# The global config file is used to set the connect mode and other
|
|
# parameters specific to each particular target.
|
|
# These files assume the host and target have been set.
|
|
#
|
|
|
|
if { [load_file -- [file join $libdir $global_init_file]] == 0 } {
|
|
# If $DEJAGNU isn't set either then there isn't any global config file.
|
|
# Warn the user as there really should be one.
|
|
if { ! [info exists env(DEJAGNU)] } {
|
|
send_error "WARNING: Couldn't find the global config file.\n"
|
|
}
|
|
}
|
|
|
|
if {[info exists env(DEJAGNU)]} {
|
|
if { [load_file -- $env(DEJAGNU)] == 0 } {
|
|
# It may seem odd to only issue a warning if there isn't a global
|
|
# config file, but issue an error if $DEJAGNU is erroneously defined.
|
|
# Since $DEJAGNU is set there is *supposed* to be a global config file,
|
|
# so the current behaviour seems reasonable.
|
|
send_error "ERROR: global config file $env(DEJAGNU) not found.\n"
|
|
exit 1
|
|
}
|
|
if {![info exists boards_dir]} {
|
|
set boards_dir "[file dirname $env(DEJAGNU)]/boards"
|
|
}
|
|
}
|
|
|
|
# Load user .dejagnurc file last as the ultimate override.
|
|
load_file ~/.dejagnurc
|
|
|
|
if {![info exists boards_dir]} {
|
|
set boards_dir ""
|
|
}
|
|
|
|
#
|
|
# parse out the config parts of the triplet name
|
|
#
|
|
|
|
# build values
|
|
if { $build_cpu eq "" } {
|
|
regsub -- "-.*-.*" $build_triplet "" build_cpu
|
|
}
|
|
if { $build_vendor eq "" } {
|
|
regsub -- "^\[a-z0-9\]*-" $build_triplet "" build_vendor
|
|
regsub -- "-.*" $build_vendor "" build_vendor
|
|
}
|
|
if { $build_os eq "" } {
|
|
regsub -- ".*-.*-" $build_triplet "" build_os
|
|
}
|
|
|
|
# host values
|
|
if { $host_cpu eq "" } {
|
|
regsub -- "-.*-.*" $host_triplet "" host_cpu
|
|
}
|
|
if { $host_vendor eq "" } {
|
|
regsub -- "^\[a-z0-9\]*-" $host_triplet "" host_vendor
|
|
regsub -- "-.*" $host_vendor "" host_vendor
|
|
}
|
|
if { $host_os eq "" } {
|
|
regsub -- ".*-.*-" $host_triplet "" host_os
|
|
}
|
|
|
|
# target values
|
|
if { $target_cpu eq "" } {
|
|
regsub -- "-.*-.*" $target_triplet "" target_cpu
|
|
}
|
|
if { $target_vendor eq "" } {
|
|
regsub -- "^\[a-z0-9\]*-" $target_triplet "" target_vendor
|
|
regsub -- "-.*" $target_vendor "" target_vendor
|
|
}
|
|
if { $target_os eq "" } {
|
|
regsub -- ".*-.*-" $target_triplet "" target_os
|
|
}
|
|
|
|
#
|
|
# Load the primary tool initialization file.
|
|
#
|
|
|
|
proc load_tool_init { file } {
|
|
global srcdir testsuitedir
|
|
global loaded_libs
|
|
|
|
if {[info exists loaded_libs(tool/$file)]} {
|
|
return
|
|
}
|
|
|
|
set loaded_libs(tool/$file) ""
|
|
|
|
lappend searchpath [file join $testsuitedir lib tool]
|
|
lappend searchpath [file join $testsuitedir lib]
|
|
# for legacy testsuites that might have files in lib/ instead of
|
|
# testsuite/lib/ in the package source tree; deprecated
|
|
lappend searchpath [file join $srcdir lib]
|
|
|
|
if { ![search_and_load_file "tool init file" [list $file] $searchpath] } {
|
|
warning "Couldn't find tool init file"
|
|
}
|
|
}
|
|
|
|
#
|
|
# load the testing framework libraries
|
|
#
|
|
load_lib utils.exp
|
|
load_lib framework.exp
|
|
load_lib debugger.exp
|
|
load_lib remote.exp
|
|
load_lib target.exp
|
|
load_lib targetdb.exp
|
|
load_lib libgloss.exp
|
|
|
|
# Initialize the test counters and reset them to 0.
|
|
init_testcounts
|
|
reset_vars
|
|
|
|
#
|
|
# Parse the command line arguments.
|
|
#
|
|
|
|
# Load the tool initialization file. Allow the --tool option to override
|
|
# what's set in the site.exp file.
|
|
if {[info exists comm_line_tool]} {
|
|
set tool $comm_line_tool
|
|
}
|
|
|
|
if {[info exists tool]} {
|
|
load_tool_init ${tool}.exp
|
|
}
|
|
|
|
set argc [ llength $argv ]
|
|
for { set i 0 } { $i < $argc } { incr i } {
|
|
set option [ lindex $argv $i ]
|
|
|
|
# make all options have two hyphens
|
|
switch -glob -- $option {
|
|
"--*" {
|
|
}
|
|
"-*" {
|
|
set option "-$option"
|
|
}
|
|
}
|
|
|
|
# split out the argument for options that take them
|
|
switch -glob -- $option {
|
|
"--*=*" {
|
|
regexp {^[^=]*=(.*)$} $option nil optarg
|
|
}
|
|
"--bu*" -
|
|
"--g*" -
|
|
"--ho*" -
|
|
"--ig*" -
|
|
"--loc*" -
|
|
"--m*" -
|
|
"--ob*" -
|
|
"--ou*" -
|
|
"--sr*" -
|
|
"--str*" -
|
|
"--ta*" -
|
|
"--di*" -
|
|
"--to*" {
|
|
incr i
|
|
set optarg [lindex $argv $i]
|
|
}
|
|
}
|
|
|
|
switch -glob -- $option {
|
|
"--v*" { # (--verbose) verbose output
|
|
# Already parsed.
|
|
continue
|
|
}
|
|
|
|
"--g*" { # (--global_init) the global init file name
|
|
# Already parsed (and no longer useful). The file has been loaded.
|
|
continue
|
|
}
|
|
|
|
"--loc*" { # (--local_init) the local init file name
|
|
# Already parsed (and no longer useful). The file has been loaded.
|
|
continue
|
|
}
|
|
|
|
"--bu*" { # (--build) the build host configuration
|
|
# Already parsed (and don't set again). Let $DEJAGNU rename it.
|
|
continue
|
|
}
|
|
|
|
"--ho*" { # (--host) the host configuration
|
|
# Already parsed (and don't set again). Let $DEJAGNU rename it.
|
|
continue
|
|
}
|
|
|
|
"--target_bo*" {
|
|
# Set it again, father knows best.
|
|
set target_list $optarg
|
|
continue
|
|
}
|
|
|
|
"--ta*" { # (--target) the target configuration
|
|
# Already parsed (and don't set again). Let $DEJAGNU rename it.
|
|
continue
|
|
}
|
|
|
|
"--a*" { # (--all) print all test output to screen
|
|
set all_flag 1
|
|
verbose "Print all test output to screen"
|
|
continue
|
|
}
|
|
|
|
"--di*" {
|
|
# Already parsed (and don't set again). Let $DEJAGNU rename it.
|
|
continue
|
|
}
|
|
|
|
|
|
"--de*" { # (--debug) expect internal debugging
|
|
if {[file exists ./dbg.log]} {
|
|
catch [file delete -force -- dbg.log]
|
|
}
|
|
if { $verbose > 2 } {
|
|
exp_internal -f dbg.log 1
|
|
} else {
|
|
exp_internal -f dbg.log 0
|
|
}
|
|
verbose "Expect Debugging is ON"
|
|
continue
|
|
}
|
|
|
|
"--D[01]" { # (-Debug) turn on Tcl debugger
|
|
# The runtest shell script handles this option, but it
|
|
# still appears in the options in the Tcl code.
|
|
verbose "Tcl debugger is ON"
|
|
continue
|
|
}
|
|
|
|
"--m*" { # (--mail) mail the output
|
|
set mailing_list $optarg
|
|
set mail_logs 1
|
|
verbose "Mail results to $mailing_list"
|
|
continue
|
|
}
|
|
|
|
"--r*" { # (--reboot) reboot the target
|
|
set reboot 1
|
|
verbose "Will reboot the target (if supported)"
|
|
continue
|
|
}
|
|
|
|
"--ob*" { # (--objdir) where the test case object code lives
|
|
# Already parsed, but parse again to make sure command line
|
|
# options override any config file.
|
|
set objdir $optarg
|
|
verbose "Using test binaries in $objdir"
|
|
continue
|
|
}
|
|
|
|
"--ou*" { # (--outdir) where to put the output files
|
|
set outdir $optarg
|
|
verbose "Test output put in $outdir"
|
|
continue
|
|
}
|
|
|
|
"--log_dialog*" {
|
|
incr log_dialog
|
|
continue
|
|
}
|
|
|
|
"*.exp" { # specify test names to run
|
|
set all_runtests($option) ""
|
|
verbose "Running only tests $option"
|
|
continue
|
|
}
|
|
|
|
"*.exp=*" { # specify test names to run
|
|
set tmp [split $option "="]
|
|
set all_runtests([lindex $tmp 0]) [lindex $tmp 1]
|
|
verbose "Running only tests $option"
|
|
unset tmp
|
|
continue
|
|
}
|
|
|
|
"--ig*" { # (--ignore) specify test names to exclude
|
|
set ignoretests $optarg
|
|
verbose "Ignoring test $ignoretests"
|
|
continue
|
|
}
|
|
|
|
"--sr*" { # (--srcdir) where the testsuite source code lives
|
|
# Already parsed, but parse again to make sure command line
|
|
# options override any config file.
|
|
|
|
set srcdir $optarg
|
|
continue
|
|
}
|
|
|
|
"--str*" { # (--strace) expect trace level
|
|
set tracelevel $optarg
|
|
strace $tracelevel
|
|
verbose "Source Trace level is now $tracelevel"
|
|
continue
|
|
}
|
|
|
|
"--sta*" { # (--status) exit status flag
|
|
# preserved for compatability, do nothing
|
|
continue
|
|
}
|
|
|
|
"--tool_opt*" {
|
|
continue
|
|
}
|
|
|
|
"--tool_exec*" {
|
|
set TOOL_EXECUTABLE $optarg
|
|
continue
|
|
}
|
|
|
|
"--to*" { # (--tool) specify tool name
|
|
set tool $optarg
|
|
verbose "Testing $tool"
|
|
continue
|
|
}
|
|
|
|
"--x*" {
|
|
set xml 1
|
|
verbose "XML logging turned on"
|
|
continue
|
|
}
|
|
|
|
"--he*" { # (--help) help text
|
|
usage
|
|
exit 0
|
|
}
|
|
|
|
"[A-Z0-9_-.]*=*" { # skip makefile style args like CC=gcc, etc... (processed in first pass)
|
|
continue
|
|
}
|
|
|
|
default {
|
|
if {[info exists tool]} {
|
|
if { [info procs ${tool}_option_proc] ne "" } {
|
|
if {[${tool}_option_proc $option]} {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
send_error "\nIllegal Argument \"$option\"\n"
|
|
send_error "try \"runtest --help\" for option list\n"
|
|
exit 1
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# check for a few crucial variables
|
|
#
|
|
if {![info exists tool]} {
|
|
send_error "WARNING: No tool specified\n"
|
|
set tool ""
|
|
}
|
|
|
|
#
|
|
# initialize a few Tcl variables to something other than their default
|
|
#
|
|
if { $verbose > 2 || $log_dialog } {
|
|
log_user 1
|
|
} else {
|
|
log_user 0
|
|
}
|
|
|
|
set timeout 10
|
|
|
|
|
|
|
|
#
|
|
# open log files
|
|
#
|
|
open_logs
|
|
|
|
# print the config info
|
|
clone_output "Test run by $logname on [timestamp -format %c]"
|
|
if {[is3way]} {
|
|
clone_output "Target is $target_triplet"
|
|
clone_output "Host is $host_triplet"
|
|
clone_output "Build is $build_triplet"
|
|
} else {
|
|
if {[isnative]} {
|
|
clone_output "Native configuration is $target_triplet"
|
|
} else {
|
|
clone_output "Target is $target_triplet"
|
|
clone_output "Host is $host_triplet"
|
|
}
|
|
}
|
|
|
|
clone_output "\n\t\t=== $tool tests ===\n"
|
|
|
|
#
|
|
# Look for the generic board configuration file. It searches in several
|
|
# places: $libdir/config, $libdir/../config, and $boards_dir.
|
|
#
|
|
|
|
proc load_generic_config { name } {
|
|
global libdir
|
|
global board
|
|
global board_info
|
|
global boards_dir
|
|
global board_type
|
|
|
|
if {[info exists board]} {
|
|
if {![info exists board_info($board,generic_name)]} {
|
|
set board_info($board,generic_name) $name
|
|
}
|
|
}
|
|
|
|
if {[info exists board_type]} {
|
|
set type "for $board_type"
|
|
} else {
|
|
set type ""
|
|
}
|
|
|
|
set dirlist [concat $libdir/config [file dirname $libdir]/config $boards_dir]
|
|
set result [search_and_load_file "generic interface file $type" $name.exp $dirlist]
|
|
|
|
return $result
|
|
}
|
|
|
|
#
|
|
# Load the tool-specific target description.
|
|
#
|
|
proc load_config { args } {
|
|
global testsuitedir
|
|
|
|
set found 0
|
|
|
|
return [search_and_load_file "tool-and-target-specific interface file" $args [list $testsuitedir/config $testsuitedir/../config $testsuitedir/../../config $testsuitedir/../../../config]]
|
|
}
|
|
|
|
#
|
|
# Find the files that set up the configuration for the target. There
|
|
# are assumed to be two of them; one defines a basic set of
|
|
# functionality for the target that can be used by all tool
|
|
# testsuites, and the other defines any necessary tool-specific
|
|
# functionality. These files are loaded via load_config.
|
|
#
|
|
# These used to all be named $target_abbrev-$tool.exp, but as the
|
|
# $tool variable goes away, it's now just $target_abbrev.exp. First
|
|
# we look for a file named with both the abbrev and the tool names.
|
|
# Then we look for one named with just the abbrev name. Finally, we
|
|
# look for a file called default, which is the default actions, as
|
|
# some tools could be purely host based. Unknown is mostly for error
|
|
# trapping.
|
|
#
|
|
|
|
proc load_tool_target_config { name } {
|
|
global target_os libdir testsuitedir
|
|
|
|
set found [load_config $name.exp $target_os.exp "default.exp" "unknown.exp"]
|
|
|
|
if { $found == 0 } {
|
|
send_error "WARNING: Couldn't find tool config file for $name, using default.\n"
|
|
# If we can't load the tool init file, this must be a simple natively hosted
|
|
# test suite, so we use the default procs for Unix.
|
|
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 } {
|
|
send_error "ERROR: Couldn't find default tool init file.\n"
|
|
exit 1
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# Find the file that describes the machine specified by board_name.
|
|
#
|
|
|
|
proc load_board_description { board_name args } {
|
|
global libdir
|
|
global board
|
|
global board_info
|
|
global boards_dir
|
|
global board_type
|
|
|
|
set dejagnu ""
|
|
|
|
if { [llength $args] > 0 } {
|
|
set whole_name [lindex $args 0]
|
|
} else {
|
|
set whole_name $board_name
|
|
}
|
|
|
|
set board_info($whole_name,name) $whole_name
|
|
if {![info exists board]} {
|
|
set board $whole_name
|
|
set board_set 1
|
|
} else {
|
|
set board_set 0
|
|
}
|
|
|
|
set dirlist {}
|
|
if { [llength $args] > 1 } {
|
|
set suffix [lindex $args 1]
|
|
if { $suffix ne "" } {
|
|
foreach x $boards_dir {
|
|
lappend dirlist $x/$suffix
|
|
}
|
|
lappend dirlist $libdir/baseboards/$suffix
|
|
}
|
|
}
|
|
set dirlist [concat $dirlist $boards_dir]
|
|
lappend dirlist $libdir/baseboards
|
|
verbose "dirlist is $dirlist"
|
|
if {[info exists board_type]} {
|
|
set type "for $board_type"
|
|
} else {
|
|
set type ""
|
|
}
|
|
if {![info exists board_info($whole_name,isremote)]} {
|
|
set board_info($whole_name,isremote) 1
|
|
if {[info exists board_type]} {
|
|
if { $board_type eq "build" } {
|
|
set board_info($whole_name,isremote) 0
|
|
}
|
|
}
|
|
if { $board_name eq [get_local_hostname] } {
|
|
set board_info($whole_name,isremote) 0
|
|
}
|
|
}
|
|
search_and_load_file "standard board description file $type" standard.exp $dirlist
|
|
set found [search_and_load_file "board description file $type" $board_name.exp $dirlist]
|
|
if { $board_set != 0 } {
|
|
unset board
|
|
}
|
|
|
|
return $found
|
|
}
|
|
|
|
#
|
|
# Find the base-level file that describes the machine specified by args. We
|
|
# only look in one directory, $libdir/baseboards.
|
|
#
|
|
|
|
proc load_base_board_description { board_name } {
|
|
global libdir
|
|
global board
|
|
global board_info
|
|
global board_type
|
|
|
|
set board_set 0
|
|
set board_info($board_name,name) $board_name
|
|
if {![info exists board]} {
|
|
set board $board_name
|
|
set board_set 1
|
|
}
|
|
if {[info exists board_type]} {
|
|
set type "for $board_type"
|
|
} else {
|
|
set type ""
|
|
}
|
|
if {![info exists board_info($board_name,isremote)]} {
|
|
set board_info($board_name,isremote) 1
|
|
if {[info exists board_type]} {
|
|
if { $board_type eq "build" } {
|
|
set board_info($board_name,isremote) 0
|
|
}
|
|
}
|
|
}
|
|
|
|
if { $board_name eq [get_local_hostname] } {
|
|
set board_info($board_name,isremote) 0
|
|
}
|
|
set found [search_and_load_file "board description file $type" $board_name.exp [list $libdir/baseboards]]
|
|
if { $board_set != 0 } {
|
|
unset board
|
|
}
|
|
|
|
return $found
|
|
}
|
|
|
|
#
|
|
# Source the testcase in TEST_FILE_NAME.
|
|
#
|
|
|
|
proc runtest { test_file_name } {
|
|
global prms_id
|
|
global bug_id
|
|
global test_result
|
|
global errcnt
|
|
global errorCode
|
|
global errorInfo
|
|
global tool
|
|
global testdir
|
|
|
|
clone_output "Running $test_file_name ..."
|
|
set prms_id 0
|
|
set bug_id 0
|
|
set test_result ""
|
|
|
|
# set testdir so testsuite file -test has a starting point
|
|
set testdir [file dirname $test_file_name]
|
|
|
|
if {[file exists $test_file_name]} {
|
|
set timestart [timestamp]
|
|
|
|
if {[info exists tool]} {
|
|
if { [info procs ${tool}_init] ne "" } {
|
|
${tool}_init $test_file_name
|
|
}
|
|
}
|
|
|
|
if { [catch "uplevel #0 source $test_file_name" msg] == 1 } {
|
|
# If we have a Tcl error, propagate the exit status so
|
|
# that 'make' (if it invokes runtest) notices the error.
|
|
global exit_status exit_error
|
|
# exit error is set by the --status command line option
|
|
if { $exit_status == 0 } {
|
|
set exit_status 2
|
|
}
|
|
set new_error [list $test_file_name $msg]
|
|
# We can't call `perror' here, it resets `errorInfo'
|
|
# before we want to look at it. Also remember that perror
|
|
# increments `errcnt'. If we do call perror we'd have to
|
|
# reset errcnt afterwards.
|
|
clone_output "ERROR: tcl error sourcing $test_file_name."
|
|
if {[info exists errorCode]} {
|
|
clone_output "ERROR: tcl error code $errorCode"
|
|
lappend new_error $errorCode
|
|
} else {
|
|
lappend new_error [list]
|
|
}
|
|
if {[info exists errorInfo]} {
|
|
clone_output "ERROR: $errorInfo"
|
|
lappend new_error $errorInfo
|
|
unset errorInfo
|
|
} else {
|
|
lappend new_error [list]
|
|
}
|
|
lappend ::dejagnu::error::list $new_error
|
|
unresolved "testcase '$test_file_name' aborted due to Tcl error"
|
|
}
|
|
|
|
if {[info exists tool]} {
|
|
if { [info procs ${tool}_finish] ne "" } {
|
|
${tool}_finish
|
|
}
|
|
}
|
|
set timeend [timestamp]
|
|
set timediff [expr {$timeend - $timestart}]
|
|
verbose -log "testcase $test_file_name completed in $timediff seconds" 4
|
|
} else {
|
|
# This should never happen, but maybe if the file got removed
|
|
# between the `find' above and here.
|
|
perror "$test_file_name does not exist." 0
|
|
}
|
|
}
|
|
|
|
# Trap some signals so we know what's happening. These replace the previous
|
|
# ones because we've now loaded the library stuff.
|
|
#
|
|
if {![exp_debug]} {
|
|
foreach sig {{SIGINT {interrupted by user} 130} \
|
|
{SIGQUIT {interrupted by user} 131} \
|
|
{SIGTERM {terminated} 143}} {
|
|
set signal [lindex $sig 0]
|
|
set str [lindex $sig 1]
|
|
set code [lindex $sig 2]
|
|
trap "send_error \"got a \[trap -name\] signal, $str \\n\"; set exit_status $code; log_and_exit;" $signal
|
|
verbose "setting trap for $signal to $str" 1
|
|
}
|
|
unset signal str sig
|
|
}
|
|
|
|
#
|
|
# Given a list of targets, process any iterative lists.
|
|
#
|
|
proc process_target_variants { target_list } {
|
|
set result {}
|
|
foreach x $target_list {
|
|
if {[regexp "\\(" $x]} {
|
|
regsub {^.*\(([^()]*)\)$} $x {\1} variant_list
|
|
regsub {\([^(]*$} $x "" x
|
|
set list [process_target_variants $x]
|
|
set result {}
|
|
foreach x $list {
|
|
set result [concat $result [iterate_target_variants $x [split $variant_list ","]]]
|
|
}
|
|
} elseif {[regexp "\{" $x]} {
|
|
regsub "^.*\{(\[^\{\}\]*)\}$" $x {\1} variant_list
|
|
regsub "\{\[^\{\]*$" $x "" x
|
|
set list [process_target_variants $x]
|
|
foreach x $list {
|
|
foreach i [split $variant_list ","] {
|
|
set name $x
|
|
if { $i ne "" } {
|
|
append name "/" $i
|
|
}
|
|
lappend result $name
|
|
}
|
|
}
|
|
} else {
|
|
lappend result $x
|
|
}
|
|
}
|
|
return $result
|
|
}
|
|
|
|
proc iterate_target_variants { target variants } {
|
|
return [iterate_target_variants_two $target $target $variants]
|
|
}
|
|
|
|
#
|
|
# Given a list of variants, produce the list of all possible combinations.
|
|
#
|
|
proc iterate_target_variants_two { orig_target target variants } {
|
|
|
|
if { [llength $variants] == 0 } {
|
|
return [list $target]
|
|
} else {
|
|
if { [llength $variants] > 1 } {
|
|
set result [iterate_target_variants_two $orig_target $target [lrange $variants 1 end]]
|
|
} else {
|
|
if { $target ne $orig_target } {
|
|
set result [list $target]
|
|
} else {
|
|
set result {}
|
|
}
|
|
}
|
|
if { [lindex $variants 0] ne "" } {
|
|
append target "/" [lindex $variants 0]
|
|
return [concat $result [iterate_target_variants_two $orig_target $target [lrange $variants 1 end]]]
|
|
} else {
|
|
return [concat $result $target]
|
|
}
|
|
}
|
|
}
|
|
|
|
setup_build_hook [get_local_hostname]
|
|
|
|
if {[info exists host_board]} {
|
|
setup_host_hook $host_board
|
|
} else {
|
|
set hb [get_local_hostname]
|
|
if { $hb ne "" } {
|
|
setup_host_hook $hb
|
|
}
|
|
}
|
|
|
|
#
|
|
# main test execution loop
|
|
#
|
|
|
|
if {[info exists errorInfo]} {
|
|
unset errorInfo
|
|
}
|
|
|
|
|
|
# make sure we have only single path delimiters
|
|
regsub -all {([^/])//*} $srcdir {\1/} srcdir
|
|
regsub -all {([^/])//*} $objdir {\1/} objdir
|
|
regsub -all {([^/])//*} $testsuitedir {\1/} testsuitedir
|
|
regsub -all {([^/])//*} $testbuilddir {\1/} testbuilddir
|
|
|
|
if {![info exists target_list]} {
|
|
# Make sure there is at least one target machine. It's probably a Unix box,
|
|
# but that's just a guess.
|
|
set target_list { "unix" }
|
|
} else {
|
|
verbose "target list is $target_list"
|
|
}
|
|
|
|
#
|
|
# Iterate through the list of targets.
|
|
#
|
|
global current_target
|
|
|
|
set target_list [process_target_variants $target_list]
|
|
|
|
set target_count [llength $target_list]
|
|
|
|
clone_output "Schedule of variations:"
|
|
foreach current_target $target_list {
|
|
clone_output " $current_target"
|
|
}
|
|
clone_output ""
|
|
|
|
|
|
foreach current_target $target_list {
|
|
verbose "target is $current_target"
|
|
set current_target_name $current_target
|
|
set tlist [split $current_target /]
|
|
set current_target [lindex $tlist 0]
|
|
set board_variant_list [lrange $tlist 1 end]
|
|
|
|
# Set the counts for this target to 0.
|
|
reset_vars
|
|
clone_output "Running target $current_target_name"
|
|
|
|
setup_target_hook $current_target_name $current_target
|
|
|
|
# If multiple passes requested, set them up. Otherwise prepare just one.
|
|
# The format of `MULTIPASS' is a list of elements containing
|
|
# "{ name var1=value1 ... }" where `name' is a generic name for the pass and
|
|
# currently has no other meaning.
|
|
|
|
global env
|
|
|
|
if { [info exists MULTIPASS] } {
|
|
set multipass $MULTIPASS
|
|
}
|
|
if { $multipass eq "" } {
|
|
set multipass { "" }
|
|
}
|
|
|
|
# If PASS is specified, we want to run only the tests specified.
|
|
# Its value should be a number or a list of numbers that specify
|
|
# the passes that we want to run.
|
|
if {[info exists PASS]} {
|
|
set pass $PASS
|
|
} else {
|
|
set pass ""
|
|
}
|
|
|
|
if {$pass ne ""} {
|
|
set passes [list]
|
|
foreach p $pass {
|
|
foreach multipass_elem $multipass {
|
|
set multipass_name [lindex $multipass_elem 0]
|
|
if {$p == $multipass_name} {
|
|
lappend passes $multipass_elem
|
|
break
|
|
}
|
|
}
|
|
}
|
|
set multipass $passes
|
|
}
|
|
|
|
foreach pass $multipass {
|
|
|
|
# multipass_name is set for `record_test' to use (see framework.exp).
|
|
if { [lindex $pass 0] ne "" } {
|
|
set multipass_name [lindex $pass 0]
|
|
clone_output "Running pass `$multipass_name' ..."
|
|
} else {
|
|
set multipass_name ""
|
|
}
|
|
set restore ""
|
|
foreach varval [lrange $pass 1 end] {
|
|
set tmp [string first "=" $varval]
|
|
set var [string range $varval 0 [expr {$tmp - 1}]]
|
|
# Save previous value.
|
|
if {[info exists $var]} {
|
|
lappend restore "$var [list [eval concat \$$var]]"
|
|
} else {
|
|
lappend restore $var
|
|
}
|
|
# Handle "CFLAGS=$CFLAGS foo".
|
|
eval set $var \[string range \"$varval\" [expr {$tmp + 1}] end\]
|
|
verbose "$var is now [eval concat \$$var]"
|
|
unset tmp var
|
|
}
|
|
|
|
# look for the top level testsuites. if $tool doesn't
|
|
# exist and there are no subdirectories in $testsuitedir, then
|
|
# we print a warning and default to srcdir.
|
|
set test_top_dirs [lsort [getdirs -all $testsuitedir $tool*]]
|
|
if { $test_top_dirs eq "" } {
|
|
send_error "WARNING: could not find testsuite; trying $srcdir.\n"
|
|
set test_top_dirs [list $srcdir]
|
|
} else {
|
|
# JYG:
|
|
# DejaGNU's notion of test tree and test files is very
|
|
# general:
|
|
# given $testsuitedir and $tool, any subdirectory (at any
|
|
# level deep) with the "$tool" prefix starts a test tree
|
|
# given a test tree, any *.exp file underneath (at any
|
|
# level deep) is a test file.
|
|
#
|
|
# For test tree layouts with $tool prefix on
|
|
# both a parent and a child directory, we need to eliminate
|
|
# the child directory entry from test_top_dirs list.
|
|
# e.g. gdb.hp/gdb.base-hp/ would result in two entries
|
|
# in the list: gdb.hp, gdb.hp/gdb.base-hp.
|
|
# If the latter not eliminated, test files under
|
|
# gdb.hp/gdb.base-hp would be run twice (since test files
|
|
# are gathered from all sub-directories underneath a
|
|
# directory).
|
|
#
|
|
# Since $tool may be g++, etc. which could confuse
|
|
# regexp, we cannot do the simpler test:
|
|
# ...
|
|
# if [regexp "$testsuitedir/.*$tool.*/.*$tool.*" $dir]
|
|
# ...
|
|
# instead, we rely on the fact that test_top_dirs is
|
|
# a sorted list of entries, and any entry that contains
|
|
# the previous valid test top dir entry in its own pathname
|
|
# must be excluded.
|
|
|
|
set temp_top_dirs [list]
|
|
set prev_dir ""
|
|
foreach dir $test_top_dirs {
|
|
if { $prev_dir eq ""
|
|
|| [string first $prev_dir/ $dir] == -1 } {
|
|
# the first top dir entry, or an entry that
|
|
# does not share the previous entry's entire
|
|
# pathname, record it as a valid top dir entry.
|
|
#
|
|
lappend temp_top_dirs $dir
|
|
set prev_dir $dir
|
|
}
|
|
}
|
|
set test_top_dirs $temp_top_dirs
|
|
}
|
|
verbose "Top level testsuite dirs are $test_top_dirs" 2
|
|
set testlist ""
|
|
if {[array exists all_runtests]} {
|
|
foreach x [array names all_runtests] {
|
|
verbose "trying to glob $testsuitedir/$x" 2
|
|
set s [glob -nocomplain $testsuitedir/$x]
|
|
if { $s ne "" } {
|
|
set testlist [concat $testlist $s]
|
|
}
|
|
}
|
|
}
|
|
#
|
|
# If we have a list of tests, run all of them.
|
|
#
|
|
if { $testlist ne "" } {
|
|
foreach test_name $testlist {
|
|
if { $ignoretests ne "" } {
|
|
if { 0 <= [lsearch $ignoretests [file tail $test_name]]} {
|
|
continue
|
|
}
|
|
}
|
|
|
|
# set subdir to the tail of the dirname after $srcdir,
|
|
# for the driver files that want it. XXX this is silly.
|
|
# drivers should get a single var, not $srcdir/$subdir
|
|
set subdir [relative_filename $srcdir \
|
|
[file dirname $test_name]]
|
|
|
|
# XXX not the right thing to do.
|
|
set runtests [list [file tail $test_name] ""]
|
|
|
|
runtest $test_name
|
|
}
|
|
} else {
|
|
#
|
|
# Go digging for tests.
|
|
#
|
|
foreach dir $test_top_dirs {
|
|
if { $dir ne $testsuitedir } {
|
|
# Ignore this directory if is a directory to be
|
|
# ignored.
|
|
if {[info exists ignoredirs] && $ignoredirs ne ""} {
|
|
set found 0
|
|
foreach directory $ignoredirs {
|
|
if {[string match *$directory* $dir]} {
|
|
set found 1
|
|
break
|
|
}
|
|
}
|
|
if { $found } {
|
|
continue
|
|
}
|
|
}
|
|
|
|
# Run the test if dir_to_run was specified as a
|
|
# value (for example in MULTIPASS) and the test
|
|
# directory matches that directory.
|
|
if {[info exists dir_to_run] && $dir_to_run ne ""} {
|
|
# JYG: dir_to_run might be a space delimited list
|
|
# of directories. Look for match on each item.
|
|
set found 0
|
|
foreach directory $dir_to_run {
|
|
if {[string match *$directory* $dir]} {
|
|
set found 1
|
|
break
|
|
}
|
|
}
|
|
if {!$found} {
|
|
continue
|
|
}
|
|
}
|
|
|
|
# Run the test if cmdline_dir_to_run was specified
|
|
# by the user using --directory and the test
|
|
# directory matches that directory
|
|
if {[info exists cmdline_dir_to_run] \
|
|
&& $cmdline_dir_to_run ne ""} {
|
|
# JYG: cmdline_dir_to_run might be a space delimited
|
|
# list of directories. Look for match on each item.
|
|
set found 0
|
|
foreach directory $cmdline_dir_to_run {
|
|
# Look for a directory that ends with the
|
|
# provided --directory name.
|
|
if {[string match $directory $dir]
|
|
|| [string match "*/$directory" $dir]} {
|
|
set found 1
|
|
break
|
|
}
|
|
}
|
|
if {!$found} {
|
|
continue
|
|
}
|
|
}
|
|
|
|
foreach test_name [lsort [find $dir *.exp]] {
|
|
if { $test_name eq "" } {
|
|
continue
|
|
}
|
|
# Ignore this one if asked to.
|
|
if { $ignoretests ne "" } {
|
|
if { 0 <= [lsearch $ignoretests [file tail $test_name]]} {
|
|
continue
|
|
}
|
|
}
|
|
|
|
# Get the path after the $srcdir so we know
|
|
# the subdir we're in.
|
|
set subdir [relative_filename $srcdir \
|
|
[file dirname $test_name]]
|
|
# Check to see if the range of tests is limited,
|
|
# set `runtests' to a list of two elements: the script name
|
|
# and any arguments ("" if none).
|
|
if {[array exists all_runtests]} {
|
|
verbose "searching for $test_name in [array names all_runtests]" 2
|
|
if { 0 > [lsearch [array names all_runtests] [file tail $test_name]]} {
|
|
if { 0 > [lsearch [array names all_runtests] $test_name] } {
|
|
continue
|
|
}
|
|
}
|
|
set runtests [list [file tail $test_name] $all_runtests([file tail $test_name])]
|
|
} else {
|
|
set runtests [list [file tail $test_name] ""]
|
|
}
|
|
runtest $test_name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Restore the variables set by this pass.
|
|
foreach varval $restore {
|
|
if { [llength $varval] > 1 } {
|
|
verbose "Restoring [lindex $varval 0] to [lindex $varval 1]" 4
|
|
set [lindex $varval 0] [lindex $varval 1]
|
|
} else {
|
|
verbose "Restoring [lindex $varval 0] to `unset'" 4
|
|
unset -- [lindex $varval 0]
|
|
}
|
|
}
|
|
}
|
|
cleanup_target_hook $current_target
|
|
if { $target_count > 1 } {
|
|
log_summary
|
|
}
|
|
}
|
|
|
|
log_and_exit
|
|
|