On 10/9/26 11:42, Joseph Myers wrote:
On Thu, 8 Oct 2026, Jacob Bachmeyer wrote:
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?
There are about 70 remote_exec calls in the GCC testsuites (mostly for
host, some for build or target), and one remote_load, and about 20
${tool}_load. And the main way tests are run is via dg-test which is
provided by DejaGnu (and which uses ${tool}_load, which uses remote_load,
which uses call_remote, which uses standard_load if the board doesn't
provide its own *_load, which uses remote_exec).
No problem there; the environment override list parameter need only also
be added to remote_load, which needs to be documented first. ("So
*that* is what it does...") I will be writing documentation for it soon.
The dg-test procedure in dg.exp uses ${tool}_load (provided by the
testsuite) to actually run a compiled target executable. You therefore
already have the opportunity to pick up environment overrides from
testsuite-specific locations and pass them to remote_load.
Reliably handling some environment settings for all host code or all
target code means that requiring things to be passed explicitly on every
call to those functions does not seem a very robust design; enough of the
uses are effectively global state that it makes sense to treat them as
such, and then possibly allow a further level of overrides on the
remote_exec (or remote_load, or ${tool}_load) calls only for those call
sites where a very local override is the natural model.
The ${tool}_load callback invoked by dg.exp:dg-test is given only the
name of the output executable from the test GCC run. That will not
change, but, since ${tool}_load is defined by the testsuite, it can
obtain an environment override list from wherever the testsuite keeps it.
While GCC does
rename some of those functions and replace them by wrappers for various
purposes, that also seems to be something that you're discouraging.
Testsuites can *wrap* DejaGnu procedures in the global namespace and
expect their own calls to invoke the wrapper procedures. What *will*
eventually break is redefining part of the framework and expecting other
parts of the framework to call your version. (The main reason for this
is to allow testsuites to define their own procedures without fear of
"stepping on" the framework.)
This previously came up with GDB redefining default_target_compile and
expecting target_compile to run the redefined version. That currently
works, but it will eventually stop working (and default_target_compile
is documented as internal anyway).
A similar monkey-patch on remote_exec will eventually break when
standard_load calls the internal version.
Documented callbacks, like those used by dg.exp, obviously will continue
to be found in the global namespace in a test script's interpreter.
(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.)
Obviously code directly in DejaGnu such as dg.exp can't use GCC-specific
names like that. And I don't think the use for environment overrides at
various levels, as opposed to just where it's convenient to name the
overrides at a particular call site, is something specific to GCC.
The exact way that the GCC testsuite accumulates environment overrides
is specific to the GCC testsuite.
The dg.exp module works by invoking callbacks defined by the testsuite.
In the GCC testsuite, those callbacks can use GCC-specific variables.
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.
I think the interface needs to include "globally set / push / pop
overrides", not just "execute a program with these overrides".
DejaGnu will eventually have support for binding such values to groups
of tests at various levels, probably in a more generic form of
"save/restore these Tcl variables". This infrastructure is not yet
implemented. In the mean time, DejaGnu will not be adding global state
that risks creating "landmines" for testsuites to trip over.
In brief, your proposed API creates the opportunity for BAR.exp to
quietly depend on "left over" state from FOO.exp if the latter fails to
clean up its state. Such a situation is *certain* to break when native
parallel testing is implemented and FOO and BAR no longer execute in the
same process.
[...]
(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.
Tracking things in a separate variable (say env_info instead of
board_info) and then making remote_exec / remote_load extract the
overrides (based on whether "build", "host" or "target" is passed to
remote_*) and pass them down (together with any overrides that were
directly given to remote_load / remote_exec) doesn't particularly seem
more complicated than putting things in board_info, just different. It
could even use procedure names such as remote_pushenv as in my patch, or a
common remote_env, or something else.
The "build", "host", and "target" names are aliases, and remote_* also
accepts the name of any defined board, including (via support in
call_remote) any board for which load_board_description can locate a
description file, although overrides could be associated with those
aliases instead of specific boards.
This could also be complicated, as DejaGnu supports testing on multiple
targets in a single run. How to distinguish between environment
overrides meant for all targets and those meant only for the current
target? Further, some targets in a multi-target run may support
environment overrides while others do not.
It *does* need a way for a board to declare whether it has environment
variable support. There are tests currently skipped in the remote case
that should be skipped for a board lacking that support. But there are
also tests that just continue to run with best efforts - we don't want
executing everything on the host to fail because it doesn't know how to
set LC_ALL=C on that board, just because LC_ALL=C is used globally for
everything executed on the host, we want the tests to continue to run and
hope that in fact the board defaults to the C locale.
Are you suggesting that being unable to set LC_ALL=C on the *target*
would cause a failure because LC_ALL=C was set on a native *host*? I
thought we had already dropped the idea of using ::env as a template
precisely *because* remote nodes may need different environments.
DejaGnu itself currently always executes on "build". Both "host" and
"target" can potentially be remote, and can need (different) environment
overrides.
So having
${board}_exec reject calls with environment variables when unsupported is
not a good solution - and remote_exec needs to take care to work with
existing board files that define ${board}_exec to take exactly five
arguments.
Tcl's info(n) provides for that, and a WARNING (or maybe an ERROR?) will
be emitted when an environment override list is known to be dropped.
The fly in that ointment is a ${board}_exec defined to take "args",
which can silently ignore the additional argument, just as old versions
of DejaGnu will do in remote_exec and remote_load.
You can test if environment overrides are supported on a target by using
env(1) or, if the target lacks env(1), building a trivial program that
prints the value of an environment variable and running it.
-- Jacob