On 10/8/26 12:13, Joseph Myers wrote:
On Wed, 7 Oct 2026, Jacob Bachmeyer wrote:

This feature has actually been on the TODO list for some time and is planned
Unfortunately it's not mentioned in the TODO file.

Correct; I should have said "my TODO list" there.

A sufficiently simple API can be carried into the future easily, (and perhaps
even be slipped into 1.6.4) but I am very reluctant to establish more
conventions on the board_info array, which appears to be intended to be an
internal variable in the framework, since we have accessor procedures for it.
I think having some way to store environment settings associated with a
board is unavoidable for this feature.  board_info seems natural since it
already stores various state associated with a board.  It's necessary to
store the current environment state for each variable (including being
able to access the full list of environment variables to use when running
a test) and the stack of pushed previous state for each variable.

[...]
Some way to store the environment overrides is necessary, but I am unconvinced that the framework should be managing them.  In fact, as mentioned below, board_info is probably not an appropriate place for them after all.
For an immediate workaround, do the affected targets have the env(1) command?
Using env(1) would have the advantage of backwards compatibility with current
and previous releases of DejaGnu.
env is available for the case of ssh to a target, but it wouldn't help for
the case of QEMU userspace emulation where you need to pass -E options
(or -U to unset) to the emulator (you can't run the build-system env
binary under QEMU because it's for the wrong CPU architecture; and calling
QEMU under env wouldn't work well either if dealing with variables such as
LD_LIBRARY_PATH that point to libraries for the target architecture, not
the architecture for which QEMU is built).

A qemu_exec procedure would translate environment overrides to -E and -U options.  You could also use the host's env(1) and the QEMU_SET_ENV and QEMU_UNSET_ENV environment variables when running QEMU.

[...]
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.
What prevents simply adding an env-override-list optional argument to
remote_exec?  If the backend sets environment variables only for each test
rather than manipulating global state on the target, why should the framework
treat that state as global inside DejaGnu?
It's not only for each test (whatever unit is being counted as "a test").
Environment variables are set in several different contexts.  Some are
global for the whole runtest run (and don't really need the stack
discipline); for example, LANG and LC_ALL.  Some apply for a whole .exp
file (for example, ubsan_init saving UBSAN_OPTIONS and setting the value
required for all the ubsan tests, and then ubsan_finish called at the end
of the .exp file restoring it).  Some are set only for the test of an
individual .c / .cc etc. file (the normal approach in the GCC testsuite is
a per-directory .exp file that runs all the .c / .cc etc. files in that
directory using GCC's extensions to the dg.exp framework), using a
directive in that file such as

/* { dg-set-target-env-var ASAN_OPTIONS "color=never 
detect_stack_use_after_return=1" } */

All of these places are at some distance in API terms from remote_exec
(via ${tool}_load, remote_load and standard_load).

Given that the environment is set for various parts of the testsuite (all
a long way above the remote_exec calls), I think it's natural to consider
it as state that gets manipulated and restored.

Testsuites are free to define their own Tcl variables and to use namespaces outside of ::dejagnu:: and ::DejaGnu:: (which are reserved for the framework).  What prevents the GCC testsuite from tracking its own environment overrides and building the final list at each remote_exec call?

(The global namespace has a lot of stuff in it.  New features like this should use namespaces to reduce future maintenance burdens around avoiding name collisions; I suggest ::gcc_test::env:: to start the proverbial wheels turning if needed.)

Putting the interface boundary at remote_exec would preserve a proper mechanism-vs-policy split:  DejaGnu would immediately provide only the mechanism to apply environment overrides, leaving managing what overrides are needed to testsuites.

Since that mechanism is needed regardless of higher-level features built around it, exposing it is a trivial burden on future maintenance.

Why a group of related procedures and not a single remote_env command with
get/set/unset/push/pop subcommands?
The goal here is to avoid a target needing to override the whole of
remote_env just to declare that it supports environment manipulation.  [...]

Calling this "environment manipulation" is a misnomer at this point---we are actually discussing tracking a set of environment overrides that are applied when programs are run using remote_exec.

[...]

Why a remote_env command at all?  Why not simply propagate local environment
changes to a remote target?  (This could be done by setting traces on ::env or
simply snapshotting the environment when runtest starts and comparing.)
Some environment variable settings in the GCC testsuite are intended for
the target (target libraries and test programs built by GCC).  Some are
intended for the host (environment variables used by the compilers and
other tools running on the host).  [...]

Mixing them up into a single environment is not a good idea, especially
when PATH-like settings are involved (PATH or LD_LIBRARY_PATH on the build
system or host should not be set to point to libraries or executables for
the target, which may have a different architecture as well as a different
root filesystem with different paths).  The environment for build, host
and target are genuinely different and so it's natural to associate the
environment with the board interface.

This is getting somewhere:  the framework would need to track distinct environment variables for (at minimum) build, host, and target *roles*, with additional issues that each *target* is likely to need its own environment settings and that the same box ("board") can potentially be used in all three roles. This is too complex to appear in the 1.6.4 release.

   (The testsuite itself still needs
to manage temporary saves and restores in cases, typically native
compilers, where host and target are the same system and the environment
variables needed for target executables interfere with those for running
the compilers.  This does occur for some GCC tests.)

This last detail tells me that putting this in board_info is actually wrong, because the same board may need different environment overrides for different roles.

Further, as I read this, it seems that the intention is for testsuites to
specify short-lived target environment variable overrides. If we are adding
new API to a future DejaGnu release, the (also relatively new) "testcase
group" infrastructure is designed to frame this kind of dynamic variable;
there will eventually be infrastructure in the framework to run each test
script in its own group, for example.
As noted above, environment variable settings are relevant globally, and
at the .exp level, and at the level of an individual .c file within a .exp
file.  (They are *also* relevant at an even narrower level, repeatedly
loading the same test executable with different environment variable
settings, though that may only appear in one place in the testsuite.)

This looks exactly like the nested dynamic extents that the "testcase group" mechanism is intended to track.  When the core framework starts putting test scripts in groups, dg.exp will do likewise for its test cases.

The 1.6.3 release actually has "testcase group", although all it does in that release is check that "testcase group begin" and "testcase group end" calls properly match.

Maybe bulk save/restore are *also* of use, but I think basic remote
environment operations like here are a natural building block for any
larger manipulation,

I would say that an optional argument to remote_exec with a list of environment overrides is a natural building block for any larger manipulation, including remote_setenv, since any future global state could simply become the default for that list.

Fundamentally, remote_exec needs the ability to handle environment overrides; the question is how they are passed *to* remote_exec.  Adding this fundamental step could be reasonable for 1.6.4.

  and more suitable for a testsuite to be able to
include backports to keep working until the minimum required DejaGnu
version is updated a long time in the future.

This type of backport is getting very close to monkey-patching the framework and this rationale highlights exactly one of the types of maintenance problems that supporting monkey-patching causes.  Either this is a feature request or you already have a viable but inelegant solution to the problem.

Monkey-patching the framework is not supported. That means that API shapes in DejaGnu will *not* be constrained by ease of monkey-patching new APIs into older framework releases. That way lies madness.

If I gather correctly, GCC currently skips some tests on remote targets due to an inability to pass environment overrides. The minimum DejaGnu version need not be a single value; GCC can simply continue to skip those tests unless a framework version that supports remote environment overrides is used.

You already have the test for "remote target" at each place it is needed; simply update that to a test whether remote_exec ignores or honors an environment override given as its seventh argument. (A predicate could use regexp(n) and [remote_exec unix env "" "" "" "" {"GCC_PROBE_ENV=test"}] or similar and memoize its result.)

A getenv interface solves not only PATH but also all other cases where
replacing a value is inappropriate by enabling testcase code to simply examine
the effects of previous code before making its own changes.
I suspect getenv might be fragile on the board file level when dealing
with e.g. preserving whitespace when getting an existing environment
variable value.
Then we need to drop the idea that we are manipulating environment variables and recognize that we are actually talking about environment overrides for processes spawned on the target.

It should also be reasonable to add environment support with sufficient
operations for common cases that are currently broken for remote testing
in the GCC testsuite, and then potentially add more operations to the
interface later (hopefully with a way for a testsuite to check which
operations are supported and backport support for missing operations).

Again, that type of feature backporting will not be supported. You do it at your own risk:  if it blows up, that is a bug in your testsuite, *NOT* in DejaGnu.

As of 1.6.3, DejaGnu has a "testsuite can call" command that reports availability of subcommands on multiplex points like testsuite and testcase.  The availability of a Tcl procedure can be checked with the Tcl info(n) builtin.

A major part of DejaGnu's purpose is to "paper over" irrelevant differences
between targets.  Having unsetenv do significantly different things with local
and remote targets is a serious deficiency that I do not want lurking in the
framework for users to trip over.
It would be possible to have a fully functional unsetenv even without
getenv, it just means save/restore are a bit more complicated in the
remote case and the per-board per-variable state would need to represent
"explicitly unset" in addition to "explicit value" and "not manipulated by
this testsuite, whatever value if any is present by default on the board".

Is an empty environment variable name valid anywhere?  Could "=NAME" instead of "NAME=VALUE" be usable as a "unset this variable" flag?

If so, those three states map simply:

    "NAME=VALUE"   -- explicit value
    "=NAME"        -- explicitly unset
    not in list    -- not manipulated


-- Jacob

Reply via email to