ww: select sources by Go platform suffixes

This commit is contained in:
2026-08-14 21:25:16 +09:00
parent c59a7c11de
commit f138844737
3 changed files with 391 additions and 47 deletions

View File

@@ -372,6 +372,79 @@ strs_cmp(const void *a, const void *b)
return strcmp(sa, sb);
}
static int
sep_name_is(const char *s, size_t n, const char *word)
{
return strlen(word) == n && memcmp(s, word, n) == 0;
}
static int
sep_known_os(const char *s, size_t n)
{
static const char *known[] = {
"aix", "android", "darwin", "dragonfly", "freebsd", "hurd",
"illumos", "ios", "js", "linux", "nacl", "netbsd", "openbsd",
"plan9", "solaris", "wasip1", "windows", "zos",
};
for (size_t i = 0; i < sizeof known / sizeof known[0]; i++)
if (sep_name_is(s, n, known[i])) return 1;
return 0;
}
static int
sep_known_arch(const char *s, size_t n)
{
static const char *known[] = {
"386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be",
"loong64", "mips", "mipsle", "mips64", "mips64le", "mips64p32",
"mips64p32le", "ppc", "ppc64", "ppc64le", "riscv", "riscv64",
"s390", "s390x", "sparc", "sparc64", "wasm",
};
for (size_t i = 0; i < sizeof known / sizeof known[0]; i++)
if (sep_name_is(s, n, known[i])) return 1;
return 0;
}
static int
sep_target_tag(const char *s, size_t n)
{
return sep_name_is(s, n, "linux") || sep_name_is(s, n, "amd64");
}
/* Go 1.26.5 build.go:1980-2027 filters known platform suffixes before
* opening a source. WW currently has one honest target, linux/amd64. */
static int
sep_source_matches_target(const char *name)
{
size_t stem = strcspn(name, ".");
if (memchr(name, '_', stem) == NULL) return 1;
size_t end = stem;
size_t last = end;
while (last > 0 && name[last - 1] != '_') last--;
if (sep_name_is(name + last, end - last, "test")) {
if (last == 0) return 1;
end = last - 1;
last = end;
while (last > 0 && name[last - 1] != '_') last--;
}
if (last == 0) return 1;
const char *final = name + last;
size_t nfinal = end - last;
size_t prevend = last - 1;
size_t prev = prevend;
while (prev > 0 && name[prev - 1] != '_') prev--;
if (prev < prevend
&& sep_known_os(name + prev, prevend - prev)
&& sep_known_arch(final, nfinal))
return sep_target_tag(final, nfinal)
&& sep_target_tag(name + prev, prevend - prev);
if (sep_known_os(final, nfinal) || sep_known_arch(final, nfinal))
return sep_target_tag(final, nfinal);
return 1;
}
static int sep_slurp(const char*, char**, u64*);
/* Go's contract: only *_test.ww is a test source. Ask the compiler parser,
@@ -564,15 +637,39 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
{
DIR *d = opendir(dirpath);
if (d == NULL) { *out_files = NULL; return -1; }
char **names = NULL;
int nnames = 0, capnames = 0;
char **prod = NULL, **tests = NULL;
int nprod = 0, capprod = 0, ntests = 0, captests = 0;
struct dirent *ent;
while ((ent = readdir(d)) != NULL) {
struct dirent *ent = NULL;
for (;;) {
errno = 0;
ent = readdir(d);
if (ent == NULL) break;
const char *nm = ent->d_name;
size_t nl = strlen(nm);
if (nl <= 3) continue;
if (nm[0] == '.' || nm[0] == '_') continue;
if (strcmp(nm + nl - 3, ".ww") != 0) continue;
if (source_list_add(&names, &nnames, &capnames, nm) < 0) {
source_list_free(names, nnames);
closedir(d);
*out_files = NULL;
return -2;
}
}
int direrr = errno;
closedir(d);
if (direrr != 0) {
source_list_free(names, nnames);
*out_files = NULL;
return -1;
}
if (nnames > 1) qsort(names, (size_t)nnames, sizeof *names, strs_cmp);
for (int ni = 0; ni < nnames; ni++) {
const char *nm = names[ni];
size_t nl = strlen(nm);
if (!sep_source_matches_target(nm)) continue;
int is_test = nl >= 8 && strcmp(nm + nl - 8, "_test.ww") == 0;
if (variant == SEP_VARIANT_PRODUCTION && is_test) continue;
if (variant == SEP_VARIANT_EXTERNAL && !is_test) continue;
@@ -580,9 +677,9 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
int pn = snprintf(path, sizeof path, "%s/%s", dirpath, nm);
if (pn < 0 || (size_t)pn >= sizeof path) {
fprintf(stderr, "ww: package source path is too long\n");
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
@@ -590,9 +687,9 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
if (lstat(path, &st) != 0) {
fprintf(stderr,
"ww: %s: package source is not a regular file\n", path);
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
@@ -601,9 +698,9 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
fprintf(stderr,
"ww: %s: package source is not a regular file\n",
path);
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
@@ -613,17 +710,17 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
if (!S_ISREG(st.st_mode)) {
fprintf(stderr,
"ww: %s: package source is not a regular file\n", path);
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
int has_test = !is_test ? source_has_test_decl(path) : 0;
if (has_test < 0) {
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
@@ -631,18 +728,18 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
fprintf(stderr,
"ww: %s: @test declaration outside *_test.ww\n",
path);
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
if (is_test) {
char *package = NULL;
if (source_package_name(path, &package) < 0) {
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
@@ -656,14 +753,14 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
int *n = is_test ? &ntests : &nprod;
int *cap = is_test ? &captests : &capprod;
if (source_list_add(list, n, cap, path) < 0) {
source_list_free(names, nnames);
source_list_free(prod, nprod);
source_list_free(tests, ntests);
closedir(d);
*out_files = NULL;
return -2;
}
}
closedir(d);
source_list_free(names, nnames);
if (nprod > 1) qsort(prod, (size_t)nprod, sizeof *prod, strs_cmp);
if (ntests > 1) qsort(tests, (size_t)ntests, sizeof *tests, strs_cmp);
if (nprod > INT_MAX - ntests) {
@@ -4161,7 +4258,7 @@ static void
workdir_stamp_text(char *buf, size_t bufsz, int is_test, int emit_asm)
{
snprintf(buf, bufsz, "ww workdir fmt %d mode %s asm %d\n",
is_test ? 16 : 17, is_test ? "test" : "build", emit_asm);
is_test ? 17 : 18, is_test ? "test" : "build", emit_asm);
}
static int