ww: put selected toolchain first in test PATH

This commit is contained in:
2026-08-21 05:30:10 +09:00
parent 1b71250ad5
commit 9b6b1100f4
7 changed files with 586 additions and 96 deletions

View File

@@ -16,6 +16,7 @@
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <stdint.h>
#include <stdarg.h>
#ifndef PATH_MAX
@@ -82,6 +83,71 @@ run_argv(const char *prog, char *const argv[])
return 1;
}
extern char **environ;
struct test_environment {
char **values;
char *path;
};
/* Pinned cmd/go appends PATH=$GOROOT/bin:$PATH to each test command and
* os/exec keeps the appended duplicate. The selected WW driver's sibling
* directory is the local toolchain-bin analogue. Build tools retain the
* caller's environment; only the test binary receives this array. */
static int
make_test_environment(const char *toolbin, struct test_environment *out)
{
const char *oldpath = getenv("PATH");
if (oldpath == NULL) oldpath = "";
size_t dirn = strlen(toolbin), oldn = strlen(oldpath);
if (oldn > SIZE_MAX - 7 || dirn > SIZE_MAX - oldn - 7) return -1;
size_t pathn = 5 + dirn + (oldn != 0 ? 1 + oldn : 0);
char *path = malloc(pathn + 1);
if (path == NULL) return -1;
memcpy(path, "PATH=", 5);
memcpy(path + 5, toolbin, dirn);
size_t at = 5 + dirn;
if (oldn != 0) {
path[at++] = ':';
memcpy(path + at, oldpath, oldn);
at += oldn;
}
path[at] = '\0';
size_t nenv = 0;
while (environ[nenv] != NULL) {
if (nenv == SIZE_MAX - 2) { free(path); return -1; }
nenv++;
}
if (nenv > SIZE_MAX / sizeof(char *) - 2) {
free(path);
return -1;
}
char **values = calloc(nenv + 2, sizeof *values);
if (values == NULL) { free(path); return -1; }
size_t n = 0;
int inserted = 0;
for (size_t i = 0; i < nenv; i++) {
if (strncmp(environ[i], "PATH=", 5) == 0) {
if (!inserted) { values[n++] = path; inserted = 1; }
} else {
values[n++] = environ[i];
}
}
if (!inserted) values[n++] = path;
values[n] = NULL;
out->values = values;
out->path = path;
return 0;
}
static void
free_test_environment(struct test_environment *env)
{
free(env->values);
free(env->path);
}
/* run_test_bin — exec the built test binary with an optional name-filter
* pattern as argv[1] (lib/test run() reads it via os.args). fork+execv
* (not system()) so glob metacharacters in the pattern reach the binary
@@ -91,14 +157,28 @@ run_argv(const char *prog, char *const argv[])
static int
run_test_bin(const char *bin, const char *pattern)
{
char toolbin[PATH_MAX];
if (realpath(self_dir, toolbin) == NULL) {
fputs("ww: cannot prepare test environment\n", stderr);
return -1;
}
struct test_environment env = {0};
if (make_test_environment(toolbin, &env) != 0) {
fputs("ww: cannot prepare test environment\n", stderr);
return -1;
}
pid_t pid = fork();
if (pid < 0) { perror("ww: fork"); return -1; }
if (pid < 0) {
perror("ww: fork");
free_test_environment(&env);
return -1;
}
if (pid == 0) {
char *xargv[3];
xargv[0] = (char *)bin;
if (pattern) { xargv[1] = (char *)pattern; xargv[2] = NULL; }
else { xargv[1] = NULL; }
execv(bin, xargv);
execve(bin, xargv, env.values);
perror("ww: exec");
_exit(127);
}
@@ -108,6 +188,7 @@ run_test_bin(const char *bin, const char *pattern)
* test PASS. */
pid_t got;
do { got = waitpid(pid, &status, 0); } while (got < 0 && errno == EINTR);
free_test_environment(&env);
if (got < 0) { perror("ww: waitpid"); return -1; }
if (WIFEXITED(status)) return WEXITSTATUS(status);
return 1;