/* * 993_ww_ww — phase-10 marker for the ww-side driver port. * * Diffs the C-built `ww` against the ww-built `ww_ww`. Both drivers * orchestrate the same w6c/w6a/w6l, so the resulting binaries must be * byte-identical for every program in the corpus. The corpus mixes: * - a tiny single-file program (no -I flags) * - a multi-import build (selfhost/cmd/wwdump/main.ww), exercising * `use` resolution + the -I search path + the libwwrt.a link. * * Each build runs from a per-driver scratch directory so the * intermediate .combined.ww/.s/.o files don't collide. */ #include #include #include #include static int runwait(const char *cmd) { int rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return 1; } static const char * absbin(void) { const char *b = getenv("BIN"); if (!b) b = "out/bin"; if (b[0] == '/') return b; static char buf[2048]; char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return NULL; snprintf(buf, sizeof buf, "%s/%s", cwd, b); return buf; } static int slurp_eq(const char *a, const char *b) { FILE *fa = fopen(a, "rb"); FILE *fb = fopen(b, "rb"); if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } int rc = 0; for (;;) { int ca = fgetc(fa); int cb = fgetc(fb); if (ca != cb) { rc = -1; break; } if (ca == EOF) break; } fclose(fa); fclose(fb); return rc; } /* Build `src` via the named driver, expecting output binary `out` in * the build directory. `incs` may be a colon-separated list of include * dirs (the ww driver accepts -I path1:path2:path3). Returns 0 on * success. */ static int build_via(const char *bin, const char *driver, const char *src, const char *workdir, const char *incs) { char cmd[4096]; if (incs && incs[0]) { snprintf(cmd, sizeof cmd, "cd %s && timeout 180 %s/%s build -I %s %s 2>/dev/null", workdir, bin, driver, incs, src); } else { snprintf(cmd, sizeof cmd, "cd %s && timeout 180 %s/%s build %s 2>/dev/null", workdir, bin, driver, src); } return runwait(cmd); } static int diff_one(const char *bin, const char *cwd, const char *label, const char *src, const char *out_basename, const char *incs) { char dc[64], dw[64]; snprintf(dc, sizeof dc, "/tmp/ww_d_%d_c", getpid()); snprintf(dw, sizeof dw, "/tmp/ww_d_%d_w", getpid()); char cmd[256]; snprintf(cmd, sizeof cmd, "rm -rf %s %s && mkdir -p %s %s", dc, dw, dc, dw); if (runwait(cmd) != 0) return -1; if (build_via(bin, "ww", src, dc, incs) != 0) { fprintf(stderr, "ww_ww FAIL: C ww errored on %s\n", label); return -1; } if (build_via(bin, "ww_ww", src, dw, incs) != 0) { fprintf(stderr, "ww_ww FAIL: ww ww errored on %s\n", label); return -1; } char co[1024], wo[1024]; snprintf(co, sizeof co, "%s/%s", dc, out_basename); snprintf(wo, sizeof wo, "%s/%s", dw, out_basename); int rc = 0; if (slurp_eq(co, wo) != 0) { fprintf(stderr, "ww_ww FAIL: %s — driver outputs differ\n", label); rc = -1; } snprintf(cmd, sizeof cmd, "rm -rf %s %s", dc, dw); runwait(cmd); (void)cwd; return rc; } int main(void) { const char *bin = absbin(); if (!bin) return 1; char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; /* Stage a tiny program in a place both drivers can reach. * pid-keyed so concurrent runs of this test (or shards of it) don't * race on the staging file. */ char hello_src[64], hello_out[64]; snprintf(hello_src, sizeof hello_src, "/tmp/ww_d_hello_%d.ww", getpid()); snprintf(hello_out, sizeof hello_out, "ww_d_hello_%d", getpid()); { FILE *f = fopen(hello_src, "w"); if (!f) return 1; fputs("import os;\n\n" "export fn main() i32 = {\n" "\tos.write(1, \"hi\\n\".ptr, 3u64);\n" "\treturn 0;\n" "};\n", f); fclose(f); } struct { const char *label; const char *src; /* may be relative to cwd */ const char *out; /* basename of expected output */ const char *incs; /* colon-separated -I list, may be NULL */ } cases[] = { { "hello", NULL, NULL, "" }, /* filled in below */ { "wwdump", NULL, "main", NULL }, /* filled in below */ { NULL, NULL, NULL, NULL }, }; cases[0].src = hello_src; cases[0].out = hello_out; /* wwdump case: absolute paths so the driver finds the imports * regardless of the per-driver workdir. */ static char wwdump_src[2048], wwdump_incs[4096]; snprintf(wwdump_src, sizeof wwdump_src, "%s/selfhost/cmd/wwdump/main.ww", cwd); snprintf(wwdump_incs, sizeof wwdump_incs, "%s/lib/ww:%s/lib/ww/lex:%s/lib/ww/parse:%s/lib/encoding/utf8:%s/selfhost/cmd/wcc", cwd, cwd, cwd, cwd, cwd); cases[1].src = wwdump_src; cases[1].incs = wwdump_incs; int fail = 0; int n = 0; for (int i = 0; cases[i].label; i++) { if (diff_one(bin, cwd, cases[i].label, cases[i].src, cases[i].out, cases[i].incs) != 0) fail++; n++; } unlink(hello_src); if (fail) { fprintf(stderr, "ww_ww: %d/%d diff(s) failed\n", fail, n); return 1; } printf("ww_ww: byte-identical to C ww on %d corpus builds " "(single-file + selfhost/wwdump multi-import)\n", n); return 0; }