build: pass direct exports to package compilers
This commit is contained in:
4
Makefile
4
Makefile
@@ -365,8 +365,8 @@ BYTEID_WW_TARGETS = $(BYTEID_WW_TESTS:%=wwtest/%)
|
|||||||
# Ww-native sep-driver/tool observers: single-file ww tests under
|
# Ww-native sep-driver/tool observers: single-file ww tests under
|
||||||
# test/sep/ on the test/testenv helper package, porting the residual
|
# test/sep/ on the test/testenv helper package, porting the residual
|
||||||
# 989_sep* driver-observer C carriers. These are compiler/driver
|
# 989_sep* driver-observer C carriers. These are compiler/driver
|
||||||
# gates (module trees, sepwork artifact layout, composed //ww:module
|
# gates (module trees, sepwork artifact layout, owner-only units and direct
|
||||||
# units, link rejects), NOT byteid suites: they run under
|
# export arguments, link rejects), NOT byteid suites: they run under
|
||||||
# test-compiler beside the surviving residual carriers.
|
# test-compiler beside the surviving residual carriers.
|
||||||
SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww \
|
SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww \
|
||||||
test/sep/seplink_test.ww test/sep/sepscratch_test.ww \
|
test/sep/seplink_test.ww test/sep/sepscratch_test.ww \
|
||||||
|
|||||||
110
cmd/w6c/main.c
110
cmd/w6c/main.c
@@ -22,6 +22,41 @@ slurp(const char *path, char **outbuf, u64 *outlen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct importin {
|
||||||
|
const char *path;
|
||||||
|
const char *file;
|
||||||
|
char *buf;
|
||||||
|
u64 len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
parseinput(Arena *a, const char *file, char *buf, u64 len,
|
||||||
|
const char *mod, const char *testsupport, int *bad)
|
||||||
|
{
|
||||||
|
Lex l;
|
||||||
|
Parser p;
|
||||||
|
lexinit(&l, a, file, buf, len);
|
||||||
|
parserinit(&p, a, &l);
|
||||||
|
p.testmodule = testsupport;
|
||||||
|
if (mod != NULL) {
|
||||||
|
p.pathmod = mod;
|
||||||
|
p.curmod = mod;
|
||||||
|
}
|
||||||
|
Node *f = parsefile(&p);
|
||||||
|
*bad = l.errs || p.errs;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
appendnodes(Node **head, Node **tail, Node *list)
|
||||||
|
{
|
||||||
|
if (list == NULL) return;
|
||||||
|
if (*head == NULL) *head = list;
|
||||||
|
else (*tail)->next = list;
|
||||||
|
while (list->next != NULL) list = list->next;
|
||||||
|
*tail = list;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -31,8 +66,14 @@ main(int argc, char **argv)
|
|||||||
const char *testsupport = NULL;
|
const char *testsupport = NULL;
|
||||||
int testmode = 0;
|
int testmode = 0;
|
||||||
int sepmode = 0; /* -c: #22 M3 separate-compile / primary-
|
int sepmode = 0; /* -c: #22 M3 separate-compile / primary-
|
||||||
* only codegen (emit imported==0 decls
|
* only codegen (emit imported==0 decls
|
||||||
* only; treat `.wwi` deps as external) */
|
* only; treat `.wwi` deps as external) */
|
||||||
|
struct importin *imports = calloc((size_t)argc, sizeof *imports);
|
||||||
|
if (imports == NULL) {
|
||||||
|
fputs("w6c: out of memory\n", stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int nimports = 0;
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
const char *a = argv[i];
|
const char *a = argv[i];
|
||||||
if (strcmp(a, "-o") == 0 && i + 1 < argc) {
|
if (strcmp(a, "-o") == 0 && i + 1 < argc) {
|
||||||
@@ -49,6 +90,14 @@ main(int argc, char **argv)
|
|||||||
testsupport = argv[++i];
|
testsupport = argv[++i];
|
||||||
} else if (strcmp(a, "-c") == 0) {
|
} else if (strcmp(a, "-c") == 0) {
|
||||||
sepmode = 1;
|
sepmode = 1;
|
||||||
|
} else if (strcmp(a, "--import") == 0) {
|
||||||
|
if (i + 2 >= argc) {
|
||||||
|
fputs("w6c: --import requires path and file\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
imports[nimports].path = argv[++i];
|
||||||
|
imports[nimports].file = argv[++i];
|
||||||
|
nimports++;
|
||||||
} else if (a[0] == '-') {
|
} else if (a[0] == '-') {
|
||||||
fprintf(stderr, "w6c: unknown flag %s\n", a);
|
fprintf(stderr, "w6c: unknown flag %s\n", a);
|
||||||
return 2;
|
return 2;
|
||||||
@@ -60,9 +109,24 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (src == NULL) {
|
if (src == NULL) {
|
||||||
fputs("usage: w6c [-T] [-c] [-I out.wwi] [-o out.s] file.ww\n", stderr);
|
fputs("usage: w6c [-T] [-c] [-I out.wwi] "
|
||||||
|
"[--import path dep.wwi]... [-o out.s] file.ww\n", stderr);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
if (nimports > 0 && !sepmode) {
|
||||||
|
fputs("w6c: --import requires -c\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nimports; i++) {
|
||||||
|
if (imports[i].path[0] == '\0') {
|
||||||
|
fputs("w6c: --import path is empty\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (i > 0 && strcmp(imports[i-1].path, imports[i].path) >= 0) {
|
||||||
|
fputs("w6c: --import paths must be sorted and unique\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (testsupport != NULL && (!sepmode
|
if (testsupport != NULL && (!sepmode
|
||||||
|| (strcmp(testsupport, "test") != 0
|
|| (strcmp(testsupport, "test") != 0
|
||||||
&& strcmp(testsupport, "__wwtest") != 0))) {
|
&& strcmp(testsupport, "__wwtest") != 0))) {
|
||||||
@@ -70,24 +134,38 @@ main(int argc, char **argv)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Arena *a = newarena();
|
||||||
|
Checker c;
|
||||||
|
Cg cg;
|
||||||
|
|
||||||
|
Node *head = NULL, *tail = NULL;
|
||||||
|
for (int i = 0; i < nimports; i++) {
|
||||||
|
if (slurp(imports[i].file, &imports[i].buf,
|
||||||
|
&imports[i].len) < 0) {
|
||||||
|
fprintf(stderr, "w6c: import %s: cannot read %s\n",
|
||||||
|
imports[i].path, imports[i].file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int bad = 0;
|
||||||
|
Node *f = parseinput(a, imports[i].file, imports[i].buf,
|
||||||
|
imports[i].len, imports[i].path, testsupport, &bad);
|
||||||
|
if (bad) return 1;
|
||||||
|
appendnodes(&head, &tail, f->list);
|
||||||
|
}
|
||||||
|
|
||||||
char *buf;
|
char *buf;
|
||||||
u64 len;
|
u64 len;
|
||||||
if (slurp(src, &buf, &len) < 0) {
|
if (slurp(src, &buf, &len) < 0) {
|
||||||
fprintf(stderr, "w6c: %s: cannot read\n", src);
|
fprintf(stderr, "w6c: %s: cannot read\n", src);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
int bad = 0;
|
||||||
Arena *a = newarena();
|
Node *file = parseinput(a, src, buf, len, NULL, testsupport, &bad);
|
||||||
Lex l;
|
if (bad) return 1;
|
||||||
Parser p;
|
if (head != NULL) {
|
||||||
Checker c;
|
tail->next = file->list;
|
||||||
Cg cg;
|
file->list = head;
|
||||||
|
}
|
||||||
lexinit(&l, a, src, buf, len);
|
|
||||||
parserinit(&p, a, &l);
|
|
||||||
p.testmodule = testsupport;
|
|
||||||
Node *file = parsefile(&p);
|
|
||||||
if (l.errs || p.errs) return 1;
|
|
||||||
|
|
||||||
check_init(&c, a);
|
check_init(&c, a);
|
||||||
c.is_test = testmode;
|
c.is_test = testmode;
|
||||||
@@ -128,6 +206,8 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (of != stdout) fclose(of);
|
if (of != stdout) fclose(of);
|
||||||
freearena(a);
|
freearena(a);
|
||||||
|
for (int i = 0; i < nimports; i++) free(imports[i].buf);
|
||||||
|
free(imports);
|
||||||
free(buf);
|
free(buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
* wwi.c — `.wwi` export-data producer (w6c -I): a re-parseable ww-prototype
|
* wwi.c — `.wwi` export-data producer (w6c -I): a re-parseable ww-prototype
|
||||||
* rendering of a package's EXPORTED surface. Since the sep-compile flip
|
* rendering of a package's EXPORTED surface. Since the sep-compile flip
|
||||||
* (epic #22) this is the LIVE import path — the driver runs one `w6c -c -I`
|
* (epic #22) this is the LIVE import path — the driver runs one `w6c -c -I`
|
||||||
* per package and feeds each dep's `.wwi` to its importers as import scope;
|
* per package and feeds each dep's `.wwi` to its importers through a separate
|
||||||
* the combined.ww amalgamator is gone.
|
* canonical `--import` input; the combined.ww amalgamator is gone.
|
||||||
*
|
*
|
||||||
* Specs: .ai/rob-M2-spec.md (producer) + .ai/drew-M2-checkexported.md
|
* Specs: .ai/rob-M2-spec.md (producer) + .ai/drew-M2-checkexported.md
|
||||||
* (check_exported_type). Two load-bearing choices follow them:
|
* (check_exported_type). Two load-bearing choices follow them:
|
||||||
|
|||||||
117
cmd/ww/main.c
117
cmd/ww/main.c
@@ -495,21 +495,15 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
|
|||||||
* package's `.wwi` interface is materialized and every package is
|
* package's `.wwi` interface is materialized and every package is
|
||||||
* compiled on its own (`w6c -c`), then the `.o` set is flat-linked.
|
* compiled on its own (`w6c -c`), then the `.o` set is flat-linked.
|
||||||
*
|
*
|
||||||
* Each w6c pass is BOTH consumer (reads dep `.wwi` as import scope) AND
|
* Each w6c pass is BOTH consumer (reads each direct dep `.wwi` through a
|
||||||
* producer (writes this package's `.wwi` for its importers via -I), so
|
* separate --import argument) AND producer (writes this package's `.wwi`
|
||||||
* a package's interface is materialized as a side effect of compiling
|
* for its importers via -I). Reverse-topo order guarantees a package's
|
||||||
* it. Reverse-topo order guarantees a package's deps' `.wwi` exist
|
* deps' `.wwi` exist before it compiles.
|
||||||
* before it compiles.
|
|
||||||
*
|
*
|
||||||
* The load-bearing rule (ken #56, rob-resolved): every dep is tagged by
|
* Only DIRECT dependency artifacts enter a compile action. The canonical
|
||||||
* its FULL DOTTED import path on prepend (`//ww:module <path>`), so the
|
* import path paired with each `.wwi` preserves qualified symbol identity;
|
||||||
* definer's qualified symbol (#53) equals the consumer's qualified
|
* a `.wwi` relocates the public foreign type/const facts required by its own
|
||||||
* reference (#40) and the sep `.o`s link. A dep is NEVER bare-embedded.
|
* API. Full transitive reachability remains a linker concern.
|
||||||
*
|
|
||||||
* Only DIRECT dependency artifacts are prepended. A `.wwi` relocates the
|
|
||||||
* recursively reachable public foreign type/const facts required by its own
|
|
||||||
* API, retaining their origin modules without turning them into source
|
|
||||||
* imports. Full transitive reachability remains a linker concern.
|
|
||||||
*/
|
*/
|
||||||
#define SEP_MAXPKG 256
|
#define SEP_MAXPKG 256
|
||||||
|
|
||||||
@@ -529,6 +523,7 @@ struct seppkg {
|
|||||||
int failed; /* discovery/compile failure reaches this action */
|
int failed; /* discovery/compile failure reaches this action */
|
||||||
int test_support; /* compiler-generated -T support package */
|
int test_support; /* compiler-generated -T support package */
|
||||||
int loaded; /* directory membership/name loaded exactly once */
|
int loaded; /* directory membership/name loaded exactly once */
|
||||||
|
int export_changed; /* staged export differs from committed export */
|
||||||
int emit_context; /* first verified resolution context */
|
int emit_context; /* first verified resolution context */
|
||||||
unsigned char context_state[SEP_MAXCONTEXT]; /* 0 new, 1 active, 2 checked */
|
unsigned char context_state[SEP_MAXCONTEXT]; /* 0 new, 1 active, 2 checked */
|
||||||
struct ImportSet bindings; /* first context's canonical import bindings */
|
struct ImportSet bindings; /* first context's canonical import bindings */
|
||||||
@@ -701,6 +696,7 @@ sep_find_or_add_variant(struct sepgraph *g, const char *path,
|
|||||||
p->failed = 0;
|
p->failed = 0;
|
||||||
p->test_support = 0;
|
p->test_support = 0;
|
||||||
p->loaded = 0;
|
p->loaded = 0;
|
||||||
|
p->export_changed = 0;
|
||||||
p->emit_context = -1;
|
p->emit_context = -1;
|
||||||
memset(p->context_state, 0, sizeof p->context_state);
|
memset(p->context_state, 0, sizeof p->context_state);
|
||||||
p->bindings.paths = NULL;
|
p->bindings.paths = NULL;
|
||||||
@@ -1315,9 +1311,8 @@ sep_validate_module_closure(struct sepgraph *g, const int *order, int n,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Emit one of pi's own source files into the sep-unit under the
|
/* Emit one of pi's own source files into the sep-unit under the
|
||||||
* //ww:module-reset primary boundary. Imports were already resolved to
|
* //ww:module-reset primary boundary. No source or export outside pi's
|
||||||
* directory-package edges and their direct `.wwi` files were prepended;
|
* sorted owned-source set may enter this unit. */
|
||||||
* no source outside pi's sorted owned-source set may enter this unit. */
|
|
||||||
static int
|
static int
|
||||||
sep_emit_body(FILE *out, const char *path, const char *modpath)
|
sep_emit_body(FILE *out, const char *path, const char *modpath)
|
||||||
{
|
{
|
||||||
@@ -1348,13 +1343,11 @@ sep_emit_body(FILE *out, const char *path, const char *modpath)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compose pi's sep-unit at `unitf`: its byte-sorted DIRECT dependency
|
/* Compose pi's sep-unit at `unitf` from only pi's byte-sorted sources.
|
||||||
* `.wwi`s, each tagged by its dotted path, then pi's own body under
|
* Direct exports are separate compiler inputs; the linker separately retains
|
||||||
* //ww:module-reset. Compiler exports are self-contained for public type
|
* the reachable archive closure. */
|
||||||
* facts; the linker separately retains the reachable archive closure. */
|
|
||||||
static int
|
static int
|
||||||
sep_compose_unit(struct sepgraph *g, int pi, const char *scratch,
|
sep_compose_unit(struct sepgraph *g, int pi, const char *unitf)
|
||||||
const char *unitf)
|
|
||||||
{
|
{
|
||||||
if (g->pkg[pi].emit_context < 0
|
if (g->pkg[pi].emit_context < 0
|
||||||
|| g->pkg[pi].emit_context >= g->ncontext)
|
|| g->pkg[pi].emit_context >= g->ncontext)
|
||||||
@@ -1364,28 +1357,6 @@ sep_compose_unit(struct sepgraph *g, int pi, const char *scratch,
|
|||||||
fprintf(stderr, "ww: cannot open %s\n", unitf);
|
fprintf(stderr, "ww: cannot open %s\n", unitf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (int k = 0; k < g->pkg[pi].ndeps; k++) {
|
|
||||||
int dj = g->pkg[pi].deps[k];
|
|
||||||
char wwi[SEP_ARTIFACT_MAX];
|
|
||||||
sep_fname(g, dj, scratch, ".wwi", wwi, sizeof wwi);
|
|
||||||
FILE *wf = fopen(wwi, "rb");
|
|
||||||
if (wf == NULL) {
|
|
||||||
fprintf(stderr, "ww: missing %s\n", wwi);
|
|
||||||
fclose(u);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int bad = fprintf(u, "//ww:module %s\n", g->pkg[dj].path) < 0;
|
|
||||||
int ch;
|
|
||||||
while (!bad && (ch = fgetc(wf)) != EOF)
|
|
||||||
if (fputc(ch, u) == EOF) bad = 1;
|
|
||||||
if (ferror(wf) || fputc('\n', u) == EOF) bad = 1;
|
|
||||||
if (fclose(wf) != 0) bad = 1;
|
|
||||||
if (bad) {
|
|
||||||
fprintf(stderr, "ww: cannot compose package unit %s\n", unitf);
|
|
||||||
fclose(u);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int bodyrc = 0;
|
int bodyrc = 0;
|
||||||
if (g->pkg[pi].is_dir) {
|
if (g->pkg[pi].is_dir) {
|
||||||
for (int i = 0; i < g->pkg[pi].nsources && bodyrc == 0; i++)
|
for (int i = 0; i < g->pkg[pi].nsources && bodyrc == 0; i++)
|
||||||
@@ -1467,11 +1438,11 @@ archive_o(const char *objpath, const char *apath)
|
|||||||
|
|
||||||
/* -w workdir freshness: a `-w DIR` workdir is a caller-owned persistent
|
/* -w workdir freshness: a `-w DIR` workdir is a caller-owned persistent
|
||||||
* package-artifact tree that replaces the fresh `.sepwork` scratch.
|
* package-artifact tree that replaces the fresh `.sepwork` scratch.
|
||||||
* Staleness is pure content
|
* Staleness is pure content identity, never mtime: a package is reused only
|
||||||
* identity, never mtime: a package is reused only when its freshly
|
* when its freshly composed unit byte-equals the committed unit, no direct
|
||||||
* composed unit byte-equals the committed unit AND the driver/tool copies
|
* dependency emitted a changed export, AND the driver/tool copies recorded in
|
||||||
* recorded in the dir byte-equal the live executables — every decision is
|
* the dir byte-equal the live executables — every decision is reproducible by
|
||||||
* reproducible by hand with cmp(1) against plain files. Artifacts commit
|
* hand with cmp(1) against plain files. Artifacts commit
|
||||||
* via temp + rename with the unit renamed last, so a killed build can
|
* via temp + rename with the unit renamed last, so a killed build can
|
||||||
* never leave a committed unit vouching for uncommitted artifacts. The
|
* never leave a committed unit vouching for uncommitted artifacts. The
|
||||||
* caller serializes invocations per workdir (Make target = one workdir)
|
* caller serializes invocations per workdir (Make target = one workdir)
|
||||||
@@ -1565,7 +1536,7 @@ static void
|
|||||||
workdir_stamp_text(char *buf, size_t bufsz, int is_test, int emit_asm)
|
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",
|
snprintf(buf, bufsz, "ww workdir fmt %d mode %s asm %d\n",
|
||||||
is_test ? 6 : 5, is_test ? "test" : "build", emit_asm);
|
is_test ? 7 : 6, is_test ? "test" : "build", emit_asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A stale global builder identity invalidates every committed unit voucher in
|
/* A stale global builder identity invalidates every committed unit voucher in
|
||||||
@@ -1601,8 +1572,8 @@ invalidate_workdir_units(const char *scratch)
|
|||||||
|
|
||||||
/* build_sep_plan — discover dependencies for every requested product in one
|
/* build_sep_plan — discover dependencies for every requested product in one
|
||||||
* package universe, compile the dependency-first union once, then link each
|
* package universe, compile the dependency-first union once, then link each
|
||||||
* root from its own complete reachable archive closure. The transitive
|
* root from its own complete reachable archive closure. The dependency-first
|
||||||
* producer loop (one `w6c -c -I` per package, dep-first,
|
* producer loop (one `w6c -c -I` per package,
|
||||||
* each DEP `.o` wrapped in its own deterministic `.a`), then a
|
* each DEP `.o` wrapped in its own deterministic `.a`), then a
|
||||||
* reverse-topo `w6l` of each root `.o` + dep `.a` set + libwwrt.a. Side
|
* reverse-topo `w6l` of each root `.o` + dep `.a` set + libwwrt.a. Side
|
||||||
* files land in a cold `<stem>.sepwork` dir, or under the persistent
|
* files land in a cold `<stem>.sepwork` dir, or under the persistent
|
||||||
@@ -1913,12 +1884,17 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
const char *ca = warm ? anew : apath;
|
const char *ca = warm ? anew : apath;
|
||||||
int needs_export = !g->pkg[pi].root || root_package;
|
int needs_export = !g->pkg[pi].root || root_package;
|
||||||
int needs_archive = !g->pkg[pi].root || root_package;
|
int needs_archive = !g->pkg[pi].root || root_package;
|
||||||
if (sep_compose_unit(g, pi, scratch, cu) < 0) {
|
if (sep_compose_unit(g, pi, cu) < 0) {
|
||||||
g->pkg[pi].failed = 1;
|
g->pkg[pi].failed = 1;
|
||||||
any_failed = 1;
|
any_failed = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (warm && !stale_all && file_equal(unitnew, unitf)
|
int deps_changed = 0;
|
||||||
|
for (int k = 0; k < g->pkg[pi].ndeps; k++)
|
||||||
|
if (g->pkg[g->pkg[pi].deps[k]].export_changed)
|
||||||
|
deps_changed = 1;
|
||||||
|
if (warm && !stale_all && !deps_changed
|
||||||
|
&& file_equal(unitnew, unitf)
|
||||||
&& file_is_reg(asmf)
|
&& file_is_reg(asmf)
|
||||||
&& (!needs_export || file_is_reg(wwi))
|
&& (!needs_export || file_is_reg(wwi))
|
||||||
&& (emit_asm || (file_size_nonzero(obj)
|
&& (emit_asm || (file_size_nonzero(obj)
|
||||||
@@ -1938,7 +1914,20 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
* LOCAL type (the root is never imported), which the
|
* LOCAL type (the root is never imported), which the
|
||||||
* export-check rejects. Skip -I for the root; its `.wwi`
|
* export-check rejects. Skip -I for the root; its `.wwi`
|
||||||
* is never consumed. */
|
* is never consumed. */
|
||||||
char *cargv[12];
|
size_t cargvcap = (size_t)(12 + 3 * g->pkg[pi].ndeps);
|
||||||
|
char **cargv = calloc(cargvcap, sizeof *cargv);
|
||||||
|
char (*importfiles)[SEP_ARTIFACT_MAX] = NULL;
|
||||||
|
if (g->pkg[pi].ndeps > 0)
|
||||||
|
importfiles = calloc((size_t)g->pkg[pi].ndeps,
|
||||||
|
sizeof *importfiles);
|
||||||
|
if (cargv == NULL || (g->pkg[pi].ndeps > 0
|
||||||
|
&& importfiles == NULL)) {
|
||||||
|
fprintf(stderr, "ww: out of memory\n");
|
||||||
|
free(importfiles);
|
||||||
|
free(cargv);
|
||||||
|
free(order);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
int cpos = 0;
|
int cpos = 0;
|
||||||
cargv[cpos++] = "w6c";
|
cargv[cpos++] = "w6c";
|
||||||
if (!needs_export && is_test && g->pkg[pi].root) {
|
if (!needs_export && is_test && g->pkg[pi].root) {
|
||||||
@@ -1953,6 +1942,14 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
cargv[cpos++] = (char *)test_support_module;
|
cargv[cpos++] = (char *)test_support_module;
|
||||||
}
|
}
|
||||||
cargv[cpos++] = "-c";
|
cargv[cpos++] = "-c";
|
||||||
|
for (int k = 0; k < g->pkg[pi].ndeps; k++) {
|
||||||
|
int dj = g->pkg[pi].deps[k];
|
||||||
|
sep_fname(g, dj, scratch, ".wwi", importfiles[k],
|
||||||
|
sizeof importfiles[k]);
|
||||||
|
cargv[cpos++] = "--import";
|
||||||
|
cargv[cpos++] = g->pkg[dj].path;
|
||||||
|
cargv[cpos++] = importfiles[k];
|
||||||
|
}
|
||||||
if (needs_export) {
|
if (needs_export) {
|
||||||
cargv[cpos++] = "-I";
|
cargv[cpos++] = "-I";
|
||||||
cargv[cpos++] = (char *)cw;
|
cargv[cpos++] = (char *)cw;
|
||||||
@@ -1961,13 +1958,19 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
cargv[cpos++] = (char *)cs;
|
cargv[cpos++] = (char *)cs;
|
||||||
cargv[cpos++] = (char *)cu;
|
cargv[cpos++] = (char *)cu;
|
||||||
cargv[cpos] = NULL;
|
cargv[cpos] = NULL;
|
||||||
if (run_argv(c6, cargv) != 0) {
|
int compilerc = run_argv(c6, cargv);
|
||||||
|
free(importfiles);
|
||||||
|
free(cargv);
|
||||||
|
if (compilerc != 0) {
|
||||||
fprintf(stderr, "ww: w6c failed for %s\n",
|
fprintf(stderr, "ww: w6c failed for %s\n",
|
||||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||||
g->pkg[pi].failed = 1;
|
g->pkg[pi].failed = 1;
|
||||||
any_failed = 1;
|
any_failed = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (needs_export)
|
||||||
|
g->pkg[pi].export_changed = !warm
|
||||||
|
|| !file_equal(wwinew, wwi);
|
||||||
if (!emit_asm) {
|
if (!emit_asm) {
|
||||||
char *aargv[] = {"w6a", "-o", (char *)co,
|
char *aargv[] = {"w6a", "-o", (char *)co,
|
||||||
(char *)cs, NULL};
|
(char *)cs, NULL};
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
let sepmode: i32 = 0i32; // -c: #22 M3 separate-compile / primary-
|
let sepmode: i32 = 0i32; // -c: #22 M3 separate-compile / primary-
|
||||||
// only codegen (emit imported==0 decls
|
// only codegen (emit imported==0 decls
|
||||||
// only; treat `.wwi` deps as external)
|
// only; treat `.wwi` deps as external)
|
||||||
|
let importpaths: []*u8 = alloc([], argc: u64)!;
|
||||||
|
importpaths.len = argc;
|
||||||
|
let importfiles: []*u8 = alloc([], argc: u64)!;
|
||||||
|
importfiles.len = argc;
|
||||||
|
let nimports: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = 1;
|
let i: i32 = 1;
|
||||||
for (i < argc) {
|
for (i < argc) {
|
||||||
@@ -101,6 +106,16 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
testsupport = argv[i];
|
testsupport = argv[i];
|
||||||
} else { if (cstreq(a, "-c")) {
|
} else { if (cstreq(a, "-c")) {
|
||||||
sepmode = 1i32;
|
sepmode = 1i32;
|
||||||
|
} else { if (cstreq(a, "--import")) {
|
||||||
|
if (i + 2 >= argc) {
|
||||||
|
let m: str = "w6c: --import requires path and file\n";
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
|
importpaths[nimports] = argv[i + 1];
|
||||||
|
importfiles[nimports] = argv[i + 2];
|
||||||
|
nimports += 1;
|
||||||
|
i += 2;
|
||||||
} else { if (a[0u64] == 45u8) {
|
} else { if (a[0u64] == 45u8) {
|
||||||
let m: str = "w6c: unknown flag\n";
|
let m: str = "w6c: unknown flag\n";
|
||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
@@ -112,15 +127,35 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
src = a;
|
src = a;
|
||||||
}; }; }; }; }; };
|
}; }; }; }; }; }; };
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (src == nil) {
|
if (src == nil) {
|
||||||
let m: str = "usage: w6c_ww [-T] [-o out.s] file.ww\n";
|
let m: str = "usage: w6c_ww [-T] [-c] [-I out.wwi] [--import path dep.wwi]... [-o out.s] file.ww\n";
|
||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
if (nimports > 0 && sepmode == 0) {
|
||||||
|
let m: str = "w6c: --import requires -c\n";
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
|
let importi: i32 = 0;
|
||||||
|
for (importi < nimports) {
|
||||||
|
if (importpaths[importi][0u64] == 0u8) {
|
||||||
|
let m: str = "w6c: --import path is empty\n";
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
|
if (importi > 0 && strings.compare(pathstr(importpaths[importi - 1]),
|
||||||
|
pathstr(importpaths[importi])) >= 0) {
|
||||||
|
let m: str = "w6c: --import paths must be sorted and unique\n";
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
|
importi += 1;
|
||||||
|
};
|
||||||
if (testsupport != nil && (sepmode == 0
|
if (testsupport != nil && (sepmode == 0
|
||||||
|| (!cstreq(testsupport, "test")
|
|| (!cstreq(testsupport, "test")
|
||||||
&& !cstreq(testsupport, "__wwtest")))) {
|
&& !cstreq(testsupport, "__wwtest")))) {
|
||||||
@@ -129,6 +164,46 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let importhead: *node = nil;
|
||||||
|
let importtail: *node = nil;
|
||||||
|
importi = 0;
|
||||||
|
for (importi < nimports) {
|
||||||
|
let ibuf: *u8;
|
||||||
|
let ilen: u64;
|
||||||
|
ibuf, ilen = slurp(importfiles[importi]);
|
||||||
|
if (ibuf == nil) {
|
||||||
|
let pre: str = "w6c: import ";
|
||||||
|
let mid: str = ": cannot read ";
|
||||||
|
let nl: str = "\n";
|
||||||
|
let ipath: str = pathstr(importpaths[importi]);
|
||||||
|
let ifile: str = pathstr(importfiles[importi]);
|
||||||
|
os.write(2, pre.ptr, pre.len: u64);
|
||||||
|
os.write(2, ipath.ptr, ipath.len: u64);
|
||||||
|
os.write(2, mid.ptr, mid.len: u64);
|
||||||
|
os.write(2, ifile.ptr, ifile.len: u64);
|
||||||
|
os.write(2, nl.ptr, nl.len: u64);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
let il: lex;
|
||||||
|
lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen);
|
||||||
|
let ips: parser;
|
||||||
|
parserinit(&ips, &il);
|
||||||
|
let imod: str = pathstr(importpaths[importi]);
|
||||||
|
ips.pathmod = imod;
|
||||||
|
ips.curmod = imod;
|
||||||
|
if (testsupport != nil) { ips.testmodule = pathstr(testsupport); };
|
||||||
|
let imported: *node = parsefile(&ips);
|
||||||
|
if (il.errs > 0 || ips.errs > 0) { return 1; };
|
||||||
|
let d: *node = imported.list;
|
||||||
|
if (d != nil) {
|
||||||
|
if (importhead == nil) { importhead = d; }
|
||||||
|
else { importtail.next = d; };
|
||||||
|
for (d.next != nil) { d = d.next; };
|
||||||
|
importtail = d;
|
||||||
|
};
|
||||||
|
importi += 1;
|
||||||
|
};
|
||||||
|
|
||||||
let buf: *u8;
|
let buf: *u8;
|
||||||
let blen: u64;
|
let blen: u64;
|
||||||
buf, blen = slurp(src);
|
buf, blen = slurp(src);
|
||||||
@@ -137,10 +212,22 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
let l: lex;
|
||||||
|
lexinit(&l, strings.dup(pathstr(src)), buf, blen);
|
||||||
|
let ps: parser;
|
||||||
|
parserinit(&ps, &l);
|
||||||
|
if (testsupport != nil) { ps.testmodule = pathstr(testsupport); };
|
||||||
|
let f: *node = parsefile(&ps);
|
||||||
|
// Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's
|
||||||
|
// `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches
|
||||||
|
// cgen and emits junk asm with a zero exit (silent miscompile).
|
||||||
|
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||||
|
if (importhead != nil) {
|
||||||
|
importtail.next = f.list;
|
||||||
|
f.list = importhead;
|
||||||
|
};
|
||||||
|
|
||||||
// Redirect fd 1 to the output file before any cgen emit runs.
|
// cgen writes directly to fd 1; dup2 keeps that implementation private.
|
||||||
// cgen.ww writes directly to fd 1; dup2 lets us reuse it without
|
|
||||||
// threading a file descriptor through the emit helpers.
|
|
||||||
if (out != nil) {
|
if (out != nil) {
|
||||||
let ofd: i32 = os.open(pathstr(out),
|
let ofd: i32 = os.open(pathstr(out),
|
||||||
os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
||||||
@@ -158,24 +245,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.close(ofd);
|
os.close(ofd);
|
||||||
};
|
};
|
||||||
|
|
||||||
let nlen: u64 = cstrlen(src);
|
|
||||||
let view: str;
|
|
||||||
view.ptr = src;
|
|
||||||
view.len = nlen: i32;
|
|
||||||
let fname: str = strings.dup(view);
|
|
||||||
|
|
||||||
let l: lex;
|
|
||||||
lexinit(&l, fname, buf, blen);
|
|
||||||
|
|
||||||
let ps: parser;
|
|
||||||
parserinit(&ps, &l);
|
|
||||||
if (testsupport != nil) { ps.testmodule = pathstr(testsupport); };
|
|
||||||
let f: *node = parsefile(&ps);
|
|
||||||
// Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's
|
|
||||||
// `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches
|
|
||||||
// cgen and emits junk asm with a zero exit (silent miscompile).
|
|
||||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
|
||||||
|
|
||||||
let testmodule: str;
|
let testmodule: str;
|
||||||
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
||||||
let interfaceout: str;
|
let interfaceout: str;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// ww-prototype rendering of a package's EXPORTED surface. Since the
|
// ww-prototype rendering of a package's EXPORTED surface. Since the
|
||||||
// sep-compile flip (epic #22) this is the LIVE import path — the driver
|
// sep-compile flip (epic #22) this is the LIVE import path — the driver
|
||||||
// runs one `w6c -c -I` per package and feeds each dep's `.wwi` to its
|
// runs one `w6c -c -I` per package and feeds each dep's `.wwi` to its
|
||||||
// importers as import scope.
|
// importers through a separate canonical `--import` input.
|
||||||
//
|
//
|
||||||
// wwstage twin of cmd/w6c/wwi.c — byte-identical output is a rule-10
|
// wwstage twin of cmd/w6c/wwi.c — byte-identical output is a rule-10
|
||||||
// requirement (`.wwi` is a cross-stage byte-id substrate). Specs:
|
// requirement (`.wwi` is a cross-stage byte-id substrate). Specs:
|
||||||
|
|||||||
@@ -741,16 +741,12 @@ type lflags = struct {
|
|||||||
// every package on its own (`w6c -c`), then flat-links the `.o` set.
|
// every package on its own (`w6c -c`), then flat-links the `.o` set.
|
||||||
// Separate compilation is the SOLE build path (E3-C1 flip, task #87).
|
// Separate compilation is the SOLE build path (E3-C1 flip, task #87).
|
||||||
//
|
//
|
||||||
// Each w6c pass is BOTH consumer (reads dep `.wwi` as import scope) AND
|
// Each w6c pass is BOTH consumer (reads each direct dep `.wwi` through a
|
||||||
// producer (writes this package's `.wwi` via -I). Reverse-topo order
|
// separate --import argument) AND producer (writes this package's `.wwi`
|
||||||
// guarantees a package's deps' `.wwi` exist before it compiles.
|
// via -I). Reverse-topo order guarantees a package's deps' `.wwi` exist.
|
||||||
//
|
// The canonical import path paired with each self-contained export preserves
|
||||||
// Every direct dep is tagged by its FULL DOTTED import path on prepend
|
// qualified symbol identity; transitive exports remain outside the compile
|
||||||
// (`//ww:module <path>`), so the definer's qualified symbol equals the
|
// action. Unit composition is byte-identical to the cstage driver.
|
||||||
// consumer's qualified reference and the sep `.o`s link. A dependency's
|
|
||||||
// compiler-owned `.wwi` carries its reachable public foreign type facts;
|
|
||||||
// separately prepending transitive interfaces is neither necessary nor
|
|
||||||
// allowed. The unit composition is byte-identical to the cstage driver.
|
|
||||||
|
|
||||||
def SEP_MAXPKG: i32 = 256;
|
def SEP_MAXPKG: i32 = 256;
|
||||||
|
|
||||||
@@ -775,6 +771,7 @@ type seppkg = struct {
|
|||||||
failed: bool,
|
failed: bool,
|
||||||
testsupport: bool,
|
testsupport: bool,
|
||||||
loaded: bool,
|
loaded: bool,
|
||||||
|
exportchanged: bool,
|
||||||
emitcontext: i32,
|
emitcontext: i32,
|
||||||
contextstate: []u8,
|
contextstate: []u8,
|
||||||
bindings: []sepbind,
|
bindings: []sepbind,
|
||||||
@@ -929,6 +926,7 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
|||||||
g.pkg[g.n].failed = false;
|
g.pkg[g.n].failed = false;
|
||||||
g.pkg[g.n].testsupport = false;
|
g.pkg[g.n].testsupport = false;
|
||||||
g.pkg[g.n].loaded = false;
|
g.pkg[g.n].loaded = false;
|
||||||
|
g.pkg[g.n].exportchanged = false;
|
||||||
g.pkg[g.n].emitcontext = -1;
|
g.pkg[g.n].emitcontext = -1;
|
||||||
let cslot: []u8 = alloc([], SEP_MAXCONTEXT: u64)!;
|
let cslot: []u8 = alloc([], SEP_MAXCONTEXT: u64)!;
|
||||||
cslot.len = SEP_MAXCONTEXT;
|
cslot.len = SEP_MAXCONTEXT;
|
||||||
@@ -1546,8 +1544,8 @@ fn sepvalidatemoduleclosure(g: *sepgraph, order: []i32, n: i32,
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Imported source never enters this body: its direct export data was
|
// No imported source or export enters this body: the package owns exactly its
|
||||||
// prepended above, while this package owns exactly its sorted source set.
|
// sorted source set.
|
||||||
fn sepwriteall(fd: i32, buf: *u8, n: u64) bool = {
|
fn sepwriteall(fd: i32, buf: *u8, n: u64) bool = {
|
||||||
match (os.writeall(fd, buf, n)) {
|
match (os.writeall(fd, buf, n)) {
|
||||||
case let wrote: i64 => return wrote == n: i64;
|
case let wrote: i64 => return wrote == n: i64;
|
||||||
@@ -1589,12 +1587,9 @@ fn sepemitbody(fd: i32, path: *u8, modpath: *u8) i32 = {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compose pi's sep-unit at `unitf`: its byte-sorted DIRECT dependency
|
// Compose pi's sep-unit from only pi's byte-sorted sources. Direct exports are
|
||||||
// `.wwi`s, each tagged by its dotted path, then pi's own body under
|
// separate compiler inputs; the linker retains the reachable archive closure.
|
||||||
// //ww:module-reset. Compiler exports are self-contained for public type
|
fn sepcomposeunit(g: *sepgraph, pi: i32, unitf: *u8) i32 = {
|
||||||
// facts; the linker separately retains the reachable archive closure.
|
|
||||||
fn sepcomposeunit(g: *sepgraph, pi: i32, scratch: *u8,
|
|
||||||
unitf: *u8) i32 = {
|
|
||||||
if (g.pkg[pi].emitcontext < 0
|
if (g.pkg[pi].emitcontext < 0
|
||||||
|| g.pkg[pi].emitcontext >= g.ncontext) { return -1; };
|
|| g.pkg[pi].emitcontext >= g.ncontext) { return -1; };
|
||||||
let u: i32 = os.open(pathstr(unitf), os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
let u: i32 = os.open(pathstr(unitf), os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
||||||
@@ -1602,31 +1597,6 @@ fn sepcomposeunit(g: *sepgraph, pi: i32, scratch: *u8,
|
|||||||
cerr("ww: cannot open unit\n");
|
cerr("ww: cannot open unit\n");
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
let k: i32 = 0;
|
|
||||||
for (k < g.pkg[pi].ndeps) {
|
|
||||||
let dj: i32 = g.pkg[pi].deps[k];
|
|
||||||
let wwi: *u8 = sepfname(g, dj, scratch, ".wwi");
|
|
||||||
let wb: *u8;
|
|
||||||
let wn: u64;
|
|
||||||
wb, wn = slurp(wwi);
|
|
||||||
if (wb == nil) {
|
|
||||||
cerr("ww: missing wwi\n");
|
|
||||||
os.close(u);
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
let dm: str = "//ww:module ";
|
|
||||||
if (!sepwriteall(u, dm.ptr, dm.len: u64)
|
|
||||||
|| !sepwriteall(u, g.pkg[dj].path,
|
|
||||||
cstrlen(g.pkg[dj].path))
|
|
||||||
|| !sepwriteall(u, "\n".ptr, 1u64)
|
|
||||||
|| !sepwriteall(u, wb, wn)
|
|
||||||
|| !sepwriteall(u, "\n".ptr, 1u64)) {
|
|
||||||
cerr("ww: cannot compose package unit\n");
|
|
||||||
os.close(u);
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
k += 1;
|
|
||||||
};
|
|
||||||
let bodyrc: i32 = 0;
|
let bodyrc: i32 = 0;
|
||||||
if (g.pkg[pi].isdir != 0) {
|
if (g.pkg[pi].isdir != 0) {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
@@ -1720,7 +1690,7 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// buildonesep — discover deps, reverse-topo,
|
// buildonesep — discover deps, reverse-topo,
|
||||||
// the transitive producer loop (one `w6c -c -I` per package, dep-first,
|
// the dependency-first producer loop (one `w6c -c -I` per package,
|
||||||
// each dependency `.o` wrapped in its own deterministic per-package `.a`), then a
|
// each dependency `.o` wrapped in its own deterministic per-package `.a`), then a
|
||||||
// reverse-topo `w6l` of the root `.o` + dependency `.a` set + libwwrt.a.
|
// reverse-topo `w6l` of the root `.o` + dependency `.a` set + libwwrt.a.
|
||||||
// Side files land in a cold `<stem>.sepwork` scratch dir. Twin of cstage
|
// Side files land in a cold `<stem>.sepwork` scratch dir. Twin of cstage
|
||||||
@@ -1728,9 +1698,10 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
|||||||
|
|
||||||
// A `-w DIR` workdir is a caller-owned persistent package-artifact tree
|
// A `-w DIR` workdir is a caller-owned persistent package-artifact tree
|
||||||
// that replaces the fresh `.sepwork` scratch. Staleness is pure content
|
// that replaces the fresh `.sepwork` scratch. Staleness is pure content
|
||||||
// identity, never mtime: a package is reused only when its freshly
|
// identity, never mtime: a package is reused only when its freshly composed
|
||||||
// composed unit byte-equals the committed unit AND the driver/tool copies
|
// unit byte-equals the committed unit, no direct dependency emitted a changed
|
||||||
// recorded in the dir byte-equal the live executables — every decision is
|
// export, AND the driver/tool copies recorded in the dir byte-equal the live
|
||||||
|
// executables — every decision is
|
||||||
// reproducible by hand with cmp(1) against plain files. Artifacts commit
|
// reproducible by hand with cmp(1) against plain files. Artifacts commit
|
||||||
// via temp + rename with the unit renamed last, so a killed build can
|
// via temp + rename with the unit renamed last, so a killed build can
|
||||||
// never leave a committed unit vouching for uncommitted artifacts. The
|
// never leave a committed unit vouching for uncommitted artifacts. The
|
||||||
@@ -1840,14 +1811,14 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
|||||||
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||||
if (istest != 0) {
|
if (istest != 0) {
|
||||||
if (emitasm != 0) {
|
if (emitasm != 0) {
|
||||||
return "ww workdir fmt 6 mode test asm 1\n";
|
return "ww workdir fmt 7 mode test asm 1\n";
|
||||||
};
|
};
|
||||||
return "ww workdir fmt 6 mode test asm 0\n";
|
return "ww workdir fmt 7 mode test asm 0\n";
|
||||||
};
|
};
|
||||||
if (emitasm != 0) {
|
if (emitasm != 0) {
|
||||||
return "ww workdir fmt 5 mode build asm 1\n";
|
return "ww workdir fmt 6 mode build asm 1\n";
|
||||||
};
|
};
|
||||||
return "ww workdir fmt 5 mode build asm 0\n";
|
return "ww workdir fmt 6 mode build asm 0\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
fn stampmatches(path: *u8, want: str) bool = {
|
fn stampmatches(path: *u8, want: str) bool = {
|
||||||
@@ -2338,15 +2309,23 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
let needsexport: bool = !g.pkg[pi].root || rootpackage;
|
let needsexport: bool = !g.pkg[pi].root || rootpackage;
|
||||||
let needsarchive: bool = !g.pkg[pi].root || rootpackage;
|
let needsarchive: bool = !g.pkg[pi].root || rootpackage;
|
||||||
if (sepcomposeunit(g, pi, scratch, cu) < 0) {
|
if (sepcomposeunit(g, pi, cu) < 0) {
|
||||||
g.pkg[pi].failed = true;
|
g.pkg[pi].failed = true;
|
||||||
anyfailed = true;
|
anyfailed = true;
|
||||||
oi += 1;
|
oi += 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let depschanged: bool = false;
|
||||||
|
let changedk: i32 = 0;
|
||||||
|
for (changedk < g.pkg[pi].ndeps) {
|
||||||
|
if (g.pkg[g.pkg[pi].deps[changedk]].exportchanged) {
|
||||||
|
depschanged = true;
|
||||||
|
};
|
||||||
|
changedk += 1;
|
||||||
|
};
|
||||||
let fresh: bool = false;
|
let fresh: bool = false;
|
||||||
if (warm) {
|
if (warm) {
|
||||||
if (!staleall) {
|
if (!staleall && !depschanged) {
|
||||||
fresh = fileequal(unitnew, unitf);
|
fresh = fileequal(unitnew, unitf);
|
||||||
if (fresh) { fresh = fileisreg(asmf); };
|
if (fresh) { fresh = fileisreg(asmf); };
|
||||||
if (fresh) {
|
if (fresh) {
|
||||||
@@ -2390,6 +2369,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
let alen: u64 = 8u64;
|
let alen: u64 = 8u64;
|
||||||
if (!needsexport) { alen = 6u64; if (roott) { alen = 9u64; }; };
|
if (!needsexport) { alen = 6u64; if (roott) { alen = 9u64; }; };
|
||||||
if (supportt) { alen += 2u64; };
|
if (supportt) { alen += 2u64; };
|
||||||
|
alen += (g.pkg[pi].ndeps: u64) * 3u64;
|
||||||
let argv: []str = alloc([], alen)!;
|
let argv: []str = alloc([], alen)!;
|
||||||
append(argv, "w6c");
|
append(argv, "w6c");
|
||||||
if (roott) {
|
if (roott) {
|
||||||
@@ -2402,6 +2382,14 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
append(argv, testsupportmodule);
|
append(argv, testsupportmodule);
|
||||||
};
|
};
|
||||||
append(argv, "-c");
|
append(argv, "-c");
|
||||||
|
let importk: i32 = 0;
|
||||||
|
for (importk < g.pkg[pi].ndeps) {
|
||||||
|
let dj: i32 = g.pkg[pi].deps[importk];
|
||||||
|
append(argv, "--import");
|
||||||
|
append(argv, pathstr(g.pkg[dj].path));
|
||||||
|
append(argv, pathstr(sepfname(g, dj, scratch, ".wwi")));
|
||||||
|
importk += 1;
|
||||||
|
};
|
||||||
if (needsexport) {
|
if (needsexport) {
|
||||||
append(argv, "-I");
|
append(argv, "-I");
|
||||||
append(argv, pathstr(cw));
|
append(argv, pathstr(cw));
|
||||||
@@ -2430,6 +2418,11 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
if (needsexport) {
|
||||||
|
if (!warm || !fileequal(wwinew, wwi)) {
|
||||||
|
g.pkg[pi].exportchanged = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
if (emitasm == 0) {
|
if (emitasm == 0) {
|
||||||
let argv: []str = alloc([], 4u64)!;
|
let argv: []str = alloc([], 4u64)!;
|
||||||
append(argv, "w6a");
|
append(argv, "w6a");
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ package wwi_test;
|
|||||||
// 10): the `w6c -I <out.wwi>` producer IS the live import path, and
|
// 10): the `w6c -I <out.wwi>` producer IS the live import path, and
|
||||||
// `.wwi` is a cross-stage byte-id substrate pinned directly. POSITIVE:
|
// `.wwi` is a cross-stage byte-id substrate pinned directly. POSITIVE:
|
||||||
// for ascii/strings/getopt (drew2-audited leak-free), drive the target
|
// for ascii/strings/getopt (drew2-audited leak-free), drive the target
|
||||||
// as the PRIMARY module of a driver-combined unit, then (1) w6c -c -I and
|
// as the PRIMARY owner-only driver unit with separate direct exports, then
|
||||||
|
// (1) w6c -c -I and
|
||||||
// w6c_ww -c -I both succeed, (2) cs.wwi == ww.wwi byte-for-byte, (3) the
|
// w6c_ww -c -I both succeed, (2) cs.wwi == ww.wwi byte-for-byte, (3) the
|
||||||
// emitted .wwi re-parses (wwdump -a exit 0). getopt is the recursion
|
// emitted .wwi re-parses (wwdump -a exit 0). getopt is the recursion
|
||||||
// stressor. A synth fixture covers the decl-kinds + type-nodes no lib
|
// stressor. A synth fixture covers the decl-kinds + type-nodes no lib
|
||||||
@@ -28,10 +29,10 @@ package wwi_test;
|
|||||||
// producer->importer flow on BOTH stages: (a) the dep `.wwi` package
|
// producer->importer flow on BOTH stages: (a) the dep `.wwi` package
|
||||||
// line equals the real leaf, (b) the dep `.wwi` is byte-identical
|
// line equals the real leaf, (b) the dep `.wwi` is byte-identical
|
||||||
// across stages, (c) a root importing the dep RESOLVES on both stages
|
// across stages, (c) a root importing the dep RESOLVES on both stages
|
||||||
// and the two importer `.s` are byte-identical. The composed units are
|
// and the two importer `.s` are byte-identical. The owner units and
|
||||||
// fed straight to w6c / w6c_ww (not `ww build`): the producer-unit
|
// separate exports are fed straight to w6c / w6c_ww (not `ww build`):
|
||||||
// shape `//ww:module-reset <path>` + body is exactly what the driver's
|
// the producer-unit shape `//ww:module-reset <path>` + body is exactly
|
||||||
// sep_emit_body emits.
|
// what the driver's sep_emit_body emits.
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import os.exec;
|
import os.exec;
|
||||||
@@ -88,18 +89,40 @@ fn m2positive(pkg: str) void = {
|
|||||||
let co: testenv.commandout;
|
let co: testenv.commandout;
|
||||||
testenv.runcommand(td, td, "drv", av, lifetime(), &co);
|
testenv.runcommand(td, td, "drv", av, lifetime(), &co);
|
||||||
|
|
||||||
let comb: str = strings.concat(td, "/", pkg,
|
let work: str = strings.concat(td, "/", pkg, ".sepwork/");
|
||||||
".sepwork/__root.unit.ww");
|
let comb: str = strings.concat(work, "__root.unit.ww");
|
||||||
if (!testenv.exists(comb)) { fail(pkg, "no resolved unit"); };
|
if (!testenv.exists(comb)) { fail(pkg, "no resolved unit"); };
|
||||||
|
|
||||||
let cs: str = strings.concat(td, "/cs.wwi");
|
let cs: str = strings.concat(td, "/cs.wwi");
|
||||||
let ws: str = strings.concat(td, "/ww.wwi");
|
let ws: str = strings.concat(td, "/ww.wwi");
|
||||||
// The driver-composed unit uses package separators and may contain the
|
let deps: []str = [];
|
||||||
// same compiler-owned origin fact through multiple direct interfaces;
|
if (testenv.same(pkg, "ascii")) { append(deps, "strings"); };
|
||||||
// exact fact interning is intentionally tied to -c package mode.
|
if (testenv.same(pkg, "strings")) {
|
||||||
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cs, comb];
|
append(deps, "bytes"); append(deps, "encoding.utf8");
|
||||||
|
append(deps, "os"); append(deps, "types");
|
||||||
|
};
|
||||||
|
if (testenv.same(pkg, "getopt")) {
|
||||||
|
append(deps, "encoding.utf8"); append(deps, "fmt");
|
||||||
|
append(deps, "io"); append(deps, "os"); append(deps, "strings");
|
||||||
|
};
|
||||||
|
if (deps.len == 0) { abort("unknown m2 package"); };
|
||||||
|
let cav: []str = [testenv.driver("w6c"), "-c"];
|
||||||
|
let di: i32 = 0;
|
||||||
|
for (di < deps.len) {
|
||||||
|
append(cav, "--import"); append(cav, deps[di]);
|
||||||
|
append(cav, strings.concat(work, deps[di], ".wwi"));
|
||||||
|
di += 1;
|
||||||
|
};
|
||||||
|
append(cav, "-I"); append(cav, cs); append(cav, comb);
|
||||||
if (!runok(td, "w6c", cav)) { fail(pkg, "w6c -c -I rejected"); };
|
if (!runok(td, "w6c", cav)) { fail(pkg, "w6c -c -I rejected"); };
|
||||||
let wav: []str = [testenv.driver("w6c_ww"), "-c", "-I", ws, comb];
|
let wav: []str = [testenv.driver("w6c_ww"), "-c"];
|
||||||
|
di = 0;
|
||||||
|
for (di < deps.len) {
|
||||||
|
append(wav, "--import"); append(wav, deps[di]);
|
||||||
|
append(wav, strings.concat(work, deps[di], ".wwi"));
|
||||||
|
di += 1;
|
||||||
|
};
|
||||||
|
append(wav, "-I"); append(wav, ws); append(wav, comb);
|
||||||
if (!runok(td, "w6c_ww", wav)) { fail(pkg, "w6c_ww -c -I rejected"); };
|
if (!runok(td, "w6c_ww", wav)) { fail(pkg, "w6c_ww -c -I rejected"); };
|
||||||
|
|
||||||
if (!testenv.same(testenv.readfile(cs), testenv.readfile(ws))) {
|
if (!testenv.same(testenv.readfile(cs), testenv.readfile(ws))) {
|
||||||
@@ -318,22 +341,21 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
|
|||||||
fail(tag, "w6c vs w6c_ww .wwi differ (rule 10)");
|
fail(tag, "w6c vs w6c_ww .wwi differ (rule 10)");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Leg c — a root importing the dep RESOLVES on both stages
|
// Leg c — a root importing the dep RESOLVES from a separate export on
|
||||||
// (pre-fix: "package main does not match import path" REJECT). The
|
// both stages (pre-fix: "package main does not match import path"
|
||||||
// dep `.wwi` is prepended under //ww:module <path>, exactly as the
|
// REJECT).
|
||||||
// driver composes an importer unit.
|
|
||||||
testenv.writefile(root, strings.concat(
|
testenv.writefile(root, strings.concat(
|
||||||
"//ww:module ", path, "\n",
|
|
||||||
testenv.readfile(cswwi), "\n",
|
|
||||||
"//ww:module-reset\n",
|
"//ww:module-reset\n",
|
||||||
"package main;\n",
|
"package main;\n",
|
||||||
"import ", path, ";\n",
|
"import ", path, ";\n",
|
||||||
"export fn main() i32 = { return 42; };\n"));
|
"export fn main() i32 = { return 42; };\n"));
|
||||||
let rcav: []str = [testenv.driver("w6c"), "-c", "-o", rcss, root];
|
let rcav: []str = [testenv.driver("w6c"), "-c", "--import", path,
|
||||||
|
cswwi, "-o", rcss, root];
|
||||||
if (!runok(td, "csroot", rcav)) {
|
if (!runok(td, "csroot", rcav)) {
|
||||||
fail(tag, "w6c rejected the import (BUG-C)");
|
fail(tag, "w6c rejected the import (BUG-C)");
|
||||||
};
|
};
|
||||||
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "-o", rwws, root];
|
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "--import", path,
|
||||||
|
wwwwi, "-o", rwws, root];
|
||||||
if (!runok(td, "wsroot", rwav)) {
|
if (!runok(td, "wsroot", rwav)) {
|
||||||
fail(tag, "w6c_ww rejected the import (BUG-C)");
|
fail(tag, "w6c_ww rejected the import (BUG-C)");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -726,8 +726,9 @@ fn workescape(s: str) str = {
|
|||||||
let prodwork: str = strings.concat(prodout, ".sepwork/");
|
let prodwork: str = strings.concat(prodout, ".sepwork/");
|
||||||
let produnit: str = readfile(strings.concat(prodwork,
|
let produnit: str = readfile(strings.concat(prodwork,
|
||||||
"pkg.unit.ww"));
|
"pkg.unit.ww"));
|
||||||
assert(has(produnit, "//ww:module api\n"));
|
assert(has(produnit, "//ww:module-reset pkg\n"));
|
||||||
assert(!has(produnit, "//ww:module implementation\n"));
|
assert(!has(produnit, "//ww:module "));
|
||||||
|
assert(!has(produnit, "IMPLEMENTATION_SOURCE"));
|
||||||
assert(!has(produnit, "__same"));
|
assert(!has(produnit, "__same"));
|
||||||
assert(!has(produnit, "__external"));
|
assert(!has(produnit, "__external"));
|
||||||
assert(!os.exists(strings.concat(prodwork, "__same.unit.ww")));
|
assert(!os.exists(strings.concat(prodwork, "__same.unit.ww")));
|
||||||
@@ -807,30 +808,20 @@ fn workescape(s: str) str = {
|
|||||||
let externalproduction: str = readfile(strings.concat(sharedwork,
|
let externalproduction: str = readfile(strings.concat(sharedwork,
|
||||||
"__ww-test-001-external-production.unit.ww"));
|
"__ww-test-001-external-production.unit.ww"));
|
||||||
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
|
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
|
||||||
assert(has(sameunit, "//ww:module api\n"));
|
assert(!has(sameunit, "//ww:module "));
|
||||||
assert(has(sameunit, "//ww:module __same\n"));
|
|
||||||
assert(has(sameunit, "//ww:module test\n"));
|
|
||||||
assert(!has(sameunit, "//ww:module implementation\n"));
|
|
||||||
assert(!has(sameunit, "//ww:module __external\n"));
|
|
||||||
assert(os.exists(strings.concat(sharedwork,
|
assert(os.exists(strings.concat(sharedwork,
|
||||||
"__external.unit.ww")));
|
"__external.unit.ww")));
|
||||||
assert(has(sameunit, "PACKAGE_PRODUCTION_A"));
|
assert(has(sameunit, "PACKAGE_PRODUCTION_A"));
|
||||||
assert(has(sameunit, "PACKAGE_PRODUCTION_Z"));
|
assert(has(sameunit, "PACKAGE_PRODUCTION_Z"));
|
||||||
assert(has(sameunit, "SAME_TEST_SOURCE"));
|
assert(has(sameunit, "SAME_TEST_SOURCE"));
|
||||||
assert(!has(sameunit, "EXTERNAL_TEST_SOURCE"));
|
assert(!has(sameunit, "EXTERNAL_TEST_SOURCE"));
|
||||||
assert(has(externalunit, "//ww:module pkg\n"));
|
assert(!has(externalunit, "//ww:module "));
|
||||||
assert(has(externalunit, "//ww:module __external\n"));
|
|
||||||
assert(has(externalunit, "//ww:module test\n"));
|
|
||||||
assert(!has(externalunit, "//ww:module api\n"));
|
|
||||||
assert(!has(externalunit, "//ww:module implementation\n"));
|
|
||||||
assert(!has(externalunit, "//ww:module __same\n"));
|
|
||||||
assert(has(externalunit, "EXTERNAL_TEST_SOURCE"));
|
assert(has(externalunit, "EXTERNAL_TEST_SOURCE"));
|
||||||
assert(!has(externalunit, "PACKAGE_PRODUCTION_A"));
|
assert(!has(externalunit, "PACKAGE_PRODUCTION_A"));
|
||||||
assert(!has(externalunit, "PACKAGE_PRODUCTION_Z"));
|
assert(!has(externalunit, "PACKAGE_PRODUCTION_Z"));
|
||||||
assert(has(externalproduction, "PACKAGE_PRODUCTION_A"));
|
assert(has(externalproduction, "PACKAGE_PRODUCTION_A"));
|
||||||
assert(has(externalproduction, "PACKAGE_PRODUCTION_Z"));
|
assert(has(externalproduction, "PACKAGE_PRODUCTION_Z"));
|
||||||
assert(has(externalproduction, "//ww:module api\n"));
|
assert(!has(externalproduction, "//ww:module "));
|
||||||
assert(!has(externalproduction, "//ww:module implementation\n"));
|
|
||||||
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
||||||
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
||||||
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
|
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
|
||||||
@@ -872,6 +863,30 @@ fn workescape(s: str) str = {
|
|||||||
"__ww-test-001-external.unit.ww") == 1);
|
"__ww-test-001-external.unit.ww") == 1);
|
||||||
assert(occurrences(ctrace,
|
assert(occurrences(ctrace,
|
||||||
"-T --test-support-module") == 2);
|
"-T --test-support-module") == 2);
|
||||||
|
let samecompile: str = linecontaining(ctrace,
|
||||||
|
"__ww-test-000-same.unit.ww");
|
||||||
|
let externalcompile: str = linecontaining(ctrace,
|
||||||
|
"__ww-test-001-external.unit.ww");
|
||||||
|
let productioncompile: str = linecontaining(ctrace,
|
||||||
|
"__ww-test-001-external-production.unit.ww");
|
||||||
|
assert(same(samecompile, strings.concat(
|
||||||
|
"-T --test-support-module test -c --import __same ",
|
||||||
|
sharedwork, "__same.wwi --import api ", sharedwork,
|
||||||
|
"api.wwi --import test ", sharedwork, "test.wwi -o ",
|
||||||
|
sharedwork, "__ww-test-000-same.s ", sharedwork,
|
||||||
|
"__ww-test-000-same.unit.ww")));
|
||||||
|
assert(same(externalcompile, strings.concat(
|
||||||
|
"-T --test-support-module test -c --import __external ",
|
||||||
|
sharedwork, "__external.wwi --import pkg ", sharedwork,
|
||||||
|
"__ww-test-001-external-production.wwi --import test ",
|
||||||
|
sharedwork, "test.wwi -o ", sharedwork,
|
||||||
|
"__ww-test-001-external.s ", sharedwork,
|
||||||
|
"__ww-test-001-external.unit.ww")));
|
||||||
|
assert(same(productioncompile, strings.concat(
|
||||||
|
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
|
||||||
|
"__ww-test-001-external-production.wwi -o ", sharedwork,
|
||||||
|
"__ww-test-001-external-production.s ", sharedwork,
|
||||||
|
"__ww-test-001-external-production.unit.ww")));
|
||||||
let ltrace: str = readfile(linkertrace);
|
let ltrace: str = readfile(linkertrace);
|
||||||
assert(occurrences(ltrace, "\n") == 2);
|
assert(occurrences(ltrace, "\n") == 2);
|
||||||
let samelink: str = linecontaining(ltrace,
|
let samelink: str = linecontaining(ltrace,
|
||||||
@@ -1204,43 +1219,33 @@ fn workescape(s: str) str = {
|
|||||||
alphaartifact, ".unit.ww"));
|
alphaartifact, ".unit.ww"));
|
||||||
let betaunit: str = readfile(strings.concat(sharedwork,
|
let betaunit: str = readfile(strings.concat(sharedwork,
|
||||||
betaartifact, ".unit.ww"));
|
betaartifact, ".unit.ww"));
|
||||||
assert(has(commonunit, "//ww:module leaf\n"));
|
assert(has(commonunit, "//ww:module-reset common\n"));
|
||||||
assert(!has(commonunit, "//ww:module test\n"));
|
assert(!has(commonunit, "//ww:module "));
|
||||||
assert(has(alphaunit, "//ww:module common\n"));
|
assert(!has(alphaunit, "//ww:module "));
|
||||||
assert(!has(alphaunit, "//ww:module leaf\n"));
|
|
||||||
assert(has(alphaunit, "MULTIDIR_ALPHA_A"));
|
assert(has(alphaunit, "MULTIDIR_ALPHA_A"));
|
||||||
assert(has(alphaunit, "MULTIDIR_ALPHA_Z"));
|
assert(has(alphaunit, "MULTIDIR_ALPHA_Z"));
|
||||||
assert(has(betaunit, "//ww:module common\n"));
|
assert(!has(betaunit, "//ww:module "));
|
||||||
assert(has(betaunit, "//ww:module alpha\n"));
|
assert(has(betaunit, "MULTIDIR_BETA"));
|
||||||
assert(!has(betaunit, "//ww:module leaf\n"));
|
|
||||||
assert(!has(commonunit, "DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE"));
|
assert(!has(commonunit, "DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE"));
|
||||||
let roots: []str = [readfile(strings.concat(sharedwork,
|
let roots: []str = [readfile(strings.concat(sharedwork,
|
||||||
rootkeys[0], ".unit.ww")), readfile(strings.concat(sharedwork,
|
rootkeys[0], ".unit.ww")), readfile(strings.concat(sharedwork,
|
||||||
rootkeys[1], ".unit.ww")), readfile(strings.concat(sharedwork,
|
rootkeys[1], ".unit.ww")), readfile(strings.concat(sharedwork,
|
||||||
rootkeys[2], ".unit.ww")), readfile(strings.concat(sharedwork,
|
rootkeys[2], ".unit.ww")), readfile(strings.concat(sharedwork,
|
||||||
rootkeys[3], ".unit.ww"))];
|
rootkeys[3], ".unit.ww"))];
|
||||||
assert(has(roots[0], "//ww:module _alpha_same\n"));
|
assert(!has(roots[0], "//ww:module "));
|
||||||
assert(has(roots[0], "//ww:module common\n"));
|
|
||||||
assert(has(roots[0], "//ww:module test\n"));
|
|
||||||
assert(!has(roots[0], "//ww:module leaf\n"));
|
|
||||||
assert(!has(roots[0], "//ww:module alpha\n"));
|
|
||||||
assert(has(roots[0], "MULTIDIR_ALPHA_A"));
|
assert(has(roots[0], "MULTIDIR_ALPHA_A"));
|
||||||
assert(has(roots[0], "MULTIDIR_ALPHA_Z"));
|
assert(has(roots[0], "MULTIDIR_ALPHA_Z"));
|
||||||
assert(has(roots[1], "//ww:module alpha\n"));
|
assert(has(roots[0], "MULTIDIR_ALPHA_SAME"));
|
||||||
assert(has(roots[1], "//ww:module _alpha_external\n"));
|
assert(!has(roots[0], "MULTIDIR_ALPHA_EXTERNAL"));
|
||||||
assert(has(roots[1], "//ww:module test\n"));
|
assert(!has(roots[1], "//ww:module "));
|
||||||
assert(!has(roots[1], "//ww:module common\n"));
|
assert(has(roots[1], "MULTIDIR_ALPHA_EXTERNAL"));
|
||||||
assert(!has(roots[1], "//ww:module _alpha_same\n"));
|
assert(!has(roots[1], "MULTIDIR_ALPHA_A"));
|
||||||
assert(has(roots[2], "//ww:module _beta_same\n"));
|
assert(!has(roots[2], "//ww:module "));
|
||||||
assert(has(roots[2], "//ww:module common\n"));
|
assert(has(roots[2], "MULTIDIR_BETA"));
|
||||||
assert(has(roots[2], "//ww:module alpha\n"));
|
assert(has(roots[2], "MULTIDIR_BETA_SAME"));
|
||||||
assert(has(roots[2], "//ww:module test\n"));
|
assert(!has(roots[3], "//ww:module "));
|
||||||
assert(!has(roots[2], "//ww:module leaf\n"));
|
assert(has(roots[3], "MULTIDIR_BETA_EXTERNAL"));
|
||||||
assert(!has(roots[2], "//ww:module beta\n"));
|
assert(!has(roots[3], "MULTIDIR_BETA_SAME"));
|
||||||
assert(has(roots[3], "//ww:module beta\n"));
|
|
||||||
assert(has(roots[3], "//ww:module _beta_external\n"));
|
|
||||||
assert(has(roots[3], "//ww:module test\n"));
|
|
||||||
assert(!has(roots[3], "//ww:module common\n"));
|
|
||||||
let products: []str = ["leaf", "common", alphaartifact, betaartifact,
|
let products: []str = ["leaf", "common", alphaartifact, betaartifact,
|
||||||
"_alpha_same", "_alpha_external", "_beta_same",
|
"_alpha_same", "_alpha_external", "_beta_same",
|
||||||
"_beta_external", "test"];
|
"_beta_external", "test"];
|
||||||
@@ -1625,13 +1630,7 @@ fn workescape(s: str) str = {
|
|||||||
let ri: i32 = 0;
|
let ri: i32 = 0;
|
||||||
for (ri < keys.len) {
|
for (ri < keys.len) {
|
||||||
let unit: str = readfile(strings.concat(work, keys[ri], ".unit.ww"));
|
let unit: str = readfile(strings.concat(work, keys[ri], ".unit.ww"));
|
||||||
assert(has(unit, "//ww:module __wwtest\n"));
|
assert(!has(unit, "//ww:module "));
|
||||||
if (ri == 1 || ri == 2) {
|
|
||||||
assert(has(unit, "//ww:module test\n"));
|
|
||||||
};
|
|
||||||
if (ri == 3) {
|
|
||||||
assert(has(unit, "//ww:module consumer\n"));
|
|
||||||
};
|
|
||||||
let runav: []str = [bins[ri]];
|
let runav: []str = [bins[ri]];
|
||||||
runcommand(root, strings.concat("mixed-run-", stages[si], "-",
|
runcommand(root, strings.concat("mixed-run-", stages[si], "-",
|
||||||
keys[ri]), runav,
|
keys[ri]), runav,
|
||||||
@@ -1748,8 +1747,8 @@ fn workescape(s: str) str = {
|
|||||||
let cbin: str = readfile(bin);
|
let cbin: str = readfile(bin);
|
||||||
let rootunit: str = readfile(strings.concat(work,
|
let rootunit: str = readfile(strings.concat(work,
|
||||||
"__ww-test-000-same.unit.ww"));
|
"__ww-test-000-same.unit.ww"));
|
||||||
assert(has(rootunit, "//ww:module p00\n"));
|
assert(has(rootunit, "//ww:module-reset\npackage target;"));
|
||||||
assert(!has(rootunit, "//ww:module p01\n"));
|
assert(!has(rootunit, "//ww:module "));
|
||||||
let linkargs: str = readfile(trace);
|
let linkargs: str = readfile(trace);
|
||||||
assert(linkargs.len > 8192);
|
assert(linkargs.len > 8192);
|
||||||
assert(!has(linkargs, ".wwi\n"));
|
assert(!has(linkargs, ".wwi\n"));
|
||||||
@@ -2075,8 +2074,7 @@ fn workescape(s: str) str = {
|
|||||||
"__ww-test-000-external-production.unit.ww"));
|
"__ww-test-000-external-production.unit.ww"));
|
||||||
let supportunit: str = readfile(strings.concat(work,
|
let supportunit: str = readfile(strings.concat(work,
|
||||||
"__wwtest.unit.ww"));
|
"__wwtest.unit.ww"));
|
||||||
assert(has(rootunit, "//ww:module test\n"));
|
assert(!has(rootunit, "//ww:module "));
|
||||||
assert(has(rootunit, "//ww:module __wwtest\n"));
|
|
||||||
assert(has(rootunit, "USER_TEST_EXTERNAL"));
|
assert(has(rootunit, "USER_TEST_EXTERNAL"));
|
||||||
assert(!has(rootunit, "USER_TEST_PACKAGE_A"));
|
assert(!has(rootunit, "USER_TEST_PACKAGE_A"));
|
||||||
assert(!has(rootunit, "USER_TEST_PACKAGE_Z"));
|
assert(!has(rootunit, "USER_TEST_PACKAGE_Z"));
|
||||||
@@ -2115,121 +2113,52 @@ fn workescape(s: str) str = {
|
|||||||
clean(root);
|
clean(root);
|
||||||
};
|
};
|
||||||
|
|
||||||
@test fn diamond_test_dependency_compiles_once() void = {
|
|
||||||
let root: str = fresh();
|
|
||||||
let shared: str = strings.concat(root, "/shared");
|
|
||||||
let left: str = strings.concat(root, "/left");
|
|
||||||
let right: str = strings.concat(root, "/right");
|
|
||||||
let target: str = strings.concat(root, "/diamond");
|
|
||||||
assert(os.mkdir(shared, 448i32) == 0);
|
|
||||||
assert(os.mkdir(left, 448i32) == 0);
|
|
||||||
assert(os.mkdir(right, 448i32) == 0);
|
|
||||||
assert(os.mkdir(target, 448i32) == 0);
|
|
||||||
writefile(strings.concat(shared, "/shared.ww"),
|
|
||||||
"package shared;\nexport fn value() i32 = { return 20; };\n");
|
|
||||||
writefile(strings.concat(left, "/left.ww"), strings.concat(
|
|
||||||
"package left;\nimport shared;\n",
|
|
||||||
"export fn value() i32 = { return shared.value(); };\n"));
|
|
||||||
writefile(strings.concat(right, "/right.ww"), strings.concat(
|
|
||||||
"package right;\nimport shared;\n",
|
|
||||||
"export fn value() i32 = { return shared.value() + 1; };\n"));
|
|
||||||
writefile(strings.concat(target, "/diamond.ww"),
|
|
||||||
"package diamond;\nfn local() i32 = { return 1; };\n");
|
|
||||||
writefile(strings.concat(target, "/diamond_test.ww"), strings.concat(
|
|
||||||
"package diamond;\nimport left;\nimport right;\n",
|
|
||||||
"@test fn one_shared_compile() void = {\n",
|
|
||||||
" assert(left.value() + right.value() + local() == 42);\n};\n"));
|
|
||||||
let trace: str = strings.concat(root, "/compiler.trace");
|
|
||||||
let wrapper: str = strings.concat(root, "/trace-w6c.sh");
|
|
||||||
writefile(trace, "");
|
|
||||||
writeexecutable(wrapper, strings.concat(
|
|
||||||
"#!/bin/sh\n",
|
|
||||||
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_TRACE\"\n",
|
|
||||||
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
|
|
||||||
let baseenv: []str = os.getenvs();
|
|
||||||
let env: []str = alloc([], (baseenv.len + 3): u64)!;
|
|
||||||
let ei: i32 = 0;
|
|
||||||
for (ei < baseenv.len) {
|
|
||||||
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
|
||||||
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_TRACE=")
|
|
||||||
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")) {
|
|
||||||
append(env, baseenv[ei]);
|
|
||||||
};
|
|
||||||
ei += 1;
|
|
||||||
};
|
|
||||||
append(env, strings.concat("WW_W6C=", wrapper));
|
|
||||||
append(env, strings.concat("WW_PACKAGE_TRACE=", trace));
|
|
||||||
append(env, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
|
|
||||||
let bin: str = strings.concat(root, "/diamond.test");
|
|
||||||
let av: []str = [driver("ww"), "test", "-c", "-o", bin,
|
|
||||||
"-I", root, target];
|
|
||||||
let out: commandout;
|
|
||||||
runcommandenv(root, "diamond-build", av, env,
|
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
|
||||||
expectexit(&out, 0);
|
|
||||||
assert(occurrences(readfile(trace), "shared.unit.ww") == 1);
|
|
||||||
let work: str = strings.concat(bin, ".sepwork/");
|
|
||||||
let unit: str = readfile(strings.concat(work,
|
|
||||||
"__ww-test-000-same.unit.ww"));
|
|
||||||
assert(has(unit, "//ww:module left\n"));
|
|
||||||
assert(has(unit, "//ww:module right\n"));
|
|
||||||
assert(!has(unit, "//ww:module shared\n"));
|
|
||||||
assert(has(readfile(strings.concat(work, "left.unit.ww")),
|
|
||||||
"//ww:module shared\n"));
|
|
||||||
assert(has(readfile(strings.concat(work, "right.unit.ww")),
|
|
||||||
"//ww:module shared\n"));
|
|
||||||
assert(os.exists(strings.concat(work, "shared.a")));
|
|
||||||
let runav: []str = [bin];
|
|
||||||
runcommand(root, "diamond-run", runav,
|
|
||||||
(60i64 * (time.second: i64)): time.duration, &out);
|
|
||||||
expectexit(&out, 0);
|
|
||||||
assert(has(out.stdout, "one_shared_compile ... ok\n"));
|
|
||||||
clean(root);
|
|
||||||
};
|
|
||||||
|
|
||||||
@test fn exact_package_tool_argv_stage_parity() void = {
|
@test fn exact_package_tool_argv_stage_parity() void = {
|
||||||
let root: str = fresh();
|
let root: str = fresh();
|
||||||
let source: str = strings.concat(root, "/source tree");
|
let source: str = strings.concat(root, "/source tree");
|
||||||
let runtime: str = strings.concat(root, "/runtime library");
|
let runtime: str = strings.concat(root, "/runtime library");
|
||||||
let leaf: str = strings.concat(source, "/ww_root_parity_leaf_7f3");
|
let base: str = strings.concat(source, "/ww_root_parity_base_7f3");
|
||||||
let dep: str = strings.concat(source, "/ww_root_parity_dep_7f3");
|
let left: str = strings.concat(source, "/ww_root_parity_left_7f3");
|
||||||
|
let right: str = strings.concat(source, "/ww_root_parity_right_7f3");
|
||||||
let target: str = strings.concat(source, "/ww_root_parity_target_7f3");
|
let target: str = strings.concat(source, "/ww_root_parity_target_7f3");
|
||||||
let tools: str = strings.concat(root, "/tool wrappers");
|
let tools: str = strings.concat(root, "/tool wrappers");
|
||||||
assert(os.mkdir(source, 448i32) == 0);
|
assert(os.mkdir(source, 448i32) == 0);
|
||||||
assert(os.mkdir(runtime, 448i32) == 0);
|
assert(os.mkdir(runtime, 448i32) == 0);
|
||||||
let copyav: []str = ["/bin/cp", "-R", strings.concat(repo(), "/lib/."),
|
|
||||||
source];
|
|
||||||
let copyout: commandout;
|
|
||||||
runcommand(root, "copy-source-library", copyav,
|
|
||||||
(30i64 * (time.second: i64)): time.duration, ©out);
|
|
||||||
expectexit(©out, 0);
|
|
||||||
assert(copyout.stderr.len == 0);
|
|
||||||
let support: str = strings.concat(source, "/test/run.ww");
|
|
||||||
let supportbody: str = readfile(support);
|
|
||||||
assert(os.remove(support) == 0);
|
|
||||||
writefile(support, strings.concat("// WW_SRCLIB fixture marker\n",
|
|
||||||
supportbody));
|
|
||||||
writefile(strings.concat(runtime, "/libwwrt.a"),
|
writefile(strings.concat(runtime, "/libwwrt.a"),
|
||||||
readfile(strings.concat(repo(), "/out/lib/libwwrt.a")));
|
readfile(strings.concat(repo(), "/out/lib/libwwrt.a")));
|
||||||
assert(os.mkdir(leaf, 448i32) == 0);
|
assert(os.mkdir(base, 448i32) == 0);
|
||||||
assert(os.mkdir(dep, 448i32) == 0);
|
assert(os.mkdir(left, 448i32) == 0);
|
||||||
|
assert(os.mkdir(right, 448i32) == 0);
|
||||||
assert(os.mkdir(target, 448i32) == 0);
|
assert(os.mkdir(target, 448i32) == 0);
|
||||||
assert(os.mkdir(tools, 448i32) == 0);
|
assert(os.mkdir(tools, 448i32) == 0);
|
||||||
writefile(strings.concat(leaf, "/leaf.ww"), strings.concat(
|
let basea: str = strings.concat(
|
||||||
"package ww_root_parity_leaf_7f3;\n",
|
"package ww_root_parity_base_7f3;\n",
|
||||||
"export fn value() i32 = { return 40; };\n"));
|
"export fn value() i32 = { return 20; };\n");
|
||||||
writefile(strings.concat(dep, "/dep.ww"), strings.concat(
|
let basez: str = strings.concat(
|
||||||
"package ww_root_parity_dep_7f3;\n",
|
"package ww_root_parity_base_7f3;\n",
|
||||||
"import ww_root_parity_leaf_7f3;\n",
|
"fn private_value() i32 = { return 99; };\n");
|
||||||
|
let leftbody: str = strings.concat(
|
||||||
|
"package ww_root_parity_left_7f3;\n",
|
||||||
|
"import ww_root_parity_base_7f3;\n",
|
||||||
|
"import ww_root_parity_base_7f3;\n",
|
||||||
"export fn value() i32 = { return ",
|
"export fn value() i32 = { return ",
|
||||||
"ww_root_parity_leaf_7f3.value() + 2; };\n"));
|
"ww_root_parity_base_7f3.value(); };\n");
|
||||||
writefile(strings.concat(target, "/target.ww"), strings.concat(
|
let rightbody: str = strings.concat(
|
||||||
"package ww_root_parity_target_7f3;\n",
|
"package ww_root_parity_right_7f3;\n",
|
||||||
"import ww_root_parity_dep_7f3;\n",
|
"import ww_root_parity_base_7f3;\n",
|
||||||
"fn value() i32 = { return ww_root_parity_dep_7f3.value(); };\n"));
|
"export fn value() i32 = { return ",
|
||||||
writefile(strings.concat(target, "/target_test.ww"), strings.concat(
|
"ww_root_parity_base_7f3.value() + 1; };\n");
|
||||||
"package ww_root_parity_target_7f3;\n",
|
let rootbody: str = strings.concat(
|
||||||
"@test fn exact_argv() void = { assert(value() == 42); };\n"));
|
"package main;\n",
|
||||||
|
"import ww_root_parity_right_7f3;\n",
|
||||||
|
"import ww_root_parity_left_7f3;\n",
|
||||||
|
"fn main() i32 = { return ww_root_parity_left_7f3.value() + ",
|
||||||
|
"ww_root_parity_right_7f3.value() + 1; };\n");
|
||||||
|
writefile(strings.concat(base, "/a.ww"), basea);
|
||||||
|
writefile(strings.concat(base, "/z.ww"), basez);
|
||||||
|
writefile(strings.concat(left, "/left.ww"), leftbody);
|
||||||
|
writefile(strings.concat(right, "/right.ww"), rightbody);
|
||||||
|
writefile(strings.concat(target, "/main.ww"), rootbody);
|
||||||
|
|
||||||
let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh");
|
let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh");
|
||||||
let assemblerwrapper: str = strings.concat(tools, "/w6a wrapper.sh");
|
let assemblerwrapper: str = strings.concat(tools, "/w6a wrapper.sh");
|
||||||
@@ -2262,19 +2191,43 @@ fn workescape(s: str) str = {
|
|||||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||||
"\"$WW_ARGV_FAILURE_TRACE\"; done\n",
|
"\"$WW_ARGV_FAILURE_TRACE\"; done\n",
|
||||||
"printf '\\n' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
|
"printf '\\n' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
|
||||||
"exit 23\n"));
|
"owner=\n",
|
||||||
|
"for arg in \"$@\"; do if [ \"$arg\" = ",
|
||||||
|
"\"$WW_ARGV_MISSING_OWNER\" ]; then owner=1; fi; done\n",
|
||||||
|
"if [ -n \"$owner\" ]; then\n",
|
||||||
|
" mv -- \"$WW_ARGV_MISSING_EXPORT\" ",
|
||||||
|
"\"$WW_ARGV_MISSING_EXPORT.saved\" || exit 24\n",
|
||||||
|
" \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n",
|
||||||
|
" rc=$?\n",
|
||||||
|
" mv -- \"$WW_ARGV_MISSING_EXPORT.saved\" ",
|
||||||
|
"\"$WW_ARGV_MISSING_EXPORT\" || exit 25\n",
|
||||||
|
" exit $rc\n",
|
||||||
|
"fi\n",
|
||||||
|
"exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n"));
|
||||||
|
|
||||||
let stages: []str = ["ww", "ww_ww"];
|
let stages: []str = ["ww", "ww", "ww_ww", "ww_ww"];
|
||||||
let compilers: []str = ["w6c", "w6c_ww"];
|
let compilers: []str = ["w6c", "w6c", "w6c_ww", "w6c_ww"];
|
||||||
let assemblers: []str = ["w6a", "w6a_ww"];
|
let assemblers: []str = ["w6a", "w6a", "w6a_ww", "w6a_ww"];
|
||||||
let linkers: []str = ["w6l", "w6l_ww"];
|
let linkers: []str = ["w6l", "w6l", "w6l_ww", "w6l_ww"];
|
||||||
let tags: []str = ["c", "ww"];
|
let tags: []str = ["c1", "c2", "ww1", "ww2"];
|
||||||
let bin: str = strings.concat(root, "/published test binary");
|
let bin: str = strings.concat(root, "/published binary");
|
||||||
let workroot: str = strings.concat(bin, ".sepwork");
|
let workroot: str = strings.concat(bin, ".sepwork");
|
||||||
let work: str = strings.concat(workroot, "/");
|
let work: str = strings.concat(workroot, "/");
|
||||||
let referenceunit: str = "";
|
let artifacts: []str = ["ww_root_parity_base_7f3",
|
||||||
let referencewwi: str = "";
|
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3"];
|
||||||
let referencearchive: str = "";
|
let unitartifacts: []str = ["ww_root_parity_base_7f3",
|
||||||
|
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "__root"];
|
||||||
|
let wantunits: []str = [strings.concat(
|
||||||
|
"//ww:module-reset ww_root_parity_base_7f3\n", basea,
|
||||||
|
"\n//ww:module-reset ww_root_parity_base_7f3\n", basez, "\n"),
|
||||||
|
strings.concat("//ww:module-reset ww_root_parity_left_7f3\n",
|
||||||
|
leftbody, "\n"),
|
||||||
|
strings.concat("//ww:module-reset ww_root_parity_right_7f3\n",
|
||||||
|
rightbody, "\n"),
|
||||||
|
strings.concat("//ww:module-reset\n", rootbody, "\n")];
|
||||||
|
let referenceunits: []str = ["", "", "", ""];
|
||||||
|
let referenceexports: []str = ["", "", ""];
|
||||||
|
let referencearchives: []str = ["", "", ""];
|
||||||
let referencebin: str = "";
|
let referencebin: str = "";
|
||||||
let referencecompiler: str = "";
|
let referencecompiler: str = "";
|
||||||
let referenceassembler: str = "";
|
let referenceassembler: str = "";
|
||||||
@@ -2316,7 +2269,13 @@ fn workescape(s: str) str = {
|
|||||||
&& !strings.hasprefix(baseenv[ei],
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
"WW_ARGV_REAL_ASSEMBLER=")
|
"WW_ARGV_REAL_ASSEMBLER=")
|
||||||
&& !strings.hasprefix(baseenv[ei],
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
"WW_ARGV_REAL_LINKER=")) {
|
"WW_ARGV_REAL_LINKER=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_ARGV_FAILURE_TRACE=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_ARGV_MISSING_EXPORT=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_ARGV_MISSING_OWNER=")) {
|
||||||
append(env, baseenv[ei]);
|
append(env, baseenv[ei]);
|
||||||
};
|
};
|
||||||
ei += 1;
|
ei += 1;
|
||||||
@@ -2336,72 +2295,89 @@ fn workescape(s: str) str = {
|
|||||||
append(env, strings.concat("WW_ARGV_REAL_LINKER=",
|
append(env, strings.concat("WW_ARGV_REAL_LINKER=",
|
||||||
driver(linkers[si])));
|
driver(linkers[si])));
|
||||||
|
|
||||||
let av: []str = [driver(stages[si]), "test", "-c", "-o", bin,
|
let av: []str = [driver(stages[si]), "build", "-o", bin,
|
||||||
target];
|
target];
|
||||||
let out: commandout;
|
let out: commandout;
|
||||||
runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env,
|
runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env,
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
(120i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 0);
|
expectexit(&out, 0);
|
||||||
assert(out.stderr.len == 0);
|
assert(out.stderr.len == 0);
|
||||||
let rootunit: str = readfile(strings.concat(work,
|
let ui: i32 = 0;
|
||||||
"__ww-test-000-same.unit.ww"));
|
for (ui < unitartifacts.len) {
|
||||||
let depunit: str = readfile(strings.concat(work,
|
let unit: str = readfile(strings.concat(work, unitartifacts[ui],
|
||||||
"ww_root_parity_dep_7f3.unit.ww"));
|
".unit.ww"));
|
||||||
assert(has(rootunit, "//ww:module ww_root_parity_dep_7f3\n"));
|
assert(same(unit, wantunits[ui]));
|
||||||
assert(!has(rootunit, "//ww:module ww_root_parity_leaf_7f3\n"));
|
assert(!has(unit, "//ww:module "));
|
||||||
assert(has(depunit, "//ww:module ww_root_parity_leaf_7f3\n"));
|
if (si == 0) { referenceunits[ui] = strings.dup(unit); }
|
||||||
assert(os.exists(strings.concat(work,
|
else { assert(same(referenceunits[ui], unit)); };
|
||||||
"ww_root_parity_leaf_7f3.wwi")));
|
ui += 1;
|
||||||
assert(os.exists(strings.concat(work,
|
};
|
||||||
"ww_root_parity_leaf_7f3.a")));
|
let ai: i32 = 0;
|
||||||
assert(os.exists(strings.concat(work,
|
for (ai < artifacts.len) {
|
||||||
"ww_root_parity_dep_7f3.wwi")));
|
let exportf: str = readfile(strings.concat(work, artifacts[ai],
|
||||||
assert(os.exists(strings.concat(work,
|
".wwi"));
|
||||||
"ww_root_parity_dep_7f3.a")));
|
let archive: str = readfile(strings.concat(work, artifacts[ai],
|
||||||
assert(has(readfile(strings.concat(work, "test.unit.ww")),
|
".a"));
|
||||||
"// WW_SRCLIB fixture marker\n"));
|
if (si == 0) {
|
||||||
assert(!os.exists(strings.concat(work,
|
referenceexports[ai] = strings.dup(exportf);
|
||||||
"__ww-test-000-same.wwi")));
|
referencearchives[ai] = strings.dup(archive);
|
||||||
assert(!os.exists(strings.concat(work,
|
} else {
|
||||||
"__ww-test-000-same.a")));
|
assert(same(referenceexports[ai], exportf));
|
||||||
|
assert(same(referencearchives[ai], archive));
|
||||||
|
};
|
||||||
|
ai += 1;
|
||||||
|
};
|
||||||
|
assert(!os.exists(strings.concat(work, "__root.wwi")));
|
||||||
|
assert(!os.exists(strings.concat(work, "__root.a")));
|
||||||
assert(os.exists(bin));
|
assert(os.exists(bin));
|
||||||
|
|
||||||
let ctrace: str = readfile(compilertrace);
|
let ctrace: str = readfile(compilertrace);
|
||||||
let atrace: str = readfile(assemblertrace);
|
let atrace: str = readfile(assemblertrace);
|
||||||
let ltrace: str = readfile(linkertrace);
|
let ltrace: str = readfile(linkertrace);
|
||||||
assert(occurrences(ctrace, strings.concat("<", work,
|
assert(occurrences(ctrace, "\n") == 4);
|
||||||
"ww_root_parity_leaf_7f3.unit.ww>")) == 1);
|
let baseline: str = strings.concat("BEGIN<-c><-I><", work,
|
||||||
assert(occurrences(ctrace, strings.concat("<", work,
|
"ww_root_parity_base_7f3.wwi><-o><", work,
|
||||||
"ww_root_parity_dep_7f3.unit.ww>")) == 1);
|
"ww_root_parity_base_7f3.s><", work,
|
||||||
assert(occurrences(ctrace, strings.concat("<", work,
|
"ww_root_parity_base_7f3.unit.ww>");
|
||||||
"__ww-test-000-same.unit.ww>")) == 1);
|
let leftline: str = strings.concat("BEGIN<-c><--import>",
|
||||||
assert(pos(ctrace, strings.concat("<", work,
|
"<ww_root_parity_base_7f3><", work,
|
||||||
"ww_root_parity_leaf_7f3.unit.ww>"))
|
"ww_root_parity_base_7f3.wwi><-I><", work,
|
||||||
< pos(ctrace, strings.concat("<", work,
|
"ww_root_parity_left_7f3.wwi><-o><", work,
|
||||||
"ww_root_parity_dep_7f3.unit.ww>")));
|
"ww_root_parity_left_7f3.s><", work,
|
||||||
assert(pos(ctrace, strings.concat("<", work,
|
"ww_root_parity_left_7f3.unit.ww>");
|
||||||
"ww_root_parity_dep_7f3.unit.ww>"))
|
let rightline: str = strings.concat("BEGIN<-c><--import>",
|
||||||
< pos(ctrace, strings.concat("<", work,
|
"<ww_root_parity_base_7f3><", work,
|
||||||
"__ww-test-000-same.unit.ww>")));
|
"ww_root_parity_base_7f3.wwi><-I><", work,
|
||||||
assert(has(ctrace, strings.concat("BEGIN<-c><-I><", work,
|
"ww_root_parity_right_7f3.wwi><-o><", work,
|
||||||
"ww_root_parity_dep_7f3.wwi><-o><", work,
|
"ww_root_parity_right_7f3.s><", work,
|
||||||
"ww_root_parity_dep_7f3.s><", work,
|
"ww_root_parity_right_7f3.unit.ww>");
|
||||||
"ww_root_parity_dep_7f3.unit.ww>")));
|
let rootline: str = strings.concat("BEGIN<-c><--import>",
|
||||||
assert(has(ctrace, strings.concat(
|
"<ww_root_parity_left_7f3><", work,
|
||||||
"BEGIN<-T><--test-support-module><test><-c><-o><", work,
|
"ww_root_parity_left_7f3.wwi><--import>",
|
||||||
"__ww-test-000-same.s><", work,
|
"<ww_root_parity_right_7f3><", work,
|
||||||
"__ww-test-000-same.unit.ww>")));
|
"ww_root_parity_right_7f3.wwi><-o><", work,
|
||||||
|
"__root.s><", work, "__root.unit.ww>");
|
||||||
|
assert(same(linecontaining(ctrace,
|
||||||
|
"ww_root_parity_base_7f3.unit.ww"), baseline));
|
||||||
|
assert(same(linecontaining(ctrace,
|
||||||
|
"ww_root_parity_left_7f3.unit.ww"), leftline));
|
||||||
|
assert(same(linecontaining(ctrace,
|
||||||
|
"ww_root_parity_right_7f3.unit.ww"), rightline));
|
||||||
|
assert(same(linecontaining(ctrace, "__root.unit.ww"), rootline));
|
||||||
|
assert(!has(rootline, "ww_root_parity_base_7f3.wwi"));
|
||||||
|
assert(occurrences(atrace, "\n") == 4);
|
||||||
assert(has(atrace, strings.concat("BEGIN<-o><", work,
|
assert(has(atrace, strings.concat("BEGIN<-o><", work,
|
||||||
"ww_root_parity_dep_7f3.o><", work,
|
"ww_root_parity_left_7f3.o><", work,
|
||||||
"ww_root_parity_dep_7f3.s>")));
|
"ww_root_parity_left_7f3.s>")));
|
||||||
assert(occurrences(ltrace, "\n") == 1);
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
||||||
"__ww-test-000-same.o>")));
|
"__root.o>")));
|
||||||
assert(has(ltrace, strings.concat("<", work,
|
ai = 0;
|
||||||
"ww_root_parity_dep_7f3.a>")));
|
for (ai < artifacts.len) {
|
||||||
assert(has(ltrace, strings.concat("<", work,
|
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
|
||||||
"ww_root_parity_leaf_7f3.a>")));
|
".a>")) == 1);
|
||||||
assert(has(ltrace, strings.concat("<", work, "test.a>")));
|
ai += 1;
|
||||||
|
};
|
||||||
assert(has(ltrace, strings.concat("<", runtime, "/libwwrt.a>")));
|
assert(has(ltrace, strings.concat("<", runtime, "/libwwrt.a>")));
|
||||||
assert(!has(ltrace, strings.concat("<", repo(),
|
assert(!has(ltrace, strings.concat("<", repo(),
|
||||||
"/out/lib/libwwrt.a>")));
|
"/out/lib/libwwrt.a>")));
|
||||||
@@ -2410,14 +2386,9 @@ fn workescape(s: str) str = {
|
|||||||
let runav: []str = [bin];
|
let runav: []str = [bin];
|
||||||
runcommand(root, strings.concat("exact-argv-run-", tags[si]), runav,
|
runcommand(root, strings.concat("exact-argv-run-", tags[si]), runav,
|
||||||
(60i64 * (time.second: i64)): time.duration, &out);
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 0);
|
expectexit(&out, 42);
|
||||||
assert(has(out.stdout, "exact_argv ... ok\n"));
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
if (si == 0) {
|
if (si == 0) {
|
||||||
referenceunit = strings.dup(rootunit);
|
|
||||||
referencewwi = strings.dup(readfile(strings.concat(work,
|
|
||||||
"ww_root_parity_dep_7f3.wwi")));
|
|
||||||
referencearchive = strings.dup(readfile(strings.concat(work,
|
|
||||||
"ww_root_parity_dep_7f3.a")));
|
|
||||||
referencebin = strings.dup(readfile(bin));
|
referencebin = strings.dup(readfile(bin));
|
||||||
referencecompiler = strings.dup(ctrace);
|
referencecompiler = strings.dup(ctrace);
|
||||||
referenceassembler = strings.dup(atrace);
|
referenceassembler = strings.dup(atrace);
|
||||||
@@ -2425,13 +2396,6 @@ fn workescape(s: str) str = {
|
|||||||
referenceout = strings.dup(out.stdout);
|
referenceout = strings.dup(out.stdout);
|
||||||
referenceerr = strings.dup(out.stderr);
|
referenceerr = strings.dup(out.stderr);
|
||||||
} else {
|
} else {
|
||||||
assert(same(referenceunit, rootunit));
|
|
||||||
assert(same(referencewwi,
|
|
||||||
readfile(strings.concat(work,
|
|
||||||
"ww_root_parity_dep_7f3.wwi"))));
|
|
||||||
assert(same(referencearchive,
|
|
||||||
readfile(strings.concat(work,
|
|
||||||
"ww_root_parity_dep_7f3.a"))));
|
|
||||||
assert(same(referencebin, readfile(bin)));
|
assert(same(referencebin, readfile(bin)));
|
||||||
assert(same(referencecompiler, ctrace));
|
assert(same(referencecompiler, ctrace));
|
||||||
assert(same(referenceassembler, atrace));
|
assert(same(referenceassembler, atrace));
|
||||||
@@ -2442,7 +2406,7 @@ fn workescape(s: str) str = {
|
|||||||
clean(workroot);
|
clean(workroot);
|
||||||
clean(bin);
|
clean(bin);
|
||||||
|
|
||||||
let failenv: []str = alloc([], (env.len + 2): u64)!;
|
let failenv: []str = alloc([], (env.len + 4): u64)!;
|
||||||
ei = 0;
|
ei = 0;
|
||||||
for (ei < env.len) {
|
for (ei < env.len) {
|
||||||
if (!strings.hasprefix(env[ei], "WW_W6C=")
|
if (!strings.hasprefix(env[ei], "WW_W6C=")
|
||||||
@@ -2454,13 +2418,21 @@ fn workescape(s: str) str = {
|
|||||||
};
|
};
|
||||||
append(failenv, strings.concat("WW_W6C=", failurewrapper));
|
append(failenv, strings.concat("WW_W6C=", failurewrapper));
|
||||||
append(failenv, strings.concat("WW_ARGV_FAILURE_TRACE=", failuretrace));
|
append(failenv, strings.concat("WW_ARGV_FAILURE_TRACE=", failuretrace));
|
||||||
|
append(failenv, strings.concat("WW_ARGV_MISSING_EXPORT=", work,
|
||||||
|
"ww_root_parity_base_7f3.wwi"));
|
||||||
|
append(failenv, strings.concat("WW_ARGV_MISSING_OWNER=", work,
|
||||||
|
"ww_root_parity_left_7f3.unit.ww"));
|
||||||
runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av,
|
runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av,
|
||||||
failenv, (120i64 * (time.second: i64)): time.duration, &out);
|
failenv, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
assert(has(out.stderr,
|
let wantfailure: str = strings.concat(
|
||||||
"ww: w6c failed for ww_root_parity_leaf_7f3\n"));
|
"w6c: import ww_root_parity_base_7f3: cannot read ", work,
|
||||||
assert(has(readfile(failuretrace), strings.concat("<-I><", work,
|
"ww_root_parity_base_7f3.wwi\n",
|
||||||
"ww_root_parity_leaf_7f3.wwi>")));
|
"ww: w6c failed for ww_root_parity_left_7f3\n");
|
||||||
|
assert(same(out.stderr, wantfailure));
|
||||||
|
assert(has(readfile(failuretrace), strings.concat(
|
||||||
|
"<--import><ww_root_parity_base_7f3><", work,
|
||||||
|
"ww_root_parity_base_7f3.wwi>")));
|
||||||
if (si == 0) { referencefailure = strings.dup(out.stderr); }
|
if (si == 0) { referencefailure = strings.dup(out.stderr); }
|
||||||
else { assert(same(referencefailure, out.stderr)); };
|
else { assert(same(referencefailure, out.stderr)); };
|
||||||
clean(workroot);
|
clean(workroot);
|
||||||
|
|||||||
@@ -88,25 +88,22 @@ fn samefile(a: str, b: str, why: str) void = {
|
|||||||
let cwork: str = strings.concat(stems[0], ".sepwork/");
|
let cwork: str = strings.concat(stems[0], ".sepwork/");
|
||||||
let cwork2: str = strings.concat(stems[1], ".sepwork/");
|
let cwork2: str = strings.concat(stems[1], ".sepwork/");
|
||||||
let wwork: str = strings.concat(stems[2], ".sepwork/");
|
let wwork: str = strings.concat(stems[2], ".sepwork/");
|
||||||
let bariface: str = testenv.readfile(strings.concat(cwork, "example.bar.wwi"));
|
|
||||||
let fooiface: str = testenv.readfile(strings.concat(cwork, "example.foo.wwi"));
|
|
||||||
let foounit: str = testenv.readfile(strings.concat(cwork,
|
let foounit: str = testenv.readfile(strings.concat(cwork,
|
||||||
"example.foo.unit.ww"));
|
"example.foo.unit.ww"));
|
||||||
let wantfoo: str = strings.concat("//ww:module example.bar\n", bariface,
|
let wantfoo: str = strings.concat("//ww:module-reset example.foo\n", afoosrc,
|
||||||
"\n//ww:module-reset example.foo\n", afoosrc,
|
|
||||||
"\n//ww:module-reset example.foo\n", zfoosrc, "\n");
|
"\n//ww:module-reset example.foo\n", zfoosrc, "\n");
|
||||||
if (!testenv.same(foounit, wantfoo)
|
if (!testenv.same(foounit, wantfoo)
|
||||||
|| testenv.has(foounit, "DECOY_FILE")) {
|
|| testenv.has(foounit, "DECOY_FILE")
|
||||||
fail("foo unit is not its sorted, owned source set plus direct bar export");
|
|| testenv.has(foounit, "//ww:module ")) {
|
||||||
|
fail("foo unit is not exactly its sorted, owned source set");
|
||||||
};
|
};
|
||||||
let wantroot: str = strings.concat("//ww:module example.foo\n", fooiface,
|
let wantroot: str = strings.concat("//ww:module-reset\n", appsrc, "\n");
|
||||||
"\n//ww:module-reset\n", appsrc, "\n");
|
|
||||||
if (!testenv.same(wantroot, testenv.readfile(strings.concat(cwork,
|
if (!testenv.same(wantroot, testenv.readfile(strings.concat(cwork,
|
||||||
"__root.unit.ww")))) {
|
"__root.unit.ww")))) {
|
||||||
fail("root unit is not direct-foo-only");
|
fail("root unit is not exactly its owned source");
|
||||||
};
|
};
|
||||||
let keys: []str = ["example.base", "example.bar", "example.foo"];
|
let keys: []str = ["example.base", "example.bar", "example.foo"];
|
||||||
let suffixes: []str = [".wwi", ".a"];
|
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < keys.len) {
|
for (i < keys.len) {
|
||||||
let j: i32 = 0;
|
let j: i32 = 0;
|
||||||
@@ -120,6 +117,10 @@ fn samefile(a: str, b: str, why: str) void = {
|
|||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
|
samefile(strings.concat(cwork, "__root.unit.ww"), strings.concat(cwork2,
|
||||||
|
"__root.unit.ww"), "root unit changed across clean C builds");
|
||||||
|
samefile(strings.concat(cwork, "__root.unit.ww"), strings.concat(wwork,
|
||||||
|
"__root.unit.ww"), "root unit differs between stages");
|
||||||
samefile(stems[0], stems[1], "C executables are not deterministic");
|
samefile(stems[0], stems[1], "C executables are not deterministic");
|
||||||
samefile(stems[0], stems[2], "C/WW executables differ");
|
samefile(stems[0], stems[2], "C/WW executables differ");
|
||||||
|
|
||||||
|
|||||||
@@ -286,12 +286,11 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = {
|
|||||||
|| testenv.has(apiiface, "hidden")) {
|
|| testenv.has(apiiface, "hidden")) {
|
||||||
fail("self-contained", "api export leaked unrelated or private declarations");
|
fail("self-contained", "api export leaked unrelated or private declarations");
|
||||||
};
|
};
|
||||||
let expectedunit: str = strings.concat("//ww:module api\n", apiiface,
|
let expectedunit: str = strings.concat("//ww:module-reset\n", mainsrc, "\n");
|
||||||
"\n//ww:module-reset\n", mainsrc, "\n");
|
|
||||||
if (!testenv.same(expectedunit, testenv.readfile(strings.concat(cwork,
|
if (!testenv.same(expectedunit, testenv.readfile(strings.concat(cwork,
|
||||||
"__root.unit.ww"))) || !testenv.same(expectedunit,
|
"__root.unit.ww"))) || !testenv.same(expectedunit,
|
||||||
testenv.readfile(strings.concat(wwork, "__root.unit.ww")))) {
|
testenv.readfile(strings.concat(wwork, "__root.unit.ww")))) {
|
||||||
fail("self-contained", "consumer compiler input was not direct-api-only");
|
fail("self-contained", "consumer unit was not exactly its owned source");
|
||||||
};
|
};
|
||||||
if (!testenv.exists(strings.concat(cwork, "implementation.a"))
|
if (!testenv.exists(strings.concat(cwork, "implementation.a"))
|
||||||
|| !testenv.exists(strings.concat(cwork, "dimensions.a"))) {
|
|| !testenv.exists(strings.concat(cwork, "dimensions.a"))) {
|
||||||
@@ -405,10 +404,12 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
};
|
};
|
||||||
let unit: str = testenv.readfile(strings.concat(scratch,
|
let unit: str = testenv.readfile(strings.concat(scratch,
|
||||||
"__root.unit.ww"));
|
"__root.unit.ww"));
|
||||||
let lp: i32 = testenv.pos(unit, "//ww:module left\n");
|
let rootbody: str = testenv.readfile(strings.concat(main, "/main.ww"));
|
||||||
let rp: i32 = testenv.pos(unit, "//ww:module right\n");
|
let wantroot: str = strings.concat("//ww:module-reset\n", rootbody,
|
||||||
if (lp < 0 || rp < 0 || lp >= rp) {
|
"\n");
|
||||||
fail("diamond", "dependency traversal did not byte-sort imports");
|
if (!testenv.same(unit, wantroot) || testenv.has(unit,
|
||||||
|
"//ww:module ")) {
|
||||||
|
fail("diamond", "root unit contains non-owned export text");
|
||||||
};
|
};
|
||||||
let sharedunit: str = testenv.readfile(strings.concat(scratch,
|
let sharedunit: str = testenv.readfile(strings.concat(scratch,
|
||||||
"shared.unit.ww"));
|
"shared.unit.ww"));
|
||||||
@@ -426,8 +427,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
};
|
};
|
||||||
if (testenv.occurrences(leftiface, "export type token") != 1
|
if (testenv.occurrences(leftiface, "export type token") != 1
|
||||||
|| testenv.occurrences(rightiface, "export type token") != 1
|
|| testenv.occurrences(rightiface, "export type token") != 1
|
||||||
|| testenv.occurrences(unit, "export type token") != 2
|
|| testenv.has(unit, "export type token")) {
|
||||||
|| testenv.occurrences(unit, "//ww:module shared\n") != 2) {
|
|
||||||
fail("diamond", "origin fact closure did not merge deterministically");
|
fail("diamond", "origin fact closure did not merge deterministically");
|
||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -452,43 +452,6 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
fail("diamond", "shuffled enumeration changed package units");
|
fail("diamond", "shuffled enumeration changed package units");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Count actual compiler actions, rather than inferring interning from
|
|
||||||
// artifact names. The wrapper is selected through the production
|
|
||||||
// driver's existing tool override and records one row per w6c process.
|
|
||||||
let trace: str = strings.concat(td, "/compiler.trace");
|
|
||||||
let wrapper: str = strings.concat(td, "/trace-w6c.sh");
|
|
||||||
testenv.writefile(trace, "");
|
|
||||||
testenv.writeexecutable(wrapper, strings.concat(
|
|
||||||
"#!/bin/sh\n",
|
|
||||||
"printf '%s\\n' \"$*\" >> \"$WW_LOCALBUILD_TRACE\"\n",
|
|
||||||
"exec \"$WW_LOCALBUILD_W6C\" \"$@\"\n"));
|
|
||||||
let baseenv: []str = os.getenvs();
|
|
||||||
let env: []str = alloc([], (baseenv.len + 3): u64)!;
|
|
||||||
let ei: i32 = 0;
|
|
||||||
for (ei < baseenv.len) {
|
|
||||||
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
|
||||||
&& !strings.hasprefix(baseenv[ei], "WW_LOCALBUILD_TRACE=")
|
|
||||||
&& !strings.hasprefix(baseenv[ei], "WW_LOCALBUILD_W6C=")) {
|
|
||||||
append(env, baseenv[ei]);
|
|
||||||
};
|
|
||||||
ei += 1;
|
|
||||||
};
|
|
||||||
append(env, strings.concat("WW_W6C=", wrapper));
|
|
||||||
append(env, strings.concat("WW_LOCALBUILD_TRACE=", trace));
|
|
||||||
append(env, strings.concat("WW_LOCALBUILD_W6C=",
|
|
||||||
testenv.driver("w6c")));
|
|
||||||
let countedout: str = strings.concat(td, "/diamond-counted");
|
|
||||||
let countedav: []str = [testenv.driver("ww"), "build", "-I", treea,
|
|
||||||
"-o", countedout, main];
|
|
||||||
let counted: testenv.commandout;
|
|
||||||
testenv.runcommandenv(td, td, "diamond_compile_count", countedav,
|
|
||||||
env, tmo(), &counted);
|
|
||||||
if (counted.termination != exec.termination.EXIT || counted.code != 0) {
|
|
||||||
fail("diamond", "instrumented build failed");
|
|
||||||
};
|
|
||||||
if (testenv.occurrences(testenv.readfile(trace), "shared.unit.ww") != 1) {
|
|
||||||
fail("diamond", "shared package was not compiled exactly once");
|
|
||||||
};
|
|
||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -604,10 +567,11 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"__root.unit.ww"));
|
"__root.unit.ww"));
|
||||||
let depunit: str = testenv.readfile(strings.concat(work,
|
let depunit: str = testenv.readfile(strings.concat(work,
|
||||||
"dep.unit.ww"));
|
"dep.unit.ww"));
|
||||||
if (!testenv.has(rootunit, "//ww:module dep\n")
|
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|
||||||
|| testenv.has(rootunit, "//ww:module leaf\n")
|
|| testenv.has(rootunit, "//ww:module ")
|
||||||
|| !testenv.has(depunit, "//ww:module leaf\n")) {
|
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|
||||||
fail("library-roots", "compiler inputs crossed the direct-export boundary");
|
|| testenv.has(depunit, "//ww:module ")) {
|
||||||
|
fail("library-roots", "package units contain non-owned export text");
|
||||||
};
|
};
|
||||||
if (!testenv.exists(strings.concat(work, "leaf.wwi"))
|
if (!testenv.exists(strings.concat(work, "leaf.wwi"))
|
||||||
|| !testenv.exists(strings.concat(work, "leaf.a"))
|
|| !testenv.exists(strings.concat(work, "leaf.a"))
|
||||||
@@ -636,7 +600,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
fail("library-roots", "compiler actions were not deterministic postorder");
|
fail("library-roots", "compiler actions were not deterministic postorder");
|
||||||
};
|
};
|
||||||
if (!testenv.has(ctrace, strings.concat(
|
if (!testenv.has(ctrace, strings.concat(
|
||||||
"BEGIN<-c><-I><", work, "dep.wwi><-o><", work,
|
"BEGIN<-c><--import><leaf><", work, "leaf.wwi><-I><", work,
|
||||||
|
"dep.wwi><-o><", work,
|
||||||
"dep.s><", work, "dep.unit.ww>"))
|
"dep.s><", work, "dep.unit.ww>"))
|
||||||
|| testenv.occurrences(atrace, "\n") != 3
|
|| testenv.occurrences(atrace, "\n") != 3
|
||||||
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
|
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
|
||||||
@@ -758,7 +723,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
runav) != 42) {
|
runav) != 42) {
|
||||||
fail("library-roots", "empty override did not use default roots");
|
fail("library-roots", "empty override did not use default roots");
|
||||||
};
|
};
|
||||||
if (!testenv.has(rootunit, "//ww:module types\n")
|
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|
||||||
|
|| testenv.has(rootunit, "//ww:module ")
|
||||||
|| !testenv.exists(strings.concat(emptywork, "types.wwi"))
|
|| !testenv.exists(strings.concat(emptywork, "types.wwi"))
|
||||||
|| !testenv.exists(strings.concat(emptywork, "types.a"))
|
|| !testenv.exists(strings.concat(emptywork, "types.a"))
|
||||||
|| testenv.occurrences(ctrace, strings.concat("<", emptywork,
|
|| testenv.occurrences(ctrace, strings.concat("<", emptywork,
|
||||||
@@ -904,10 +870,11 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let depunitpath: str = strings.concat(work, "/dep.unit.ww");
|
let depunitpath: str = strings.concat(work, "/dep.unit.ww");
|
||||||
let rootunit: str = testenv.readfile(rootunitpath);
|
let rootunit: str = testenv.readfile(rootunitpath);
|
||||||
let depunit: str = testenv.readfile(depunitpath);
|
let depunit: str = testenv.readfile(depunitpath);
|
||||||
if (!testenv.has(rootunit, "//ww:module dep\n")
|
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|
||||||
|| testenv.has(rootunit, "//ww:module leaf\n")
|
|| testenv.has(rootunit, "//ww:module ")
|
||||||
|| !testenv.has(depunit, "//ww:module leaf\n")) {
|
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|
||||||
fail("driver-identity", "warm units crossed the direct-export boundary");
|
|| testenv.has(depunit, "//ww:module ")) {
|
||||||
|
fail("driver-identity", "warm units contain non-owned export text");
|
||||||
};
|
};
|
||||||
if (!testenv.exists(strings.concat(work, "/leaf.wwi"))
|
if (!testenv.exists(strings.concat(work, "/leaf.wwi"))
|
||||||
|| !testenv.exists(strings.concat(work, "/leaf.a"))
|
|| !testenv.exists(strings.concat(work, "/leaf.a"))
|
||||||
@@ -923,7 +890,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"/.wwtool.w6a")), testenv.readfile(assembler))
|
"/.wwtool.w6a")), testenv.readfile(assembler))
|
||||||
|| !testenv.same(testenv.readfile(strings.concat(work,
|
|| !testenv.same(testenv.readfile(strings.concat(work,
|
||||||
"/.wwtool.stamp")),
|
"/.wwtool.stamp")),
|
||||||
"ww workdir fmt 5 mode build asm 0\n")) {
|
"ww workdir fmt 6 mode build asm 0\n")) {
|
||||||
fail("driver-identity", "persistent artifacts or identities are incomplete");
|
fail("driver-identity", "persistent artifacts or identities are incomplete");
|
||||||
};
|
};
|
||||||
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
|
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
|
||||||
@@ -934,10 +901,12 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let coldlinker: str = testenv.readfile(linkertrace);
|
let coldlinker: str = testenv.readfile(linkertrace);
|
||||||
if (testenv.occurrences(coldcompiler, "\n") != 3
|
if (testenv.occurrences(coldcompiler, "\n") != 3
|
||||||
|| !testenv.has(coldcompiler, strings.concat(
|
|| !testenv.has(coldcompiler, strings.concat(
|
||||||
"BEGIN<-c><-I><", work, "/dep.wwi.new><-o><", work,
|
"BEGIN<-c><--import><leaf><", work, "/leaf.wwi><-I><", work,
|
||||||
|
"/dep.wwi.new><-o><", work,
|
||||||
"/dep.s.new><", work, "/dep.unit.new>"))
|
"/dep.s.new><", work, "/dep.unit.new>"))
|
||||||
|| !testenv.has(coldcompiler, strings.concat(
|
|| !testenv.has(coldcompiler, strings.concat(
|
||||||
"BEGIN<-c><-o><", work, "/__root.s.new><", work,
|
"BEGIN<-c><--import><dep><", work, "/dep.wwi><-o><", work,
|
||||||
|
"/__root.s.new><", work,
|
||||||
"/__root.unit.new>"))
|
"/__root.unit.new>"))
|
||||||
|| testenv.occurrences(coldassembler, "\n") != 3
|
|| testenv.occurrences(coldassembler, "\n") != 3
|
||||||
|| !testenv.has(coldassembler, strings.concat(
|
|| !testenv.has(coldassembler, strings.concat(
|
||||||
@@ -964,21 +933,62 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
fail("driver-identity", "cold binary returned the wrong value");
|
fail("driver-identity", "cold binary returned the wrong value");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
testenv.writefile(strings.concat(leaf, "/extra.ww"), strings.concat(
|
||||||
|
"package leaf;\n",
|
||||||
|
"export fn unchanged_api() i32 = { return 1; };\n"));
|
||||||
|
testenv.runcommandenv(cwd, td, strings.concat("driver-export-change-",
|
||||||
|
tags[si]), av, env, tmo(), &out);
|
||||||
|
if (out.termination != exec.termination.EXIT || out.code != 0
|
||||||
|
|| out.stderr.len != 0) {
|
||||||
|
fail("driver-identity", "dependency export-change build failed");
|
||||||
|
};
|
||||||
|
let changedexportcompiler: str = testenv.readfile(compilertrace);
|
||||||
|
let changedexportassembler: str = testenv.readfile(assemblertrace);
|
||||||
|
if (testenv.occurrences(changedexportcompiler, strings.concat("<", work,
|
||||||
|
"/leaf.unit.new>")) != 2
|
||||||
|
|| testenv.occurrences(changedexportcompiler, strings.concat("<", work,
|
||||||
|
"/dep.unit.new>")) != 2
|
||||||
|
|| testenv.occurrences(changedexportcompiler, strings.concat("<", work,
|
||||||
|
"/__root.unit.new>")) != 1
|
||||||
|
|| testenv.occurrences(changedexportcompiler, "\n") != 5
|
||||||
|
|| testenv.occurrences(changedexportassembler, "\n") != 5) {
|
||||||
|
fail("driver-identity", "changed export did not stop at an unchanged importer export");
|
||||||
|
};
|
||||||
|
if (code(cwd, strings.concat("driver-export-change-run-", tags[si]),
|
||||||
|
runav) != 42) {
|
||||||
|
fail("driver-identity", "export-change binary returned the wrong value");
|
||||||
|
};
|
||||||
|
let changedexportbin: str = testenv.readfile(bin);
|
||||||
|
let beforewarmcompiler: str = strings.dup(changedexportcompiler);
|
||||||
|
let beforewarmassembler: str = strings.dup(changedexportassembler);
|
||||||
|
|
||||||
testenv.runcommandenv(cwd, td, strings.concat("driver-warm-",
|
testenv.runcommandenv(cwd, td, strings.concat("driver-warm-",
|
||||||
tags[si]), av, env, tmo(), &out);
|
tags[si]), av, env, tmo(), &out);
|
||||||
if (out.termination != exec.termination.EXIT || out.code != 0
|
if (out.termination != exec.termination.EXIT || out.code != 0
|
||||||
|| out.stderr.len != 0
|
|| out.stderr.len != 0
|
||||||
|| !testenv.same(coldcompiler, testenv.readfile(compilertrace))
|
|| !testenv.same(beforewarmcompiler, testenv.readfile(compilertrace))
|
||||||
|| !testenv.same(coldassembler, testenv.readfile(assemblertrace))
|
|| !testenv.same(beforewarmassembler, testenv.readfile(assemblertrace))
|
||||||
|| testenv.occurrences(testenv.readfile(linkertrace), "\n") != 2
|
|| testenv.occurrences(testenv.readfile(linkertrace), "\n") != 3
|
||||||
|| !testenv.same(rootunit, testenv.readfile(rootunitpath))
|
|| !testenv.same(rootunit, testenv.readfile(rootunitpath))
|
||||||
|| !testenv.same(coldwwi, testenv.readfile(strings.concat(work,
|
|| !testenv.same(changedexportbin, testenv.readfile(bin))) {
|
||||||
"/dep.wwi")))
|
|
||||||
|| !testenv.same(coldarchive, testenv.readfile(strings.concat(work,
|
|
||||||
"/dep.a")))
|
|
||||||
|| !testenv.same(coldbin, testenv.readfile(bin))) {
|
|
||||||
fail("driver-identity", "unchanged warm build did not reuse packages");
|
fail("driver-identity", "unchanged warm build did not reuse packages");
|
||||||
};
|
};
|
||||||
|
assert(os.remove(strings.concat(leaf, "/extra.ww")) == 0);
|
||||||
|
testenv.runcommandenv(cwd, td, strings.concat("driver-export-restore-",
|
||||||
|
tags[si]), av, env, tmo(), &out);
|
||||||
|
if (out.termination != exec.termination.EXIT || out.code != 0
|
||||||
|
|| out.stderr.len != 0
|
||||||
|
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
|
||||||
|
"<", work, "/leaf.unit.new>")) != 3
|
||||||
|
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
|
||||||
|
"<", work, "/dep.unit.new>")) != 3
|
||||||
|
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
|
||||||
|
"<", work, "/__root.unit.new>")) != 1
|
||||||
|
|| testenv.occurrences(testenv.readfile(compilertrace), "\n") != 7
|
||||||
|
|| testenv.occurrences(testenv.readfile(assemblertrace), "\n") != 7
|
||||||
|
|| !testenv.same(coldbin, testenv.readfile(bin))) {
|
||||||
|
fail("driver-identity", "restored export did not rebuild only its direct importer");
|
||||||
|
};
|
||||||
|
|
||||||
assert(os.remove(copied[si]) == 0);
|
assert(os.remove(copied[si]) == 0);
|
||||||
testenv.writeexecutable(copied[si], strings.concat(driverbytes,
|
testenv.writeexecutable(copied[si], strings.concat(driverbytes,
|
||||||
@@ -994,14 +1004,14 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let changedassembler: str = testenv.readfile(assemblertrace);
|
let changedassembler: str = testenv.readfile(assemblertrace);
|
||||||
let changedlinker: str = testenv.readfile(linkertrace);
|
let changedlinker: str = testenv.readfile(linkertrace);
|
||||||
if (testenv.occurrences(changedcompiler, strings.concat("<", work,
|
if (testenv.occurrences(changedcompiler, strings.concat("<", work,
|
||||||
"/leaf.unit.new>")) != 2
|
"/leaf.unit.new>")) != 4
|
||||||
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
|
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
|
||||||
"/dep.unit.new>")) != 2
|
"/dep.unit.new>")) != 4
|
||||||
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
|
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
|
||||||
"/__root.unit.new>")) != 2
|
"/__root.unit.new>")) != 2
|
||||||
|| testenv.occurrences(changedcompiler, "\n") != 6
|
|| testenv.occurrences(changedcompiler, "\n") != 10
|
||||||
|| testenv.occurrences(changedassembler, "\n") != 6
|
|| testenv.occurrences(changedassembler, "\n") != 10
|
||||||
|| testenv.occurrences(changedlinker, "\n") != 3) {
|
|| testenv.occurrences(changedlinker, "\n") != 5) {
|
||||||
fail("driver-identity", "driver change reused stale package actions");
|
fail("driver-identity", "driver change reused stale package actions");
|
||||||
};
|
};
|
||||||
if (!testenv.same(testenv.readfile(strings.concat(work,
|
if (!testenv.same(testenv.readfile(strings.concat(work,
|
||||||
|
|||||||
@@ -3,26 +3,24 @@ package sepbuild_test;
|
|||||||
// `ww build` sep-driver layout observers, both stages. Ports of the
|
// `ww build` sep-driver layout observers, both stages. Ports of the
|
||||||
// retired native carriers test/wcc/989_sepbuild_run.c,
|
// retired native carriers test/wcc/989_sepbuild_run.c,
|
||||||
// 989_seproot_export_run.c, 989_sepstructdef_run.c and
|
// 989_seproot_export_run.c, 989_sepstructdef_run.c and
|
||||||
// 989_wwispread_sep.c; every assertion preserved.
|
// 989_wwispread_sep.c; assertions retained where their production boundary
|
||||||
|
// remains live.
|
||||||
//
|
//
|
||||||
// sepbuild (#46 commit-3) — build_one_sep END-TO-END on the real lib
|
// sepbuild (#46 commit-3) — build_one_sep END-TO-END on the real lib
|
||||||
// chain root -> os -> {rt,time} (transitive-closure discovery + topo):
|
// chain root -> os -> {rt,time} (transitive-closure discovery + topo):
|
||||||
// build+run exit 7 both stages; {time,rt,os}.wwi + __root.s
|
// build+run exit 7 both stages; {time,rt,os}.wwi + __root.s
|
||||||
// materialize (#69: the root is compiled without -I, so no
|
// materialize (#69: the root is compiled without -I, so no
|
||||||
// __root.wwi); per-package .s/.wwi/.unit.ww and the final binary
|
// __root.wwi); per-package .s/.wwi/.unit.ww and the final binary
|
||||||
// byte-id cs vs ww; the KEYSTONE (spec 3.1) recompiles the driver's
|
// byte-id cs vs ww; every .unit.ww is the package's own sorted source
|
||||||
// own non-leaf .unit.ww with each dep's .wwi section replaced by that
|
// set; `ww run` routes through the same sole sep path (exit 7 both
|
||||||
// dep's full directory bodies and requires byte-identical .s — the
|
|
||||||
// proof the .wwi conveys exactly the dep facts P's codegen needs;
|
|
||||||
// `ww run` routes through the same sole sep path (exit 7 both
|
|
||||||
// stages).
|
// stages).
|
||||||
//
|
//
|
||||||
// seproot (#69 BUG-1) — a ROOT whose `export fn use(a: *t)` names an
|
// seproot (#69 BUG-1) — a ROOT whose `export fn use(a: *t)` names an
|
||||||
// unexported local `type t` builds (exit 37 both stages) because the
|
// unexported local `type t` builds (exit 37 both stages) because the
|
||||||
// root is compiled WITHOUT the -I .wwi-producer flag: __root.wwi must
|
// root is compiled WITHOUT the -I .wwi-producer flag: __root.wwi must
|
||||||
// NOT exist; replaying the driver's own __root.unit.ww through
|
// NOT exist; replaying the driver's own __root.unit.ww plus c.wwi
|
||||||
// w6c/w6c_ww with -I must REJECT (the isolated bug) while -c -o alone
|
// through w6c/w6c_ww with -I must REJECT (the isolated bug) while -c
|
||||||
// must accept; __root.s carries the exported fn.
|
// -o alone must accept; __root.s carries the exported fn.
|
||||||
//
|
//
|
||||||
// sepstructdef (#70 BUG-2) — a dep exporting aggregate-init defs
|
// sepstructdef (#70 BUG-2) — a dep exporting aggregate-init defs
|
||||||
// (struct-lit + array-lit) sep-builds and links (exit 20 both
|
// (struct-lit + array-lit) sep-builds and links (exit 20 both
|
||||||
@@ -69,80 +67,6 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// A package directory's *.ww bodies (less *test.ww), byte-sorted, each
|
|
||||||
// newline-terminated — mirrors the driver's body enumeration so the
|
|
||||||
// substituted bodies-unit matches the sep-unit structurally.
|
|
||||||
fn dirbodies(dir: str) str = {
|
|
||||||
let out: str = "";
|
|
||||||
let names: []str = testenv.listdir(dir);
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < names.len) {
|
|
||||||
if (strings.hassuffix(names[i], ".ww")
|
|
||||||
&& !strings.hassuffix(names[i], "test.ww")) {
|
|
||||||
out = strings.concat(out,
|
|
||||||
testenv.readfile(strings.concat(dir, "/", names[i])),
|
|
||||||
"\n");
|
|
||||||
};
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Byte-offset borrow: strings.sub is rune-indexed, and the driver
|
|
||||||
// units embed lib comment bytes outside ASCII, so rune indices would
|
|
||||||
// mis-address the byte cursor below (readfile's borrow idiom).
|
|
||||||
fn bslice(s: str, start: i32, end: i32) str = {
|
|
||||||
assert(start <= end && end <= s.len);
|
|
||||||
let r: str;
|
|
||||||
r.ptr = s.ptr + (start: u64);
|
|
||||||
r.len = end - start;
|
|
||||||
return r;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Transform a driver sep-unit into a bodies-unit: every `//ww:module
|
|
||||||
// <path>` dep section (its .wwi content) is replaced by <path>'s full
|
|
||||||
// directory bodies (dots -> slashes under libdir); the trailing
|
|
||||||
// `//ww:module-reset` primary body is copied verbatim. The keystone's
|
|
||||||
// other arm.
|
|
||||||
fn composebodies(unit: str, libdir: str) str = {
|
|
||||||
let out: str = "";
|
|
||||||
let n: i32 = unit.len;
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < n) {
|
|
||||||
let j: i32 = i;
|
|
||||||
for (j < n && unit[j] != '\n') { j += 1; };
|
|
||||||
let line: str = bslice(unit, i, j);
|
|
||||||
if (strings.hasprefix(line, "//ww:module-reset")) {
|
|
||||||
out = strings.concat(out, bslice(unit, i, n));
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
if (strings.hasprefix(line, "//ww:module ")) {
|
|
||||||
out = strings.concat(out, line, "\n");
|
|
||||||
let path: str = bslice(line, 12, line.len);
|
|
||||||
let d: []u8 = alloc([], (path.len + 1): u64)!;
|
|
||||||
let k: i32 = 0;
|
|
||||||
for (k < path.len) {
|
|
||||||
if (path[k] == '.') { append(d, '/'); }
|
|
||||||
else { append(d, path[k]); };
|
|
||||||
k += 1;
|
|
||||||
};
|
|
||||||
out = strings.concat(out, dirbodies(strings.concat(libdir,
|
|
||||||
"/", strings.frombytes(d))));
|
|
||||||
i = j + 1;
|
|
||||||
for (i < n) {
|
|
||||||
let e: i32 = i;
|
|
||||||
for (e < n && unit[e] != '\n') { e += 1; };
|
|
||||||
if (strings.hasprefix(bslice(unit, i, e),
|
|
||||||
"//ww:module")) { break; };
|
|
||||||
i = e + 1;
|
|
||||||
};
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
i = j + 1;
|
|
||||||
};
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
@test fn sepbuild() void = {
|
@test fn sepbuild() void = {
|
||||||
let td: str = testenv.fresh();
|
let td: str = testenv.fresh();
|
||||||
let rootww: str = strings.concat(td, "/root.ww");
|
let rootww: str = strings.concat(td, "/root.ww");
|
||||||
@@ -200,34 +124,6 @@ fn composebodies(unit: str, libdir: str) str = {
|
|||||||
samefile("sepbuild", "the final binary",
|
samefile("sepbuild", "the final binary",
|
||||||
strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww"));
|
strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww"));
|
||||||
|
|
||||||
// KEYSTONE through the driver, non-leaf packages only (leaves have
|
|
||||||
// no dep sections, so their keystone is vacuous)
|
|
||||||
let libdir: str = strings.concat(testenv.repo(), "/lib");
|
|
||||||
let keypkgs: []str = ["os", "__root"];
|
|
||||||
let kp: i32 = 0;
|
|
||||||
for (kp < keypkgs.len) {
|
|
||||||
let unit: str = testenv.readfile(strings.concat(td,
|
|
||||||
"/prog.cs.sepwork/", keypkgs[kp], ".unit.ww"));
|
|
||||||
let bodiesf: str = strings.concat(td, "/", keypkgs[kp],
|
|
||||||
".bodies.ww");
|
|
||||||
testenv.writefile(bodiesf, composebodies(unit, libdir));
|
|
||||||
let bodiess: str = strings.concat(td, "/", keypkgs[kp],
|
|
||||||
".bodies.s");
|
|
||||||
let av: []str = [testenv.driver("w6c"), "-c", "-o", bodiess,
|
|
||||||
bodiesf];
|
|
||||||
if (runcode(td, strings.concat("key_", keypkgs[kp]), av) != 0) {
|
|
||||||
fail("sepbuild", strings.concat(keypkgs[kp], " bodies -c failed"));
|
|
||||||
};
|
|
||||||
if (!testenv.same(testenv.readfile(bodiess),
|
|
||||||
testenv.readfile(strings.concat(td, "/prog.cs.sepwork/",
|
|
||||||
keypkgs[kp], ".s")))) {
|
|
||||||
fail("sepbuild", strings.concat(keypkgs[kp],
|
|
||||||
" bodies.s != driver sep.s (the .wwi does not convey ",
|
|
||||||
"the dep facts P needs)"));
|
|
||||||
};
|
|
||||||
kp += 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// `ww run` routes through the sole sep path on both stages
|
// `ww run` routes through the sole sep path on both stages
|
||||||
let cav: []str = [testenv.driver("ww"), "run", rootww];
|
let cav: []str = [testenv.driver("ww"), "run", rootww];
|
||||||
let rccs: i32 = runcode(td, "run_cs", cav);
|
let rccs: i32 = runcode(td, "run_cs", cav);
|
||||||
@@ -309,19 +205,20 @@ fn composebodies(unit: str, libdir: str) str = {
|
|||||||
// with -I the export-check FIRES (the isolated bug); without it the
|
// with -I the export-check FIRES (the isolated bug); without it the
|
||||||
// post-fix invocation accepts. Both compilers.
|
// post-fix invocation accepts. Both compilers.
|
||||||
let unit: str = strings.concat(td, "/prog.cs.sepwork/__root.unit.ww");
|
let unit: str = strings.concat(td, "/prog.cs.sepwork/__root.unit.ww");
|
||||||
|
let ciface: str = strings.concat(td, "/prog.cs.sepwork/c.wwi");
|
||||||
let comps: []str = ["w6c", "w6c_ww"];
|
let comps: []str = ["w6c", "w6c_ww"];
|
||||||
let c: i32 = 0;
|
let c: i32 = 0;
|
||||||
for (c < 2) {
|
for (c < 2) {
|
||||||
let wwi: str = strings.concat(td, "/nv.", comps[c], ".wwi");
|
let wwi: str = strings.concat(td, "/nv.", comps[c], ".wwi");
|
||||||
let asmf: str = strings.concat(td, "/nv.", comps[c], ".s");
|
let asmf: str = strings.concat(td, "/nv.", comps[c], ".s");
|
||||||
let rav: []str = [testenv.driver(comps[c]), "-c", "-I", wwi,
|
let rav: []str = [testenv.driver(comps[c]), "-c", "--import", "c",
|
||||||
"-o", asmf, unit];
|
ciface, "-I", wwi, "-o", asmf, unit];
|
||||||
if (runcode(td, strings.concat("nvI_", comps[c]), rav) == 0) {
|
if (runcode(td, strings.concat("nvI_", comps[c]), rav) == 0) {
|
||||||
fail("seproot", strings.concat(comps[c], " -c -I accepted the ",
|
fail("seproot", strings.concat(comps[c], " -c -I accepted the ",
|
||||||
"root export-over-unexported-type (vacuous gate)"));
|
"root export-over-unexported-type (vacuous gate)"));
|
||||||
};
|
};
|
||||||
let aav: []str = [testenv.driver(comps[c]), "-c", "-o", asmf,
|
let aav: []str = [testenv.driver(comps[c]), "-c", "--import", "c",
|
||||||
unit];
|
ciface, "-o", asmf, unit];
|
||||||
if (runcode(td, strings.concat("nvO_", comps[c]), aav) != 0) {
|
if (runcode(td, strings.concat("nvO_", comps[c]), aav) != 0) {
|
||||||
fail("seproot", strings.concat(comps[c], " -c -o (no -I) ",
|
fail("seproot", strings.concat(comps[c], " -c -o (no -I) ",
|
||||||
"rejected the root unit (post-fix invocation)"));
|
"rejected the root unit (post-fix invocation)"));
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ package wwdump_test;
|
|||||||
// wwdump_ww's exit code is deliberately NOT gated: the diagnostics
|
// wwdump_ww's exit code is deliberately NOT gated: the diagnostics
|
||||||
// land on stderr regardless, and the armed bail flips the exit code —
|
// land on stderr regardless, and the armed bail flips the exit code —
|
||||||
// the line count is the one signal stable across the fold sequence.
|
// the line count is the one signal stable across the fold sequence.
|
||||||
// #90 sep-feed: import-bearing fixtures feed their RESOLVED sep unit
|
// #90 sep-feed: `ww build -S` resolves import-bearing fixtures to an
|
||||||
// (`ww build -S` composes <stem>.sepwork/__root.unit.ww); the
|
// owner unit and direct exports; this raw wwdump-only gate explicitly
|
||||||
|
// composes those artifacts because wwdump has no package-input CLI. The
|
||||||
// import-free test/wcc/901_*.ww companions stay raw-fed.
|
// import-free test/wcc/901_*.ww companions stay raw-fed.
|
||||||
//
|
//
|
||||||
// wwdumpgate (#52, F15 c4) — the -c and -r arms gate on parse-stage
|
// wwdumpgate (#52, F15 c4) — the -c and -r arms gate on parse-stage
|
||||||
@@ -93,11 +94,30 @@ fn countdiag(stderr: str) i32 = {
|
|||||||
fail(classes[i], strings.concat(rels[i],
|
fail(classes[i], strings.concat(rels[i],
|
||||||
": no resolved sep unit (ww build -S failed)"));
|
": no resolved sep unit (ww build -S failed)"));
|
||||||
};
|
};
|
||||||
src = strings.concat(stem, ".sepwork/__root.unit.ww");
|
let work: str = strings.concat(stem, ".sepwork/");
|
||||||
if (!testenv.exists(src)) {
|
let owner: str = strings.concat(work, "__root.unit.ww");
|
||||||
|
if (!testenv.exists(owner)) {
|
||||||
fail(classes[i], strings.concat(rels[i],
|
fail(classes[i], strings.concat(rels[i],
|
||||||
": __root.unit.ww missing after ww build -S"));
|
": __root.unit.ww missing after ww build -S"));
|
||||||
};
|
};
|
||||||
|
let deps: []str = [];
|
||||||
|
if (i == 0) { append(deps, "math.checked"); append(deps, "types"); };
|
||||||
|
if (i == 1) {
|
||||||
|
append(deps, "ascii"); append(deps, "os"); append(deps, "strconv");
|
||||||
|
};
|
||||||
|
if (i == 3) { append(deps, "fnmatch"); };
|
||||||
|
if (i == 4) { append(deps, "math.random"); append(deps, "test"); };
|
||||||
|
let composed: str = "";
|
||||||
|
let di: i32 = 0;
|
||||||
|
for (di < deps.len) {
|
||||||
|
composed = strings.concat(composed, "//ww:module ", deps[di],
|
||||||
|
"\n", testenv.readfile(strings.concat(work, deps[di],
|
||||||
|
".wwi")), "\n");
|
||||||
|
di += 1;
|
||||||
|
};
|
||||||
|
composed = strings.concat(composed, testenv.readfile(owner));
|
||||||
|
src = strings.concat(td, "/wwdump.raw.ww");
|
||||||
|
testenv.writefile(src, composed);
|
||||||
};
|
};
|
||||||
let co: testenv.commandout;
|
let co: testenv.commandout;
|
||||||
let av: []str = [testenv.driver("wwdump_ww"), "-c", src];
|
let av: []str = [testenv.driver("wwdump_ww"), "-c", src];
|
||||||
|
|||||||
Reference in New Issue
Block a user