One limitation of the DejaGnu board file interface is the lack of
support for setting environment variables on a board. As a
consequence, various GCC tests that depend on environment variable
setting are either skipped for remote targets, or do not function
correctly in the remote target case, unless a hack is used in the
board file to copy relevant environment variables (set directly on the
build system in the current testsuite code) from the build system to
the target.
I've posted a patch to the dejagnu list to add support for environment
variable handling to the DejaGnu board file interface and to DejaGnu's
ssh.exp (lists.gnu.org seems to be down at present so I can't link to
it here, but I've attached a copy).
Here are the corresponding GCC changes, which include a backported
copy of the relevant remote_* code in DejaGnu to avoid breaking things
with existing DejaGnu releases. This is only an RFC (and has no
ChangeLog entries) since it's possible the proposed board file
interface will change in the course of review, so requiring
adjustments to the GCC testsuite changes.
The changes here are not exhaustive (even for the target, let alone
for environment variables relevant to the host in the case of
remote-host testing), but are intended to cover the main cases where
lack of environment variable support caused problems for testing on
remote targets, or different test results in the remote case versus
the native, local testing case. Rather than literally replicating the
existing logic exactly in all cases changes, a general preference is
applied towards using the new remote_pushenv / remote_popenv for
saving and restoring environment variable settings, where that seems
appropriate for the test in question, rather than sometimes leaving
modified settings in effect globally for the rest of that testsuite
run.
Some notes on specific cases changed or not changed here:
* The DejaGnu interface handles pushing and popping values for
environment variables on a board. It doesn't include reading the
current value of a variable from a board (in particular, doesn't
have specific support for PATH-like variables where prepending
together with a colon is appropriate), and the remote case of
unsetting a variable actually just restores the initial value it had
on that board; pushing and popping a state of "unset" is not
supported. This influences the details of how some environment
variables are handled, but in ways I don't think are problems.
- Empty values are used in place of unset variables as needed.
- Handling of PATH-like variables is generally unchanged. Users
typically have existing methods for dealing with finding shared
libraries on a remote target that do not require setting
LD_LIBRARY_PATH: either having the libraries installed on the
target before running tests, or a board file that links with
-Wl,-dynamic-linker, and -Wl,-rpath, options. So while it might
be useful to have extra DejaGnu support for PATH-like variables,
and it might allow refactoring some of the GCC testsuite code
related to such variables, the lack of such support isn't
problematic the way the lack of support for other cases of
environment variables is problematic.
* The changes are only concerned with code that sets environment
variables for use by either the compiler and other tools ($host) or
by compiled code and libraries ($target) (and the priority is for
$target, remote targets being more common than remote hosts,
although many cases are fixed for $host as well). Code that only
reads environment variables (for properties of $build or
configuration of the testsuite), or only sets them for use on
$build, is not changed (although cases of saving and restoring on
$build might sometimes benefit from using the new interfaces to
avoid needing local code to save and restore values).
- gcc/testsuite/g++.dg/modules/modules.exp reads env(OS) but appears
to use it for properties of $host, not $build, so it is likely
that test would malfunction for the case where one of $host and
$build is Windows but the other is not. The same applies to some
other .exp files.
- Variables configuring the testsuite are typically set outside the
testsuite (sometimes in the GCC build system, sometimes only
available for use by the person or script testing GCC) and only
read in .exp files. However, GDB_FOR_GCC_TESTING, even though set
as well as read, is such a variable (only .exp files use it, so it
is indeed only relevant on $build, although it relates to a copy
of GDB run on the target).
* Except for the cases of dg-set-target-env-var and asan-gtest where
tests were previously skipped when environment variable setting was
unsupported, calls to remote_pushenv are allowed to fail and test
execution continues.
* GUALITY_GDB_NAME: there is no change to the pre-existing test for
whether this is set (on $build), but when the testsuite sets it,
that is done on $target (including transferring an existing value of
GUALITY_GDB_NAME from $build in a cross-compilation case). The
libstdc++-v3 tests using GUALITY_GDB_NAME only support native, local
testing (my previous fixes to align results from remote, cross,
installed testing better with those for native, build-tree testing
were specfically about compiler testsuites, not library ones), and
no changes are made to the environment variable setting there.
* DEBUGINFOD_URLS: tests now set it unconditionally to empty on the
target (rather than leaving unset when already unset).
* MAKEFLAGS: gcc.misc-tests/outputs.exp now sets it to empty on $host
(rather than unsetting on $build). This is done as a push and pop
(whereas previously the value was unset and never restored).
* The environment variable handling in gcc.target/msp430/msp430.exp
(all of which should be for the host, and which should probably also
be using push/pop rather than allowing global changes to escape) is
left untouched; I haven't tested for this target.
* GFORTRAN_NUM_IMAGES: there is no change to the pre-existing test for
whether this is set (on $build), but when the testsuite sets it,
that is done on $target (including transferring an existing value of
GFORTRAN_NUM_IMAGES from $build in a cross-compilation case). This
is also popped (as is GFORTRAN_SHARED_MEMORY_SIZE) rather than being
left in effect for subsequent .exp files.
* The environment variable handling in go.test/go-test.exp is left
untouched.
* ASAN_OPTIONS: now pushed and popped rather than the initially set
value being left in effect for subsequent .exp files.
* DEJAGNU_GTEST_ARG, HWASAN_OPTIONS: now pushed and popped rather than
set and unset.
* LC_ALL and LANG: no change to logic setting these variables,
although properly such settings should generally be for $host not
$build. Likewise for TERM and GCC_COLORS in lib/gcc-dg.exp, and
LANGUAGE and GCC_COLORS in libstdc++-v3/testsuite/lib/libstdc++.exp.
Some such settings are also done at top level when a .exp file is
loaded, rather than in an init function with a matching finish
function that could readily be made to use a push/pop pair.
* ADA_INCLUDE_PATH and ADA_OBJECTS_PATH: these are changed to use
remote_setenv (rather than push and pop) given the nature of the
logic making a global change inside gnat_target_compile (and
expected to persist) is awkward to turn into push and pop.
* GCC_EXEC_PREFIX: no changes are made (although it might be relevant
for build-tree remote-host testing) as this doesn't seem always to
follow a clean stack discipline.
* ACC_DEVICE_TYPE: now pushed and popped rather than set and remaining
in effect.
Tested with no regressions for x86_64-pc-linux-gnu (with both existing
DejaGnu without the environment variable support, and DejaGnu patched
with the support added). Also did spot tests that the new
functionality operates correctly in a cross to aarch64-linux-gnu
(using ssh.exp).
diff --git a/gcc/testsuite/g++.dg/guality/guality.exp
b/gcc/testsuite/g++.dg/guality/guality.exp
index 7f1e7b23a608..3ac72c586042 100644
--- a/gcc/testsuite/g++.dg/guality/guality.exp
+++ b/gcc/testsuite/g++.dg/guality/guality.exp
@@ -56,15 +56,14 @@ if ![info exists ::env(GUALITY_GDB_NAME)] {
} else {
set guality_gdb_name "gdb"
}
- setenv GUALITY_GDB_NAME "$guality_gdb_name"
+} else {
+ set guality_gdb_name $::env(GUALITY_GDB_NAME)
}
+remote_pushenv target GUALITY_GDB_NAME "$guality_gdb_name"
-if [info exists ::env(DEBUGINFOD_URLS)] {
- set orig_debuginfod_urls "$::env(DEBUGINFOD_URLS)"
- setenv DEBUGINFOD_URLS ""
-}
+remote_pushenv target DEBUGINFOD_URLS ""
-report_gdb $::env(GUALITY_GDB_NAME) [info script]
+report_gdb $guality_gdb_name [info script]
global DG_TORTURE_OPTIONS LTO_TORTURE_OPTIONS
set guality_dg_torture_options [guality_minimal_options $DG_TORTURE_OPTIONS]
@@ -107,13 +106,9 @@ if {[check_guality "
gcc-dg-runtest $Og "" ""
}
-if [info exists guality_gdb_name] {
- unsetenv GUALITY_GDB_NAME
-}
+remote_popenv target GUALITY_GDB_NAME
-if [info exists ::env(DEBUGINFOD_URLS)] {
- setenv DEBUGINFOD_URLS "$orig_debuginfod_urls"
-}
+remote_popenv target DEBUGINFOD_URLS
torture-finish
dg-finish
diff --git a/gcc/testsuite/g++.dg/simulate-thread/simulate-thread.exp
b/gcc/testsuite/g++.dg/simulate-thread/simulate-thread.exp
index 2dc5decd5eac..facaeebc9056 100644
--- a/gcc/testsuite/g++.dg/simulate-thread/simulate-thread.exp
+++ b/gcc/testsuite/g++.dg/simulate-thread/simulate-thread.exp
@@ -34,19 +34,14 @@ set-torture-options [list \
{ -O3 -g -std=c++11 } \
{ -Os -g } ]
-if [info exists ::env(DEBUGINFOD_URLS)] {
- set orig_debuginfod_urls "$::env(DEBUGINFOD_URLS)"
- setenv DEBUGINFOD_URLS ""
-}
+remote_pushenv target DEBUGINFOD_URLS ""
if [gdb-exists] {
gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" ""
gcc-dg-runtest [lsort [glob $srcdir/c-c++-common/simulate-thread/*.c]] "" ""
}
-if [info exists ::env(DEBUGINFOD_URLS)] {
- setenv DEBUGINFOD_URLS "$orig_debuginfod_urls"
-}
+remote_popenv target DEBUGINFOD_URLS
torture-finish
dg-finish
diff --git a/gcc/testsuite/gcc.dg/guality/guality.exp
b/gcc/testsuite/gcc.dg/guality/guality.exp
index c38ae8899bc0..4ced1147330f 100644
--- a/gcc/testsuite/gcc.dg/guality/guality.exp
+++ b/gcc/testsuite/gcc.dg/guality/guality.exp
@@ -56,15 +56,14 @@ if ![info exists ::env(GUALITY_GDB_NAME)] {
} else {
set guality_gdb_name "gdb"
}
- setenv GUALITY_GDB_NAME "$guality_gdb_name"
+} else {
+ set guality_gdb_name $::env(GUALITY_GDB_NAME)
}
+remote_pushenv target GUALITY_GDB_NAME "$guality_gdb_name"
-if [info exists ::env(DEBUGINFOD_URLS)] {
- set orig_debuginfod_urls "$::env(DEBUGINFOD_URLS)"
- setenv DEBUGINFOD_URLS ""
-}
+remote_pushenv target DEBUGINFOD_URLS ""
-report_gdb $::env(GUALITY_GDB_NAME) [info script]
+report_gdb $guality_gdb_name [info script]
proc guality_transform_options { args } {
set res [list]
@@ -122,13 +121,9 @@ if {[check_guality "
gcc-dg-runtest $Og "" "-Wc++-compat"
}
-if [info exists guality_gdb_name] {
- unsetenv GUALITY_GDB_NAME
-}
+remote_popenv target GUALITY_GDB_NAME
-if [info exists ::env(DEBUGINFOD_URLS)] {
- setenv DEBUGINFOD_URLS "$orig_debuginfod_urls"
-}
+remote_popenv target DEBUGINFOD_URLS
torture-finish
dg-finish
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/simulate-thread.exp
b/gcc/testsuite/gcc.dg/simulate-thread/simulate-thread.exp
index 8664019d88a4..6f318f378072 100644
--- a/gcc/testsuite/gcc.dg/simulate-thread/simulate-thread.exp
+++ b/gcc/testsuite/gcc.dg/simulate-thread/simulate-thread.exp
@@ -36,19 +36,14 @@ set-torture-options [list \
{ -O2 -g } \
{ -O3 -g } ]
-if [info exists ::env(DEBUGINFOD_URLS)] {
- set orig_debuginfod_urls "$::env(DEBUGINFOD_URLS)"
- setenv DEBUGINFOD_URLS ""
-}
+remote_pushenv target DEBUGINFOD_URLS ""
if [gdb-exists] {
gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] "" ""
gcc-dg-runtest [lsort [glob $srcdir/c-c++-common/simulate-thread/*.c]] "" ""
}
-if [info exists ::env(DEBUGINFOD_URLS)] {
- setenv DEBUGINFOD_URLS "$orig_debuginfod_urls"
-}
+remote_popenv target DEBUGINFOD_URLS
torture-finish
dg-finish
diff --git a/gcc/testsuite/gcc.misc-tests/help.exp
b/gcc/testsuite/gcc.misc-tests/help.exp
index 47bff2c07655..0ad475422930 100644
--- a/gcc/testsuite/gcc.misc-tests/help.exp
+++ b/gcc/testsuite/gcc.misc-tests/help.exp
@@ -33,13 +33,7 @@ gcc_parallel_test_enable 0
# wide (or 80 when COLUMNS is not defined), set the COLUMNS environment
# variable to a value large enough to prevent this (and restore it when
# done).
-global env
-
-if [ info exists env(COLUMNS) ] {
- set prev_columns $env(COLUMNS)
-}
-
-set env(COLUMNS) 1024
+remote_pushenv host COLUMNS 1024
# Document --version. Ideally, there should be no undocumented switches
# in --help.
@@ -154,13 +148,6 @@ check_for_options c "--help=^joined,^separate" "" "" ""
check_for_options c "--help=hardened" "The following options are enabled by
-fhardened" "" ""
-if [ info exists prev_columns ] {
- # Reset the enviroment variable to its oriuginal value.
- set env(COLUMNS) $prev_columns
-} else {
- # Remove the variable from the environment if it didn't exist
- # to begin with to avoid affecting subsequent tests.
- array unset env COLUMNS
-}
+remote_popenv host COLUMNS
gcc_parallel_test_enable 1
diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp
b/gcc/testsuite/gcc.misc-tests/outputs.exp
index 5a2d2f7fdbfa..4304c0f51ec3 100644
--- a/gcc/testsuite/gcc.misc-tests/outputs.exp
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -90,9 +90,7 @@ if { [info exists ::env(OS)] && [string match "Windows*"
$::env(OS)] } {
# Avoid possible influence from the make jobserver,
# otherwise ltrans0.ltrans_args files may be missing.
-if [info exists env(MAKEFLAGS)] {
- unsetenv MAKEFLAGS
-}
+remote_pushenv host MAKEFLAGS ""
# For the test named TEST, run the compiler with SOURCES and OPTS, and
# look in DIRS for OUTPUTS. SOURCES is a list of suffixes for source
@@ -895,3 +893,5 @@ outest "$b-377 doc single !-c -o -dd -st=" $sing "-c
-dumpdir dir/ -dumpbase $b
gcc_parallel_test_enable 1
+
+remote_popenv host MAKEFLAGS
diff --git a/gcc/testsuite/gfortran.dg/coarray/caf.exp
b/gcc/testsuite/gfortran.dg/coarray/caf.exp
index b8c2ca773166..797b84998fdf 100644
--- a/gcc/testsuite/gfortran.dg/coarray/caf.exp
+++ b/gcc/testsuite/gfortran.dg/coarray/caf.exp
@@ -79,12 +79,15 @@ proc dg-compile-aux-modules { args } {
if { [getenv GFORTRAN_NUM_IMAGES] == "" } {
# Some caf_shmem tests need at least 8 images. This is also to limit the
# number of images on big machines preventing overload w/o any benefit.
- setenv GFORTRAN_NUM_IMAGES 8
+ set num_images 8
+} else {
+ set num_images [getenv GFORTRAN_NUM_IMAGES]
}
+remote_pushenv target GFORTRAN_NUM_IMAGES $num_images
if { [getenv GCC_TEST_RUN_EXPENSIVE] == "" } {
# Lower caf_shmem shared memory block size to avoid excessive VM consumption.
- setenv GFORTRAN_SHARED_MEMORY_SIZE 2M
+ remote_pushenv target GFORTRAN_SHARED_MEMORY_SIZE 2M
}
# Main loop.
@@ -138,5 +141,12 @@ foreach test [lsort [glob -nocomplain
$srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]]
}
}
}
+
+remote_popenv target GFORTRAN_NUM_IMAGES
+
+if { [getenv GCC_TEST_RUN_EXPENSIVE] == "" } {
+ remote_popenv target GFORTRAN_SHARED_MEMORY_SIZE
+}
+
torture-finish
dg-finish
diff --git a/gcc/testsuite/gfortran.dg/guality/guality.exp
b/gcc/testsuite/gfortran.dg/guality/guality.exp
index dddbe8b02f56..18f56b333eda 100644
--- a/gcc/testsuite/gfortran.dg/guality/guality.exp
+++ b/gcc/testsuite/gfortran.dg/guality/guality.exp
@@ -37,15 +37,14 @@ if ![info exists ::env(GUALITY_GDB_NAME)] {
} else {
set guality_gdb_name "gdb"
}
- setenv GUALITY_GDB_NAME "$guality_gdb_name"
+} else {
+ set guality_gdb_name $::env(GUALITY_GDB_NAME)
}
+remote_pushenv target GUALITY_GDB_NAME "$guality_gdb_name"
-if [info exists ::env(DEBUGINFOD_URLS)] {
- set orig_debuginfod_urls "$::env(DEBUGINFOD_URLS)"
- setenv DEBUGINFOD_URLS ""
-}
+remote_pushenv target DEBUGINFOD_URLS ""
-report_gdb $::env(GUALITY_GDB_NAME) [info script]
+report_gdb $guality_gdb_name [info script]
global DG_TORTURE_OPTIONS
set guality_dg_torture_options [guality_minimal_options $DG_TORTURE_OPTIONS]
@@ -54,13 +53,9 @@ set-torture-options \
gfortran-dg-runtest [lsort [glob $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]] ""
""
-if [info exists guality_gdb_name] {
- unsetenv GUALITY_GDB_NAME
-}
+remote_popenv target GUALITY_GDB_NAME
-if [info exists ::env(DEBUGINFOD_URLS)] {
- setenv DEBUGINFOD_URLS "$orig_debuginfod_urls"
-}
+remote_popenv target DEBUGINFOD_URLS
torture-finish
dg-finish
diff --git a/gcc/testsuite/lib/asan-dg.exp b/gcc/testsuite/lib/asan-dg.exp
index 53210ca9627c..41cf81cbe886 100644
--- a/gcc/testsuite/lib/asan-dg.exp
+++ b/gcc/testsuite/lib/asan-dg.exp
@@ -121,7 +121,7 @@ proc asan_init { args } {
global asan_saved_TEST_ALWAYS_FLAGS
global asan_saved_ALWAYS_CXXFLAGS
- setenv ASAN_OPTIONS "color=never"
+ remote_pushenv target ASAN_OPTIONS "color=never"
set needs_cxx [lindex $args 0]
set link_flags ""
@@ -175,6 +175,7 @@ proc asan_finish { args } {
set ld_library_path $asan_saved_library_path
set_ld_library_path_env_vars
}
+ remote_popenv target ASAN_OPTIONS
clear_effective_target_cache
}
@@ -303,7 +304,6 @@ proc asan-gtest { args } {
if { ![info exists asan_last_gtest_test_list] } { return }
if { [llength $asan_last_gtest_test_list] == 0 } { return }
- if { ![isnative] || [is_remote target] } { return }
set gtest_test_list $asan_last_gtest_test_list
unset asan_last_gtest_test_list
@@ -329,9 +329,13 @@ proc asan-gtest { args } {
set testname "$testcase $gtest"
set status -1
- setenv DEJAGNU_GTEST_ARG "$gtest"
+ set res [remote_pushenv target DEJAGNU_GTEST_ARG "$gtest"]
+ if { $res != 0 } {
+ remote_popenv target DEJAGNU_GTEST_ARG
+ return
+ }
set result [${tool}_load ./$output_file $gtest]
- unsetenv DEJAGNU_GTEST_ARG
+ remote_popenv target DEJAGNU_GTEST_ARG
set status [lindex $result 0]
set output [lindex $result 1]
if { "$status" == "pass" } {
@@ -344,9 +348,9 @@ proc asan-gtest { args } {
set regexpr [lindex $gtest_death 2]
set status -1
- setenv DEJAGNU_GTEST_ARG "$gtest:$id"
+ remote_pushenv target DEJAGNU_GTEST_ARG "$gtest:$id"
set result [${tool}_load ./$output_file "$gtest:$id"]
- unsetenv DEJAGNU_GTEST_ARG
+ remote_popenv target DEJAGNU_GTEST_ARG
set status [lindex $result 0]
set output [lindex $result 1]
if { "$status" == "fail" } {
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index 191e2b83fe12..c7d7eafc0008 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -14,6 +14,8 @@
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
+load_lib remote-env.exp
+
load_lib target-libpath.exp
load_lib wrapper.exp
diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp
index 9f1832592574..deeb5384560d 100644
--- a/gcc/testsuite/lib/gcc-dg.exp
+++ b/gcc/testsuite/lib/gcc-dg.exp
@@ -482,10 +482,11 @@ if { [info procs ${tool}_load] != [list] \
set saved_target_env_var [list]
if { [info exists set_target_env_var] \
&& [llength $set_target_env_var] != 0 } {
- if { [is_remote target] } {
+ set res [set-target-env-var]
+ if { $res != 0 } {
+ restore-target-env-var
return [list "unsupported" ""]
}
- set-target-env-var
}
set result [eval [list saved_${tool}_load $program] $args]
if { [info exists set_target_env_var] \
@@ -592,26 +593,19 @@ proc set-target-env-var { } {
foreach env_var $set_target_env_var {
set var [lindex $env_var 0]
set value [lindex $env_var 1]
- if [info exists ::env($var)] {
- lappend saved_target_env_var [list $var 1 $::env($var)]
- } else {
- lappend saved_target_env_var [list $var 0]
+ lappend saved_target_env_var $var
+ set res [remote_pushenv target $var $value]
+ if { $res != 0 } {
+ return $res
}
- setenv $var $value
}
+ return 0
}
proc restore-target-env-var { } {
upvar 1 saved_target_env_var saved_target_env_var
- for { set env_vari [llength $saved_target_env_var] } {
- [incr env_vari -1] >= 0 } {} {
- set env_var [lindex $saved_target_env_var $env_vari]
- set var [lindex $env_var 0]
- if [lindex $env_var 1] {
- setenv $var [lindex $env_var 2]
- } else {
- unsetenv $var
- }
+ foreach env_var $saved_target_env_var {
+ remote_popenv target $env_var
}
}
@@ -625,26 +619,15 @@ proc dg-set-compiler-env-var { args } {
set var [lindex $args 1]
set value [lindex $args 2]
verbose "dg-set-compiler-env-var $var $value" 2
- if [info exists ::env($var)] {
- lappend saved_compiler_env_var [list $var 1 $::env($var)]
- } else {
- lappend saved_compiler_env_var [list $var 0]
- }
- setenv $var $value
+ lappend saved_compiler_env_var $var
+ remote_pushenv host $var $value
lappend set_compiler_env_var [list $var $value]
}
proc restore-compiler-env-var { } {
global saved_compiler_env_var
- for { set env_vari [llength $saved_compiler_env_var] } {
- [incr env_vari -1] >= 0 } {} {
- set env_var [lindex $saved_compiler_env_var $env_vari]
- set var [lindex $env_var 0]
- if [lindex $env_var 1] {
- setenv $var [lindex $env_var 2]
- } else {
- unsetenv $var
- }
+ foreach env_var $saved_compiler_env_var {
+ remote_popenv host $env_var
}
}
diff --git a/gcc/testsuite/lib/gcc-gdb-test.exp
b/gcc/testsuite/lib/gcc-gdb-test.exp
index f7c1da8fae25..81cdcc4bd0b8 100644
--- a/gcc/testsuite/lib/gcc-gdb-test.exp
+++ b/gcc/testsuite/lib/gcc-gdb-test.exp
@@ -59,7 +59,8 @@ proc gdb-test { useline args } {
set line [get-absolute-line $useline $line]
}
- set gdb_name $::env(GUALITY_GDB_NAME)
+ global guality_gdb_name
+ set gdb_name $guality_gdb_name
set testname "$testcase line $line [lindex $args 1] == [lindex $args 2]"
set output_file "[file rootname [file tail $prog]].exe"
set cmd_file "[file rootname [file tail $prog]].gdb"
diff --git a/gcc/testsuite/lib/gnat.exp b/gcc/testsuite/lib/gnat.exp
index 21a9e86defb1..48e3a95d581b 100644
--- a/gcc/testsuite/lib/gnat.exp
+++ b/gcc/testsuite/lib/gnat.exp
@@ -146,8 +146,8 @@ proc gnat_target_compile { source dest type options } {
# gnatlink looks for system.ads itself and has no --RTS option, so
# specify via environment
- setenv ADA_INCLUDE_PATH "$rtsdir/adainclude"
- setenv ADA_OBJECTS_PATH "$rtsdir/adainclude"
+ remote_setenv host ADA_INCLUDE_PATH "$rtsdir/adainclude"
+ remote_setenv host ADA_OBJECTS_PATH "$rtsdir/adainclude"
# Always log so compilations can be repeated manually.
verbose -log "ADA_INCLUDE_PATH=$rtsdir/adainclude"
verbose -log "ADA_OBJECTS_PATH=$rtsdir/adainclude"
diff --git a/gcc/testsuite/lib/hwasan-dg.exp b/gcc/testsuite/lib/hwasan-dg.exp
index 0abe2b38730b..28442275281b 100644
--- a/gcc/testsuite/lib/hwasan-dg.exp
+++ b/gcc/testsuite/lib/hwasan-dg.exp
@@ -116,7 +116,7 @@ proc hwasan_init { args } {
global hwasan_saved_ALWAYS_CXXFLAGS
set needs_cxx [lindex $args 0]
- setenv HWASAN_OPTIONS "random_tags=0"
+ remote_pushenv target HWASAN_OPTIONS "random_tags=0"
if [istarget x86_64-*-*] {
set target_hwasan_flags "-mlam=u57"
@@ -162,7 +162,7 @@ proc hwasan_finish { args } {
global hwasan_saved_library_path
global ld_library_path
- unsetenv HWASAN_OPTIONS
+ remote_popenv target HWASAN_OPTIONS
if [info exists hwasan_saved_ALWAYS_CXXFLAGS ] {
set ALWAYS_CXXFLAGS $hwasan_saved_ALWAYS_CXXFLAGS
diff --git a/gcc/testsuite/lib/remote-env.exp b/gcc/testsuite/lib/remote-env.exp
new file mode 100644
index 000000000000..d94e5efc850a
--- /dev/null
+++ b/gcc/testsuite/lib/remote-env.exp
@@ -0,0 +1,104 @@
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program 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.
+#
+# This program 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 GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Remote environment variable support (backported from DejaGnu 1.6,4).
+
+if { [info procs remote_pushenv] == "" } then {
+ proc remote_setenv { dest var value } {
+ return [call_remote "" setenv $dest $var $value]
+ }
+
+ proc standard_setenv { dest var value } {
+ if { ![isremote $dest] } {
+ global env
+ set env($var) $value
+ return 0
+ } else {
+ return 1
+ }
+ }
+
+ proc remote_unsetenv { dest var } {
+ return [call_remote "" unsetenv $dest $var]
+ }
+
+ proc standard_unsetenv { dest var } {
+ if { ![isremote $dest] } {
+ global env
+ unset env($var)
+ } else {
+ global board_info
+ unset board_info($dest,env_$var)
+ }
+ }
+
+ proc remote_saveenv { dest var } {
+ return [call_remote "" saveenv $dest $var]
+ }
+
+ proc standard_saveenv { dest var } {
+ if { ![isremote $dest] } {
+ global env
+ if { [info exists env($var)] } {
+ return [list 1 $env($var)]
+ } else {
+ return [list 0 ""]
+ }
+ } else {
+ global board_info
+ if { [info exists board_info($dest,env_$var)] } {
+ return [list 1 $board_info($dest,env_$var)]
+ } else {
+ return [list 0 ""]
+ }
+ }
+ }
+
+ proc remote_restoreenv { dest var saved } {
+ set was_set [lindex $saved 0]
+ set value [lindex $saved 1]
+ if { $was_set == 1 } {
+ return [remote_setenv $dest $var $value]
+ } else {
+ return [remote_unsetenv $dest $var]
+ }
+ }
+
+ proc remote_pushenv { dest var value } {
+ set saved [remote_saveenv $dest $var]
+ set res [remote_setenv $dest $var $value]
+ if {[board_info $dest exists name]} {
+ set dest [board_info $dest name]
+ }
+ global board_info
+ if { ![info exists board_info($dest,saved_env_$var)] } {
+ set board_info($dest,saved_env_$var) ""
+ }
+ set board_info($dest,saved_env_$var) [list $saved
$board_info($dest,saved_env_$var)]
+ return $res
+ }
+
+ proc remote_popenv { dest var } {
+ if {[board_info $dest exists name]} {
+ set dest [board_info $dest name]
+ }
+ global board_info
+ set old_stack $board_info($dest,saved_env_$var)
+ set saved [lindex $old_stack 0]
+ set board_info($dest,saved_env_$var) [lindex $old_stack 1]
+ return [remote_restoreenv $dest $var $saved]
+ }
+}
diff --git a/gcc/testsuite/lib/tsan-dg.exp b/gcc/testsuite/lib/tsan-dg.exp
index 6379d18e6b54..0bbcd6485266 100644
--- a/gcc/testsuite/lib/tsan-dg.exp
+++ b/gcc/testsuite/lib/tsan-dg.exp
@@ -81,9 +81,6 @@ proc tsan_link_flags { paths } {
return "$flags"
}
-set orig_tsan_options_saved 0
-set orig_tsan_options 0
-
#
# tsan_init -- called at the start of each subdir of tests
#
@@ -96,17 +93,8 @@ proc tsan_init { args } {
global tsan_saved_ALWAYS_CXXFLAGS
global dg-do-what-default
global tsan_saved_dg-do-what-default
- global orig_tsan_options_saved
- global orig_tsan_options
-
- if { $orig_tsan_options_saved == 0 } {
- # Save the original environment.
- if [info exists env(TSAN_OPTIONS)] {
- set orig_tsan_options "$env(TSAN_OPTIONS)"
- set orig_tsan_options_saved 1
- }
- }
- setenv TSAN_OPTIONS color=never
+
+ remote_pushenv target TSAN_OPTIONS color=never
set link_flags ""
if ![is_remote host] {
@@ -148,14 +136,8 @@ proc tsan_finish { args } {
global tsan_saved_dg-do-what-default
global tsan_saved_library_path
global ld_library_path
- global orig_tsan_options_saved
- global orig_tsan_options
- if { $orig_tsan_options_saved } {
- setenv TSAN_OPTIONS "$orig_tsan_options"
- } elseif [info exists env(TSAN_OPTIONS)] {
- unsetenv TSAN_OPTIONS
- }
+ remote_popenv target TSAN_OPTIONS
if [info exists tsan_saved_ALWAYS_CXXFLAGS ] {
set ALWAYS_CXXFLAGS $tsan_saved_ALWAYS_CXXFLAGS
diff --git a/gcc/testsuite/lib/ubsan-dg.exp b/gcc/testsuite/lib/ubsan-dg.exp
index 15013cd45d2e..72f50ef5a838 100644
--- a/gcc/testsuite/lib/ubsan-dg.exp
+++ b/gcc/testsuite/lib/ubsan-dg.exp
@@ -17,9 +17,6 @@
# Return 1 if compilation with -fsanitize=undefined is error-free for trivial
# code, 0 otherwise.
-set orig_ubsan_options_saved 0
-set orig_ubsan_options 0
-
proc check_effective_target_fsanitize_undefined {} {
return [check_runtime fsanitize_undefined {
int main (void) { return 0; }
@@ -86,18 +83,9 @@ proc ubsan_init { args } {
global TOOL_OPTIONS
global ubsan_saved_TEST_ALWAYS_FLAGS
global ubsan_saved_ALWAYS_CXXFLAGS
- global orig_ubsan_options_saved
- global orig_ubsan_options
set needs_cxx [lindex $args 0]
- if { $orig_ubsan_options_saved == 0 } {
- # Save the original environment.
- if [info exists env(UBSAN_OPTIONS)] {
- set orig_ubsan_options "$env(UBSAN_OPTIONS)"
- set orig_ubsan_options_saved 1
- }
- }
- setenv UBSAN_OPTIONS color=never
+ remote_pushenv target UBSAN_OPTIONS color=never
set link_flags ""
if ![is_remote host] {
@@ -133,14 +121,8 @@ proc ubsan_finish { args } {
global ubsan_saved_ALWAYS_CXXFLAGS
global ubsan_saved_library_path
global ld_library_path
- global orig_ubsan_options_saved
- global orig_ubsan_options
- if { $orig_ubsan_options_saved } {
- setenv UBSAN_OPTIONS "$orig_ubsan_options"
- } elseif [info exists env(UBSAN_OPTIONS)] {
- unsetenv UBSAN_OPTIONS
- }
+ remote_popenv target UBSAN_OPTIONS
if [info exists ubsan_saved_ALWAYS_CXXFLAGS ] {
set ALWAYS_CXXFLAGS $ubsan_saved_ALWAYS_CXXFLAGS
diff --git a/libatomic/testsuite/lib/libatomic.exp
b/libatomic/testsuite/lib/libatomic.exp
index 456493c3a797..0cc479a8a774 100644
--- a/libatomic/testsuite/lib/libatomic.exp
+++ b/libatomic/testsuite/lib/libatomic.exp
@@ -28,6 +28,7 @@ load_lib dg.exp
# loaded until ${tool}_target_compile is defined since it uses that
# to determine default LTO options.
+load_gcc_lib remote-env.exp
load_gcc_lib file-format.exp
load_gcc_lib target-supports.exp
load_gcc_lib target-utils.exp
diff --git a/libffi/testsuite/lib/libffi.exp b/libffi/testsuite/lib/libffi.exp
index 01cc12fa3b4b..4d5e6557b3fd 100644
--- a/libffi/testsuite/lib/libffi.exp
+++ b/libffi/testsuite/lib/libffi.exp
@@ -22,6 +22,7 @@ proc load_gcc_lib { filename } {
load_lib dg.exp
load_lib libgloss.exp
+load_gcc_lib remote-env.exp
load_gcc_lib target-supports.exp
load_gcc_lib target-supports-dg.exp
load_gcc_lib target-libpath.exp
diff --git a/libgo/testsuite/lib/libgo.exp b/libgo/testsuite/lib/libgo.exp
index 638bf8696025..2d9d7caffaa1 100644
--- a/libgo/testsuite/lib/libgo.exp
+++ b/libgo/testsuite/lib/libgo.exp
@@ -42,6 +42,7 @@ proc load_gcc_lib { filename } {
set loaded_libs($filename) ""
}
+load_gcc_lib remote-env.exp
load_gcc_lib multiline.exp
load_gcc_lib prune.exp
load_gcc_lib target-libpath.exp
diff --git a/libgomp/testsuite/lib/libgomp.exp
b/libgomp/testsuite/lib/libgomp.exp
index 93e2a681cb4c..56dbb213648e 100644
--- a/libgomp/testsuite/lib/libgomp.exp
+++ b/libgomp/testsuite/lib/libgomp.exp
@@ -15,6 +15,7 @@ load_lib standard.exp
# loaded until ${tool}_target_compile is defined since it uses that
# to determine default LTO options.
+load_gcc_lib remote-env.exp
load_gcc_lib multiline.exp
load_gcc_lib prune.exp
load_gcc_lib target-libpath.exp
diff --git a/libgomp/testsuite/libgomp.oacc-c++/c++.exp
b/libgomp/testsuite/libgomp.oacc-c++/c++.exp
index 7b2315e406f2..2193962ebda7 100644
--- a/libgomp/testsuite/libgomp.oacc-c++/c++.exp
+++ b/libgomp/testsuite/libgomp.oacc-c++/c++.exp
@@ -99,7 +99,7 @@ foreach offload_target [concat [split $offload_targets ","]
"disable"] {
# that we're actually going to test.
set tagopt "$tagopt -foffload=$offload_target"
# Force usage of the corresponding OpenACC device type.
- setenv ACC_DEVICE_TYPE $openacc_device_type
+ remote_pushenv target ACC_DEVICE_TYPE $openacc_device_type
# To get better test coverage for device-specific code that is only
# ever used in offloading configurations, we'd like more thorough
@@ -121,6 +121,7 @@ foreach offload_target [concat [split $offload_targets ","]
"disable"] {
}
gcc-dg-runtest $tests "$tagopt" ""
+ remote_popenv target ACC_DEVICE_TYPE
}
unset offload_target
diff --git a/libgomp/testsuite/libgomp.oacc-c/c.exp
b/libgomp/testsuite/libgomp.oacc-c/c.exp
index 8ca0c81687cc..38eefa85dca3 100644
--- a/libgomp/testsuite/libgomp.oacc-c/c.exp
+++ b/libgomp/testsuite/libgomp.oacc-c/c.exp
@@ -80,7 +80,7 @@ foreach offload_target [concat [split $offload_targets ","]
"disable"] {
# that we're actually going to test.
set tagopt "$tagopt -foffload=$offload_target"
# Force usage of the corresponding OpenACC device type.
- setenv ACC_DEVICE_TYPE $openacc_device_type
+ remote_pushenv target ACC_DEVICE_TYPE $openacc_device_type
# To get better test coverage for device-specific code that is only
# ever used in offloading configurations, we'd like more thorough
@@ -102,6 +102,7 @@ foreach offload_target [concat [split $offload_targets ","]
"disable"] {
}
gcc-dg-runtest $tests "$tagopt" ""
+ remote_popenv target ACC_DEVICE_TYPE
}
unset offload_target
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
b/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
index e5844ad00fa2..c768edbc2336 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
+++ b/libgomp/testsuite/libgomp.oacc-fortran/fortran.exp
@@ -96,12 +96,13 @@ foreach offload_target [concat [split $offload_targets ","]
"disable"] {
# that we're actually going to test.
set tagopt "$tagopt -foffload=$offload_target"
# Force usage of the corresponding OpenACC device type.
- setenv ACC_DEVICE_TYPE $openacc_device_type
+ remote_pushenv target ACC_DEVICE_TYPE $openacc_device_type
# For Fortran we're doing torture testing, as Fortran has far more tests
# with arrays etc. that testing just -O0 or -O2 is insufficient, that is
# typically not the case for C/C++.
gfortran-dg-runtest $tests "$tagopt" ""
+ remote_popenv target ACC_DEVICE_TYPE
}
unset offload_target
diff --git a/libitm/testsuite/lib/libitm.exp b/libitm/testsuite/lib/libitm.exp
index 2de0f6cbf158..6a274ecef237 100644
--- a/libitm/testsuite/lib/libitm.exp
+++ b/libitm/testsuite/lib/libitm.exp
@@ -27,6 +27,7 @@ load_lib dg.exp
# loaded until ${tool}_target_compile is defined since it uses that
# to determine default LTO options.
+load_gcc_lib remote-env.exp
load_gcc_lib multiline.exp
load_gcc_lib prune.exp
load_gcc_lib target-libpath.exp
diff --git a/libphobos/testsuite/lib/libphobos.exp
b/libphobos/testsuite/lib/libphobos.exp
index 33f13e724f6a..55bfc321e0c2 100644
--- a/libphobos/testsuite/lib/libphobos.exp
+++ b/libphobos/testsuite/lib/libphobos.exp
@@ -29,6 +29,7 @@ proc load_gcc_lib { filename } {
load_lib dg.exp
load_lib libgloss.exp
+load_gcc_lib remote-env.exp
load_gcc_lib target-supports.exp
load_gcc_lib target-supports-dg.exp
load_gcc_lib dg-options.exp
diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp
b/libstdc++-v3/testsuite/lib/libstdc++.exp
index b2b1934a5240..560b781bfd9e 100644
--- a/libstdc++-v3/testsuite/lib/libstdc++.exp
+++ b/libstdc++-v3/testsuite/lib/libstdc++.exp
@@ -63,6 +63,7 @@ proc search_for { file pattern } {
load_lib dg.exp
load_lib libgloss.exp
# compiler routines, then ours
+load_gcc_lib remote-env.exp
load_gcc_lib target-supports.exp
load_gcc_lib target-supports-dg.exp
load_gcc_lib scanasm.exp
diff --git a/libvtv/testsuite/lib/libvtv.exp b/libvtv/testsuite/lib/libvtv.exp
index 23c6270975b6..3cb02c99b4ad 100644
--- a/libvtv/testsuite/lib/libvtv.exp
+++ b/libvtv/testsuite/lib/libvtv.exp
@@ -28,6 +28,7 @@ load_lib dg.exp
# loaded until ${tool}_target_compile is defined since it uses that
# to determine default LTO options.
+load_gcc_lib remote-env.exp
load_gcc_lib multiline.exp
load_gcc_lib prune.exp
load_gcc_lib target-libpath.exp
--
Joseph S. Myers
[email protected]
Remote environment variable support
One limitation of the DejaGnu board file interface is the lack of
support for setting environment variables on a board. As a
consequence, various GCC tests that depend on environment variable
setting are either skipped for remote targets, or do not function
correctly in the remote target case, unless a hack is used in the
board file to copy relevant environment variables (set directly on the
build system in the current testsuite code) from the build system to
the target.
Add support for the most common environment variable cases (as used in
the GCC testsuites) to the board file interface, and implement the
underlying support in ssh.exp as well as for the local testing case.
The basic operations provided are setenv and unsetenv, with a
convention for how remote boards store the current environment
variable settings in board_info($dest,env_$var). Since a common use
case is setting a variable only for a given test or group of tests,
and restoring the previous state afterwards, there are also saveenv
and restoreenv operations, and, building on top of those, pushenv and
popenv operations that maintain a stack of saved state for a given
environment variable and restore from that stack.
Some of the main limitations in this interface are as follows:
* There is no getenv interface; tests should generally only need to
set a controlled environment on the board rather than retrieve the
original uncontrolled state, except for the save/restore case (which
can hopefully be handled, as in ssh.exp, b only ever setting
variables in the context of an individual test being run, rather
than actually changing some kind of global state on the board).
* The unsetenv interface unsets a variable in the local state, but
restores it to its initial state (not necessarily unset) in the
remote case. Similarly, the pushenv interface only supports setting
a string value (with previous state saved) rather than setting
either "unset" or "initial" (with previous state saved).
* There is no handling for PATH-like variables, where appropriate
handling is prepending a new value (plus colon) rather than fully
replacing a previous value. This is not in practice an important
limitation for testing GCC, since the use of variables such as
LD_LIBRARY_PATH in the GCC testsuites is readily avoided in remote
testing, either by testing an installed compiler (with the required
shared libraries installed in the root filesystem) or by using a
board file that links with options such as -rpath. If it were
desired to handle such variables, however, I'd be inclined to prefer
a "prepend with colon" interface rather than building it on a getenv
interface.
diff --git a/lib/remote.exp b/lib/remote.exp
index 4110575..30fa797 100644
--- a/lib/remote.exp
+++ b/lib/remote.exp
@@ -1446,4 +1446,108 @@ proc remote_swap_conn { host } {
return "pass"
}
+# Set an environment variable; return 0 if supported, 1 if not.
+# Remote boards supporting environment variable setting should store
+# the value in env_$var in board_info.
+
+proc remote_setenv { dest var value } {
+ return [call_remote "" setenv $dest $var $value]
+}
+
+proc standard_setenv { dest var value } {
+ if { ![isremote $dest] } {
+ global env
+ set env($var) $value
+ return 0
+ } else {
+ return 1
+ }
+}
+
+# Clear an environment variable (if local), or restore to its initial
+# value (if any) (if not local).
+
+proc remote_unsetenv { dest var } {
+ return [call_remote "" unsetenv $dest $var]
+}
+
+proc standard_unsetenv { dest var } {
+ if { ![isremote $dest] } {
+ global env
+ unset env($var)
+ } else {
+ global board_info
+ unset board_info($dest,env_$var)
+ }
+}
+
+# Return the current state of an environment variable (list of 0 and
+# "" or 1 and value), or restore it from such a state.
+
+proc remote_saveenv { dest var } {
+ return [call_remote "" saveenv $dest $var]
+}
+
+proc standard_saveenv { dest var } {
+ if { ![isremote $dest] } {
+ global env
+ if { [info exists env($var)] } {
+ return [list 1 $env($var)]
+ } else {
+ return [list 0 ""]
+ }
+ } else {
+ global board_info
+ if { [info exists board_info($dest,env_$var)] } {
+ return [list 1 $board_info($dest,env_$var)]
+ } else {
+ return [list 0 ""]
+ }
+ }
+}
+
+proc remote_restoreenv { dest var saved } {
+ set was_set [lindex $saved 0]
+ set value [lindex $saved 1]
+ if { $was_set == 1 } {
+ return [remote_setenv $dest $var $value]
+ } else {
+ return [remote_unsetenv $dest $var]
+ }
+}
+
+# Push the current state of an environment variable in saved_env_$var
+# in board_info and set a new value, or restore a previously saved
+# value; remote_pushenv returns the same value as remote_setenv. If
+# setting fails, a value is still stored on the stack; this is so that
+# callers using this function on a best-efforts basis, that wish to
+# continue execution even if setting environment variables is not
+# supported by this board, can call remote_popenv later without
+# needing to record whether remote_pushenv succeeded or failed.
+
+proc remote_pushenv { dest var value } {
+ set saved [remote_saveenv $dest $var]
+ set res [remote_setenv $dest $var $value]
+ if {[board_info $dest exists name]} {
+ set dest [board_info $dest name]
+ }
+ global board_info
+ if { ![info exists board_info($dest,saved_env_$var)] } {
+ set board_info($dest,saved_env_$var) ""
+ }
+ set board_info($dest,saved_env_$var) [list $saved
$board_info($dest,saved_env_$var)]
+ return $res
+}
+
+proc remote_popenv { dest var } {
+ if {[board_info $dest exists name]} {
+ set dest [board_info $dest name]
+ }
+ global board_info
+ set old_stack $board_info($dest,saved_env_$var)
+ set saved [lindex $old_stack 0]
+ set board_info($dest,saved_env_$var) [lindex $old_stack 1]
+ return [remote_restoreenv $dest $var $saved]
+}
+
set sum_program "testcsum"
diff --git a/lib/ssh.exp b/lib/ssh.exp
index 4514707..bb4150a 100644
--- a/lib/ssh.exp
+++ b/lib/ssh.exp
@@ -115,6 +115,12 @@ proc ssh_upload {desthost srcfile destfile} {
}
}
+proc ssh_setenv { dest var value } {
+ global board_info
+ set board_info($dest,env_$var) $value
+ return 0
+}
+
# Execute CMD on BOARDNAME.
#
proc ssh_exec { boardname program pargs inp outp } {
@@ -168,7 +174,14 @@ proc ssh_exec { boardname program pargs inp outp } {
set inp "/dev/null"
}
- set ret [local_exec "$SSH $ssh_useropts $ssh_user$hostname sh -c '$program
$pargs 2>&1 ; echo XYZ\\\${?}ZYX'" $inp $outp $timeout]
+ global board_info
+ set target_env ""
+ foreach {key val} [array get board_info $boardname,env_*] {
+ set var [string replace $key 0 [expr [string length $boardname,env_] -
1]]
+ append target_env "export $var=\"$val\"; "
+ }
+
+ set ret [local_exec "$SSH $ssh_useropts $ssh_user$hostname sh -c
'$target_env$program $pargs 2>&1 ; echo XYZ\\\${?}ZYX'" $inp $outp $timeout]
set status [lindex $ret 0]
set output [lindex $ret 1]