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.
> 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.
If it's desired for everything around board_info use to be in remote.exp
so a board file doesn't need to know the conventions for setting /
unsetting a variable in the stored state, or for getting the set of
current variables and their values, it could be implemented that way.
> 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).
The form of backwards compatibility I'm concerned with is that GCC can use
target environment variable setting without introducing a dependency on a
new DejaGnu version, via just having a backport of the relevant functions
that's used if they're not defined by DejaGnu, so native testing and cross
testing without target environment variable support continue working as
they always have, both with new and old DejaGnu - but with the actual
testsuite code manipulating environment variables being able to use the
new interfaces unconditionally rather than needing lots of conditionals
spread across the testsuite.
> > 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.
> 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. It
would be possible to have a single remote_env if preferred *provided*
there is a separate small procedure called via call_remote that declares
whether environment setting is supported (in this version, boards should
only need to define ${board}_setenv, and then use the environment
information in ${board}_exec).
> These are either related and remote-protocol-specific or target-specific, or
> the entire set could be condensed into a shared implementation with a get-all
> operation for remote drivers to use.
>
> 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). And some are intended for the build
system (typically variables controlling how the testsuite itself behaves;
no DejaGnu changes are needed for those, since working directly with the
global environment is OK there).
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. (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.)
> 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.)
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, 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.
> 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.
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).
> 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".
--
Joseph S. Myers
[email protected]