diff --git a/cmd/ww/main.c b/cmd/ww/main.c index 514b3293..233b2736 100644 --- a/cmd/ww/main.c +++ b/cmd/ww/main.c @@ -24,7 +24,7 @@ static const char *usage = "usage: ww [-V] [args...]\n" " -V print version and exit\n" -" build [-p] [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n" +" build [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n" " run [path] ... build then exec, passing extra args to the program\n" " test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n" " version print version and exit\n" @@ -33,7 +33,7 @@ static const char *usage = " foo.ww literal file\n" " foo search cwd, -I dirs, then the source library for foo.ww or foo/\n" " lib/foo directory: build its package sources\n" -" -p emits a non-main archive FILE + FILE.wwi\n" +" -o publishes a non-main archive FILE + FILE.wwi\n" " lib/... every package under lib, recursively (test only)\n" " . build the cwd's .ww\n"; @@ -969,6 +969,17 @@ sep_command_declared_name(const struct seppkg *p) ? strcmp(p->name, "main_test") == 0 : strcmp(p->name, "main") == 0; } + +/* Directory-package action kind comes only from the loaded declaration. + * An explicit package-less file is the retained raw-unit compatibility path; + * it has no directory package declaration and remains a command unit. */ +static int +sep_root_is_command(const struct seppkg *p) +{ + if (p->name == NULL) return !p->is_dir; + return strcmp(p->name, "main") == 0; +} + static int sep_forbidden_command_import(const struct sepgraph *g, int importer, int dep) { @@ -2663,6 +2674,20 @@ copy_file_atomic(const char *src, const char *dst) return rename(tmp, dst); } +/* A package publication writes OUT, OUT.new, OUT.wwi, and OUT.wwi.new. + * Validate the longest spelling before any producer tool can run. */ +static int +validate_package_output_path(const char *out) +{ + size_t n = strlen(out); + if ((size_t)PATH_MAX < sizeof ".wwi.new" + || n > (size_t)PATH_MAX - sizeof ".wwi.new") { + fprintf(stderr, "ww: package output path is too long\n"); + return -1; + } + return 0; +} + /* A coordinator-private completion marker distinguishes a newly linked * product from a caller-owned binary left behind by an earlier invocation. */ static int @@ -2681,13 +2706,13 @@ record_product_status(const char *path) } /* The stamp pins the non-content build inputs a unit compare cannot see: - * the -T/-S shape of the producer pass and the artifact protocol + * the -T/-S/root-action shape of the producer pass and the artifact protocol * revision (bump "fmt" when the unit/archive/commit format changes). */ static void workdir_stamp_text(char *buf, size_t bufsz, int is_test, int emit_asm) { snprintf(buf, bufsz, "ww workdir fmt %d mode %s asm %d\n", - is_test ? 11 : 10, is_test ? "test" : "build", emit_asm); + is_test ? 11 : 12, is_test ? "test" : "build", emit_asm); } /* A stale global builder identity invalidates every committed unit voucher in @@ -2732,7 +2757,8 @@ invalidate_workdir_units(const char *scratch) static int build_one_sep_impl(const char *src, int entry_is_dir, const char *out, const char *objstem, const char *extra_includes, - const struct seplinkflags *linkflags, int package_only, int is_test, + const struct seplinkflags *linkflags, int publish_package, + int require_command, int is_test, struct sepproduct *products, int nproducts, int emit_asm, const char *workdir, char *scratchout, size_t scratchoutsz, struct sepgraph **graphout) @@ -2895,8 +2921,6 @@ build_one_sep_impl(const char *src, int entry_is_dir, SEP_ROLE_NORMAL, products[i].artifact, 1); if (products[i].root < 0) return 1; products[i].variant_root = products[i].root; - if (!is_test && !package_only) - g->pkg[products[i].root].link_entry = 1; } const char *test_support_module = "test"; /* -T generates a dispatcher whose support qualifier is selected by the @@ -3016,6 +3040,14 @@ build_one_sep_impl(const char *src, int entry_is_dir, } if (g->identity_failed) return 1; if (sep_finalize_directory_identities(g) < 0) return 1; + if (!is_test) { + for (int i = 0; i < nproducts; i++) { + int root = products[i].variant_root; + if (!g->pkg[root].failed) + g->pkg[root].link_entry = + sep_root_is_command(&g->pkg[root]); + } + } if (is_test && entry_is_dir) { for (int i = 0; i < nproducts; i++) { int variant = products[i].variant_root; @@ -3031,18 +3063,15 @@ build_one_sep_impl(const char *src, int entry_is_dir, products[i].root = mainpkg; } } + int root_package = !is_test + && !g->pkg[products[0].root].failed + && !sep_root_is_command(&g->pkg[products[0].root]); if (sep_validate_artifact_paths(g, scratch) < 0) return 1; if (warm && sep_validate_workdir_owners(g, scratch) < 0) return 1; if (warm && stale_all && invalidate_workdir_units(scratch) != 0) return 1; - int root_package = package_only; - if (root_package && !g->pkg[products[0].root].failed - && strcmp(g->pkg[products[0].root].name, "main") == 0) { - fprintf(stderr, "ww: -p requires a non-main package\n"); - return 1; - } int *order = calloc((size_t)g->n, sizeof *order); int *stack = calloc((size_t)g->n, sizeof *stack); int norder = 0; @@ -3065,6 +3094,23 @@ build_one_sep_impl(const char *src, int entry_is_dir, || sep_validate_module_closure(g, order, ignored, 1) < 0) g->pkg[root].failed = 1; } + if (!is_test && require_command) { + int root = products[0].root; + if (!g->pkg[root].failed + && !sep_root_is_command(&g->pkg[root])) { + fprintf(stderr, "ww: package %s is not a main package\n", + g->pkg[root].path[0] ? g->pkg[root].path + : g->pkg[root].canon); + free(stack); free(order); + return 1; + } + } + if (!g->pkg[products[0].root].failed + && root_package && publish_package && !emit_asm + && validate_package_output_path(out) < 0) { + free(stack); free(order); + return 1; + } for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0; for (int i = 0; i < nproducts; i++) { int root = products[i].root; @@ -3277,21 +3323,24 @@ build_one_sep_impl(const char *src, int entry_is_dir, if (root_package) { int root = products[0].root; if (g->pkg[root].failed) { free(order); return 1; } - char archive[SEP_ARTIFACT_MAX], iface[SEP_ARTIFACT_MAX]; - char outiface[SEP_ARTIFACT_MAX]; - sep_fname(g, root, scratch, ".a", archive, sizeof archive); - sep_fname(g, root, scratch, ".wwi", iface, sizeof iface); - int on = snprintf(outiface, sizeof outiface, "%s.wwi", out); - if (on < 0 || (size_t)on >= sizeof outiface) { - fprintf(stderr, "ww: package output path is too long\n"); - free(order); - return 1; - } - if (copy_file_atomic(archive, out) != 0 - || copy_file_atomic(iface, outiface) != 0) { - fprintf(stderr, "ww: cannot write package artifact %s\n", out); - free(order); - return 1; + if (publish_package) { + char archive[SEP_ARTIFACT_MAX], iface[SEP_ARTIFACT_MAX]; + char outiface[SEP_ARTIFACT_MAX]; + sep_fname(g, root, scratch, ".a", archive, sizeof archive); + sep_fname(g, root, scratch, ".wwi", iface, sizeof iface); + int on = snprintf(outiface, sizeof outiface, "%s.wwi", out); + if (on < 0 || (size_t)on >= sizeof outiface) { + fprintf(stderr, "ww: package output path is too long\n"); + free(order); + return 1; + } + if (copy_file_atomic(archive, out) != 0 + || copy_file_atomic(iface, outiface) != 0) { + fprintf(stderr, + "ww: cannot write package artifact %s\n", out); + free(order); + return 1; + } } free(order); return 0; @@ -3414,7 +3463,8 @@ static int build_one_sep(const char *src, int entry_is_dir, const char *root_identity, const char *out, const char *objstem, const char *extra_includes, - const struct seplinkflags *linkflags, int package_only, int is_test, + const struct seplinkflags *linkflags, int publish_package, + int require_command, int is_test, int root_variant, const char *test_package, int emit_asm, int keepscratch, const char *workdir) { @@ -3432,10 +3482,10 @@ build_one_sep(const char *src, int entry_is_dir, const char *root_identity, .variant_root = -1, .support = -1, }; - if (!package_only && !entry_is_dir) + if (!entry_is_dir) product.artifact = "__root"; int r = build_one_sep_impl(src, entry_is_dir, out, objstem, - extra_includes, linkflags, package_only, is_test, + extra_includes, linkflags, publish_package, require_command, is_test, &product, 1, emit_asm, workdir, scratch, sizeof scratch, &g); sep_graph_free(g); @@ -3477,7 +3527,7 @@ build_package_tests(const char *src, const char *root_identity, for (int i = 0; i < nproducts; i++) products[i].identity = root_identity; int r = build_one_sep_impl(src, 1, products[0].out, - products[0].out, extra_includes, NULL, 0, 1, + products[0].out, extra_includes, NULL, 0, 0, 1, products, nproducts, 0, workdir, scratch, sizeof scratch, &g); sep_graph_free(g); return r; @@ -3621,11 +3671,10 @@ parse_build_flags(const char *cmd, int argc, char **argv, struct seplinkflags *linkflags, char *outpath, size_t outsz, char *workdir, size_t workdirsz, - const char **src_out, int *emit_asm_out, int *package_out) + const char **src_out, int *emit_asm_out) { *src_out = NULL; if (emit_asm_out) *emit_asm_out = 0; - if (package_out) *package_out = 0; int i = 0; for (; i < argc; i++) { if (strcmp(argv[i], "-S") == 0) { @@ -3634,12 +3683,6 @@ parse_build_flags(const char *cmd, int argc, char **argv, return -1; } *emit_asm_out = 1; - } else if (strcmp(argv[i], "-p") == 0) { - if (package_out == NULL) { - fprintf(stderr, "ww %s: unknown flag\n", cmd); - return -1; - } - *package_out = 1; } else if (strcmp(argv[i], "-w") == 0) { if (workdir == NULL) { fprintf(stderr, "ww %s: unknown flag\n", cmd); @@ -3738,20 +3781,14 @@ do_build(int argc, char **argv) char outflag[PATH_MAX] = {0}; char workdir[PATH_MAX] = {0}; int emit_asm = 0; - int package_only = 0; if (parse_build_flags("build", argc, argv, incs, incsz, &linkflags, outflag, sizeof outflag, workdir, sizeof workdir, - &src, &emit_asm, &package_only) < 0) { + &src, &emit_asm) < 0) { free(incs); return 2; } if (src == NULL) src = "."; - if (package_only && emit_asm) { - fprintf(stderr, "ww build: -p and -S cannot be combined\n"); - free(incs); - return 2; - } struct stat requested; int literal = stat(src, &requested) == 0; char resolved[PATH_MAX]; @@ -3761,11 +3798,6 @@ do_build(int argc, char **argv) free(incs); return 1; } - if (package_only && !is_dir) { - fprintf(stderr, "ww build: -p needs a package directory\n"); - free(incs); - return 2; - } char out[PATH_MAX]; const char *objstem = NULL; if (outflag[0]) { @@ -3785,8 +3817,8 @@ do_build(int argc, char **argv) } const char *root_identity = !literal && is_dir ? src : NULL; int rc = build_one_sep(resolved, is_dir, root_identity, out, objstem, incs, - &linkflags, package_only, 0, SEP_VARIANT_PRODUCTION, NULL, emit_asm, - 1, workdir); + &linkflags, outflag[0] != '\0', 0, 0, SEP_VARIANT_PRODUCTION, NULL, + emit_asm, 1, workdir); free(incs); return rc; } @@ -3802,7 +3834,7 @@ do_run(int argc, char **argv) char outflag[PATH_MAX] = {0}; /* -o accepted+ignored: run always uses the temp */ int next = parse_build_flags("run", argc, argv, incs, incsz, &linkflags, - outflag, sizeof outflag, NULL, 0, &src, NULL, NULL); + outflag, sizeof outflag, NULL, 0, &src, NULL); if (next < 0) { free(incs); return 2; } if (src == NULL) src = "."; struct stat requested; @@ -3831,7 +3863,7 @@ do_run(int argc, char **argv) const char *root_identity = !literal && is_dir ? src : NULL; int buildrc = build_one_sep(resolved, is_dir, root_identity, tmp, tmp, incs, &linkflags, - 0, 0, SEP_VARIANT_PRODUCTION, NULL, 0, 0, NULL); + 0, 1, 0, SEP_VARIANT_PRODUCTION, NULL, 0, 0, NULL); free(incs); if (buildrc != 0) { if (unlink(tmp) != 0 && errno != ENOENT) @@ -4181,7 +4213,7 @@ do_test(int argc, char **argv) /* No-o redirects internal scratch to /tmp rather than beside the * source. An explicit -o names the caller-owned artifact stem. */ int br = build_one_sep(resolved, is_dir, NULL, outp, - outstem[0] ? outstem : tmp, incs, NULL, 0, 1, + outstem[0] ? outstem : tmp, incs, NULL, 0, 0, 1, SEP_VARIANT_PRODUCTION, NULL, emit_asm, outstem[0] ? 1 : 0, workdir); if (br != 0) { @@ -4249,7 +4281,7 @@ do_test(int argc, char **argv) } /* See module-mode note: no-o scratch is redirected to /tmp. */ int br = build_one_sep(target, 0, NULL, outp, outstem[0] ? outstem : tmp, - incs, NULL, 0, 1, SEP_VARIANT_PRODUCTION, NULL, emit_asm, + incs, NULL, 0, 0, 1, SEP_VARIANT_PRODUCTION, NULL, emit_asm, outstem[0] ? 1 : 0, workdir); if (br != 0) { if (owntmp && unlink(outp) != 0 && errno != ENOENT) diff --git a/docs/build-system.md b/docs/build-system.md index 1398d28c..55fe3a35 100644 --- a/docs/build-system.md +++ b/docs/build-system.md @@ -2843,34 +2843,78 @@ source-like `.wwi` syntax remains a transitional export encoding pending the binary `.wwe` format described above, but the separate direct-input ownership boundary is live in production Cstage and WWstage compilers and drivers. -An ordinary executable directory root is one normal package action. Its -finalized canonical import identity tags its owner-only unit; it receives only -direct exports, emits `.wwi`, `.o`, and a deterministic `.a`, and is compiled -exactly once. The declared package name validates the last component of that -identity for ordinary importable packages. A selected command root may declare -`package main`; `main` validates its executable role and never replaces or -truncates an identity such as `cmd.tool`. The narrow compiler `--entry` flag -both classifies that primary unit as a command and controls bare `main` codegen; -the package driver uses the parser-only `--command-package` marker for command -test variants that must remain ordinary archive code. Neither flag changes -export identity, and imported interfaces remain under strict leaf validation. -The linker receives that root archive first, then the complete reachable -package-archive closure and runtime archive; it never receives `.wwi`. The -linkers seed `main` before archive selection, so the existing WWAR member -protocol needs no special root object or format change. +A selected production root is one normal package action. Its finalized +canonical import identity tags its owner-only unit; it receives only direct +exports, emits `.wwi`, `.o`, and a deterministic `.a`, and is compiled exactly +once. The declared package name validates the last component of that identity +for ordinary importable packages. After loading and identity finalization, the +declaration also selects the terminal build action: `package main` is a command +and every other valid declaration is a compile-only library. A command root +receives the narrow compiler `--entry` flag, which controls bare `main` codegen, +then the linker receives that root archive first, the complete reachable +package-archive closure, and the runtime archive; it never receives `.wwi`. A +non-main root receives no `--entry` and never enters the linker. `main` validates +command kind but never replaces or truncates an identity such as `cmd.tool`. +The explicit package-less single-file compatibility path has no directory +package declaration to classify and remains a raw command unit; it does not +participate in canonical directory-package interning. +The package driver still uses the parser-only `--command-package` marker for +command test variants that must remain ordinary archive code. Neither marker +changes export identity, and imported interfaces remain under strict leaf +validation. The linkers seed `main` before archive selection, so the existing +WWAR member protocol needs no special root object or format change. -`ww build -p -o lib.a DIR` explicitly requests a non-main package product: it -emits a deterministic archive at `lib.a` and its compiler interface at -`lib.a.wwi`, without invoking the linker. A logical target retains its full -identity (`ww build -p -I ROOT -o bar.a foo.bar` emits `foo.bar.*` symbols), -while a literal directory is reverse-resolved through the active source roots -or receives the deterministic local identity described below. Its declared -leaf can never invent or truncate that identity. Package output requires a -directory and `-p` cannot be combined with assembly-only `-S`. Two cold builds -with identical inputs are required to produce byte-identical requested -products. Compiler intrinsics keep their package-mode runtime ABI independent -of transitive source interfaces (for example, `alloc` lowers to the runtime -allocator without requiring an `rt.wwi` compiler input). +Publication is separate from that semantic action choice. `ww build -o lib.a +DIR` or `ww build -I ROOT -o bar.a foo.bar` automatically publishes a non-main +root's deterministic archive and self-contained compiler export at +`FILE.wwi`, without invoking the linker; the latter retains `foo.bar.*` symbols. +Without `-o`, a non-main root and its dependencies are compiled in the selected +scratch or persistent work directory and no cwd product is invented. For a +command, `-o` continues to name the executable publication path. Output names, +request order, and whether publication was requested never enter package or +action identity. The historical action-selecting `-p` exception is removed and +rejected as an unknown build flag. Assembly-only `-S` still stops before object, +archive, publication, or link production. A literal directory is +reverse-resolved through the active source roots or receives the deterministic +local identity described below; its declared leaf can never invent or truncate +that identity. Two cold builds with identical inputs are required to produce +byte-identical requested products. Compiler intrinsics keep their package-mode +runtime ABI independent of transitive source interfaces (for example, `alloc` +lowers to the runtime allocator without requiring an `rt.wwi` compiler input). + +This rule follows the pinned official Go 1.26.5 source at commit +`c19862e5f8415b4f24b189d065ed739517c548ba`. `go/build.Package` stores source +directory, declared name, and import path independently, and defines a command +solely as a package named `main` +([`go/build/build.go`, lines 436–449](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L449), +[`go/build/build.go`, lines 514–519](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L514-L519)). +The Go builder's `AutoAction` links only `main` and returns the archive compile +action for every other package +([`cmd/go/internal/work/action.go`, lines 450–456](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L450-L456)). +The build command invents a default output only for one `main`, applies an +explicit `-o` to either AutoAction result, and otherwise builds each requested +package without conflating publication and semantic kind +([`cmd/go/internal/work/build.go`, lines 473–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L473-L478), +[`cmd/go/internal/work/build.go`, lines 508–548](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L508-L548), +[`cmd/go/internal/work/build.go`, lines 551–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L551-L558)). + +Both WW stages represent the rule with the existing loaded declaration and +stable root action index; no package, dependency, ownership, locator, traversal, +or closure allocation is added. `ww run` adds only a command-kind requirement: +a successfully loaded, cycle-free non-main root produces the deterministic +`package PATH is not a main package` diagnostic before any compiler, assembler, +or linker invocation; package and graph failures retain precedence. Before a +non-main `-o` build invokes a producer, both stages validate the longest atomic +publication spelling, `FILE.wwi.new`, so an incomplete archive/export pair is +never caused by a late path-overflow failure. Package loading, cycle detection, +and closure validation retain diagnostic precedence over this publication-only +check, and `-S` does not validate a publication path it never consumes. +Build workdir format 12 invalidates older build-mode unit vouchers before reuse +because root compiler argv changed; test workdir format 11 is unchanged because +test variants still link only their explicit generated-main action. Thereafter +an equivalent warm library build invokes no tools, a private dependency change +stops at its unchanged export, and an export change recompiles its direct +importer under the existing propagation rule. ### 11.7 Implemented directory package-test slice @@ -2939,7 +2983,7 @@ invocation, each still-unbound directory is finalized by this exact algorithm: invalidates a name inferred from a later or nested root. 3. Bind the first precedence-valid candidate from each reaching context through the command-global bidirectional interner. An identity supplied by successful - logical package lookup, such as `-p encoding.utf8`, is already bound and is + logical package lookup, such as `encoding.utf8`, is already bound and is preserved exactly. That forward-selected identity is authoritative: reverse derivation applies only to still-unbound literal roots, so a nested active root cannot rename an explicitly resolved package. diff --git a/selfhost/cmd/ww/main.ww b/selfhost/cmd/ww/main.ww index 6822b77f..c53f2322 100644 --- a/selfhost/cmd/ww/main.ww +++ b/selfhost/cmd/ww/main.ww @@ -1402,6 +1402,14 @@ fn sepcommanddeclaredname(p: *seppkg) bool = { return cstreqlit(p.name, "main"); }; +// Directory-package action kind comes only from the loaded declaration. An +// explicit package-less file is the retained raw-unit compatibility path and +// remains a command unit. +fn seprootiscommand(p: *seppkg) bool = { + if (p.name == nil) { return p.isdir == 0; }; + return cstreqlit(p.name, "main"); +}; + fn sepforbiddencommandimport(g: *sepgraph, importer: i32, dep: i32) bool = { let from: *seppkg = &g.pkg[importer]; let to: *seppkg = &g.pkg[dep]; @@ -3324,8 +3332,20 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = { return os.rename(pathstr(tmpp), pathstr(dst)); }; +// Package publication writes OUT, OUT.new, OUT.wwi, and OUT.wwi.new. Check +// the longest spelling before any producer tool can run. +fn validatepackageoutputpath(out: *u8) i32 = { + let suffix: u64 = ".wwi.new".len: u64 + 1u64; + let limit: u64 = os.PATH_MAX: u64; + if (suffix > limit || cstrlen(out) > limit - suffix) { + cerr("ww: package output path is too long\n"); + return -1; + }; + return 0; +}; + // The stamp pins the non-content build inputs a unit compare cannot see: -// the -T/-S shape of the producer pass and the artifact protocol +// the -T/-S/root-action shape of the producer pass and the artifact protocol // revision (bump "fmt" when the unit/archive/commit format changes). fn workdirstamptext(istest: i32, emitasm: i32) str = { if (istest != 0) { @@ -3335,9 +3355,9 @@ fn workdirstamptext(istest: i32, emitasm: i32) str = { return "ww workdir fmt 11 mode test asm 0\n"; }; if (emitasm != 0) { - return "ww workdir fmt 10 mode build asm 1\n"; + return "ww workdir fmt 12 mode build asm 1\n"; }; - return "ww workdir fmt 10 mode build asm 0\n"; + return "ww workdir fmt 12 mode build asm 0\n"; }; fn stampmatches(path: *u8, want: str) bool = { @@ -3444,7 +3464,7 @@ fn cerrpath(head: str, path: *u8, tail: str) void = { fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, objstem: *u8, incs: *u8, lf: *lflags, - packageonly: i32, istest: i32, + publishpackage: i32, requirecommand: i32, istest: i32, products: *sepproduct, nproducts: i32, emitasm: i32, workdir: *u8, scratchout: **u8, graphout: **sepgraph) i32 = { @@ -3663,9 +3683,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, SEP_ROLE_NORMAL, products[producti].artifact, true); if (products[producti].root < 0) { return 1; }; products[producti].variantroot = products[producti].root; - if (istest == 0 && packageonly == 0) { - g.pkg[products[producti].root].linkentry = true; - }; producti += 1; }; let testsupportmodule: str = "test"; @@ -3785,6 +3802,17 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, }; if (g.identityfailed) { return 1; }; if (sepfinalizedirectoryidentities(g) < 0) { return 1; }; + if (istest == 0) { + producti = 0; + for (producti < nproducts) { + let root: i32 = products[producti].variantroot; + if (!g.pkg[root].failed) { + g.pkg[root].linkentry = + seprootiscommand(&g.pkg[root]); + }; + producti += 1; + }; + }; if (istest != 0 && entryisdir != 0) { producti = 0; for (producti < nproducts) { @@ -3803,16 +3831,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, producti += 1; }; }; + let rootpackage: bool = istest == 0 + && !g.pkg[products[0].root].failed + && !seprootiscommand(&g.pkg[products[0].root]); if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; }; if (warm && sepvalidateworkdirowners(g, scratch) < 0) { return 1; }; if (warm && staleall && invalidateworkdirunits(scratch) != 0) { return 1; }; - let rootpackage: bool = packageonly != 0; - if (rootpackage && !g.pkg[products[0].root].failed - && cstreqlit(g.pkg[products[0].root].name, "main")) { - cerr("ww: -p requires a non-main package\n"); - return 1; - }; - let ci: i32 = 0; let order: []i32; let stack: []i32; @@ -3839,6 +3863,21 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, }; producti += 1; }; + if (istest == 0 && requirecommand != 0) { + let root: i32 = products[0].root; + if (!g.pkg[root].failed && !seprootiscommand(&g.pkg[root])) { + let identity: *u8 = g.pkg[root].canon; + if (g.pkg[root].path[0u64] != 0u8) { + identity = g.pkg[root].path; + }; + cerrpath("ww: package ", identity, + " is not a main package\n"); + return 1; + }; + }; + if (!g.pkg[products[0].root].failed + && rootpackage && publishpackage != 0 && emitasm == 0 + && validatepackageoutputpath(out) < 0) { return 1; }; ci = 0; for (ci < g.n) { g.pkg[ci].color = 0; ci += 1; }; producti = 0; @@ -4149,14 +4188,18 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, if (rootpackage) { let root: i32 = products[0].root; if (g.pkg[root].failed) { return 1; }; - let archive: *u8 = sepfname(g, root, scratch, ".a"); - let iface: *u8 = sepfname(g, root, scratch, ".wwi"); - let outiface: *u8 = sepappendlit(out, ".wwi"); - if (archive == nil || iface == nil || outiface == nil) { return 1; }; - if (copyfileatomic(archive, out) != 0 - || copyfileatomic(iface, outiface) != 0) { - cerrpath("ww: cannot write package artifact ", out, "\n"); - return 1; + if (publishpackage != 0) { + let archive: *u8 = sepfname(g, root, scratch, ".a"); + let iface: *u8 = sepfname(g, root, scratch, ".wwi"); + let outiface: *u8 = sepappendlit(out, ".wwi"); + if (archive == nil || iface == nil || outiface == nil) { + return 1; + }; + if (copyfileatomic(archive, out) != 0 + || copyfileatomic(iface, outiface) != 0) { + cerrpath("ww: cannot write package artifact ", out, "\n"); + return 1; + }; }; return 0; }; @@ -4305,7 +4348,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, // exact tree. Twin of the cstage build_one_sep wrapper. fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, rootidentity: *u8, out: *u8, - objstem: *u8, incs: *u8, lf: *lflags, packageonly: i32, istest: i32, + objstem: *u8, incs: *u8, lf: *lflags, publishpackage: i32, + requirecommand: i32, istest: i32, rootvariant: i32, testpackage: *u8, emitasm: i32, keepscratch: i32, workdir: *u8) i32 = { let scratch: *u8 = nil; @@ -4317,7 +4361,7 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, product.testpackage = testpackage; product.status = nil; product.artifact = nil; - if (packageonly == 0 && entryisdir == 0) { + if (entryisdir == 0) { product.artifact = "__root\0".ptr; }; product.variant = rootvariant; @@ -4325,7 +4369,7 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, product.variantroot = -1; product.support = -1; let r: i32 = buildonesepimpl(selfdir, src, entryisdir, out, objstem, - incs, lf, packageonly, istest, &product, 1, + incs, lf, publishpackage, requirecommand, istest, &product, 1, emitasm, workdir, &scratch, &g); sepgraphfree(g); if (keepscratch == 0 && scratch != nil) { @@ -4367,7 +4411,7 @@ fn buildpackagetests(selfdir: *u8, src: *u8, rootidentity: *u8, i += 1; }; let r: i32 = buildonesepimpl(selfdir, src, 1, - products[0].out, products[0].out, incs, &lf, 0, 1, + products[0].out, products[0].out, incs, &lf, 0, 0, 1, products, nproducts, 0, workdir, &scratch, &g); sepgraphfree(g); return r; @@ -4464,7 +4508,7 @@ fn resolvemodule(selfdir: *u8, name: *u8, incs: *u8, isdir: *i32) *u8 = { }; fn writeusage(fd: i32) void = { - let s: str = "usage: ww [-V] [args...]\n -V print version and exit\n build [-p] [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then the source library for foo.ww or foo/\n lib/foo directory: build its package sources\n -p emits a non-main archive FILE + FILE.wwi\n lib/... every package under lib, recursively (test only)\n . build the cwd's .ww\n"; + let s: str = "usage: ww [-V] [args...]\n -V print version and exit\n build [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then the source library for foo.ww or foo/\n lib/foo directory: build its package sources\n -o publishes a non-main archive FILE + FILE.wwi\n lib/... every package under lib, recursively (test only)\n . build the cwd's .ww\n"; os.write(fd, s.ptr, s.len: u64); }; @@ -4508,7 +4552,6 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let outflag: *u8 = nil; // -o target (binary + intermediate stem); T3 let workdir: *u8 = nil; // -w persistent package-artifact workdir let emitasm: i32 = 0; - let packageonly: i32 = 0; let inccap: u64 = 1u64; let capi: i32 = start; for (capi < argc) { @@ -4535,8 +4578,6 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { if (p[0u64] == 45u8) { // '-' if (cstreqlit(p, "-S")) { emitasm = 1; - } else { if (cstreqlit(p, "-p")) { - packageonly = 1; } else { if (p[1u64] == 73u8) { // '-I' let dir: *u8 = nil; if (p[2u64] != 0u8) { @@ -4616,7 +4657,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { } else { cerr("ww build: unknown flag\n"); return 2; - }; }; }; }; }; }; }; + }; }; }; }; }; }; } else { if (src == nil) { src = p; }; }; @@ -4627,10 +4668,6 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { let dot: [2]u8 = ['.': u8, 0u8]; src = &dot[0]; }; - if (packageonly != 0 && emitasm != 0) { - cerr("ww build: -p and -S cannot be combined\n"); - return 2; - }; let requestedliteral: bool = false; let requestedstat: os.filestat; match (os.stat(&requestedstat, pathstr(src))) { @@ -4643,13 +4680,9 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { cerrpath("ww build: cannot find module ", src, "\n"); return 1; }; - if (packageonly != 0 && isdir == 0) { - cerr("ww build: -p needs a package directory\n"); - return 2; - }; let out: *u8 = nil; let objstem: *u8 = nil; - if (outflag != nil) { + if (outflag != nil && outflag[0u64] != 0u8) { // -o sets both the binary path and the intermediate stem so // artifacts land beside the requested output (T3). out = outflag; @@ -4678,9 +4711,11 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { lf.nlibs = nlibs; let rootidentity: *u8 = nil; if (!requestedliteral && isdir != 0) { rootidentity = src; }; + let publishpackage: i32 = 0; + if (outflag != nil && outflag[0u64] != 0u8) { publishpackage = 1; }; return buildonesep(selfdir, resolved, isdir, rootidentity, out, objstem, incs.ptr, &lf, - packageonly, 0i32, SEP_VARIANT_PRODUCTION, nil, + publishpackage, 0i32, 0i32, SEP_VARIANT_PRODUCTION, nil, emitasm, 1i32, workdir); }; @@ -4862,7 +4897,8 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = { if (!requestedliteral && isdir != 0) { rootidentity = src; }; if (buildonesep(selfdir, resolved, isdir, rootidentity, outp, outp, incs.ptr, &lf, - 0i32, 0i32, SEP_VARIANT_PRODUCTION, nil, 0i32, 0i32, nil) != 0) { + 0i32, 1i32, 0i32, SEP_VARIANT_PRODUCTION, nil, + 0i32, 0i32, nil) != 0) { let cleanrc: i32 = os.remove(pathstr(outp)); if (cleanrc != 0 && cleanrc != -2i32) { cerr("ww: cannot remove temporary output\n"); @@ -4952,7 +4988,8 @@ fn runsingletest(selfdir: *u8, src: *u8, incs: *u8, compileonly: i32, let keep: i32 = 0; if (outstem != nil) { keep = 1; }; let bres: i32 = buildonesep(selfdir, src, 0, nil, outp, objstem, incs, &lf, - 0i32, 1i32, SEP_VARIANT_PRODUCTION, nil, emitasm, keep, workdir); + 0i32, 0i32, 1i32, SEP_VARIANT_PRODUCTION, nil, + emitasm, keep, workdir); if (bres != 0) { if (owntmp) { let cleanrc: i32 = os.remove(pathstr(outp)); diff --git a/test/package/package_test.ww b/test/package/package_test.ww index b4238a7d..0508e4e9 100644 --- a/test/package/package_test.ww +++ b/test/package/package_test.ww @@ -984,7 +984,7 @@ fn mkdirall(path: str) void = { " assert(pkg.second() == 9);\n};\n")); let prodout: str = strings.concat(root, "/production.a"); - let prodav: []str = [driver("ww"), "build", "-p", "-I", root, + let prodav: []str = [driver("ww"), "build", "-I", root, "-o", prodout, pkg]; let out: commandout; runcommand(root, "production-build", prodav, @@ -2094,7 +2094,7 @@ fn mkdirall(path: str) void = { if (rsi == 1) { uniondriver = wwtracedriver; }; let rootout: str = strings.concat(root, "/root-only-", rootstages[rsi], ".a"); - let rootav: []str = [driver(rootstages[rsi]), "build", "-p", + let rootav: []str = [driver(rootstages[rsi]), "build", "-I", root, "-o", rootout, aaroot]; runcommand(root, strings.concat("root-only-", rootstages[rsi]), rootav, (60i64 * (time.second: i64)): time.duration, &out); @@ -3942,7 +3942,7 @@ fn mkdirall(path: str) void = { let rootout: str = strings.concat(root, "/long-root-", rootlabels[ri], "-", tags[si], ".a"); clean(compilertrace); writefile(compilertrace, ""); - let rootav: []str = [driver(stages[si]), "build", "-p", "-I", + let rootav: []str = [driver(stages[si]), "build", "-I", source, "-o", rootout, rootspellings[ri]]; runcommandenv(root, strings.concat("long-root-", rootlabels[ri], "-", tags[si]), rootav, env, @@ -4232,7 +4232,7 @@ fn mkdirall(path: str) void = { clean(trace); writefile(trace, ""); let importout: str = strings.concat(root, "/importer-", stages[si], ".a"); - let importav: []str = [driver(stages[si]), "build", "-p", "-I", source, + let importav: []str = [driver(stages[si]), "build", "-I", source, "-o", importout, importer]; runcommandenv(root, strings.concat("command-import-", stages[si]), importav, env, (60i64 * (time.second: i64)): time.duration, &out); @@ -4351,7 +4351,7 @@ fn mkdirall(path: str) void = { let identitydiagnostics: []str = ["", ""]; i = 0; for (i < stages.len) { - let av: []str = [driver(stages[i]), "build", "-p", "-I", root, + let av: []str = [driver(stages[i]), "build", "-I", root, "-o", strings.concat(root, "/bad-identity-", stages[i], ".a"), identityroot]; runcommandenv(root, strings.concat("duplicate-directory-identity-", @@ -4372,7 +4372,7 @@ fn mkdirall(path: str) void = { let reserveddiagnostics: []str = ["", ""]; i = 0; for (i < stages.len) { - let av: []str = [driver(stages[i]), "build", "-p", "-I", root, + let av: []str = [driver(stages[i]), "build", "-I", root, "-o", strings.concat(root, "/bad-reserved-", stages[i], ".a"), reserved]; runcommandenv(root, strings.concat("reserved-local-import-", stages[i]), @@ -4843,7 +4843,7 @@ fn runtimepath(relative: str) str = { writefile(strings.concat(extra, "/extra.ww"), "package extra;\nexport fn marker() i32 = { return 7; };\n"); let extralib: str = strings.concat(root, "/libextra.a"); - let libav: []str = [driver("ww"), "build", "-p", "-o", extralib, + let libav: []str = [driver("ww"), "build", "-o", extralib, extra]; let out: commandout; runcommand(root, "link-flags-library", libav, diff --git a/test/sep/importdir_test.ww b/test/sep/importdir_test.ww index a65bd86e..ce71938a 100644 --- a/test/sep/importdir_test.ww +++ b/test/sep/importdir_test.ww @@ -150,7 +150,7 @@ fn samefile(a: str, b: str, why: str) void = { "late/example/foo", "late/example/foo", fooalias, fooalias]; i = 0; for (i < rootouts.len) { - let rav: []str = [testenv.driver(rootdrivers[i]), "build", "-p", + let rav: []str = [testenv.driver(rootdrivers[i]), "build", "-I", early, "-I", late, "-o", rootouts[i], roottargets[i]]; expectcode(td, strings.concat("foo_root_", roottags[i]), rav, 0); let rw: str = strings.concat(rootouts[i], ".sepwork/"); diff --git a/test/sep/localbuild_test.ww b/test/sep/localbuild_test.ww index f2694ad9..efe94d04 100644 --- a/test/sep/localbuild_test.ww +++ b/test/sep/localbuild_test.ww @@ -166,9 +166,9 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = { "fn hidden() i32 = { return 99; };\n")); let ca: str = strings.concat(td, "/libonly-c.a"); let wa: str = strings.concat(td, "/libonly-w.a"); - let cav: []str = [testenv.driver("ww"), "build", "-p", "-I", td, + let cav: []str = [testenv.driver("ww"), "build", "-I", td, "-o", ca, lib]; - let wav: []str = [testenv.driver("ww_ww"), "build", "-p", "-I", td, + let wav: []str = [testenv.driver("ww_ww"), "build", "-I", td, "-o", wa, lib]; if (code(td, "build_package_c", cav) != 0 || code(td, "build_package_w", wav) != 0) { @@ -302,10 +302,10 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = { strings.concat(td, "/api-c2.a"), strings.concat(td, "/api-w.a")]; i = 0; for (i < packages.len) { - let pav: []str = [testenv.driver(drivers[i]), "build", "-p", "-I", td, + let pav: []str = [testenv.driver(drivers[i]), "build", "-I", td, "-o", packages[i], api]; if (code(td, strings.concat("package_", tags[i]), pav) != 0) { - fail("self-contained", "ww build -p api failed"); + fail("self-contained", "ww build api failed"); }; i += 1; }; @@ -907,7 +907,7 @@ fn writediamond(td: str, reverse: bool) str = { "/.wwtool.w6a")), testenv.readfile(assembler)) || !testenv.same(testenv.readfile(strings.concat(work, "/.wwtool.stamp")), - "ww workdir fmt 10 mode build asm 0\n")) { + "ww workdir fmt 12 mode build asm 0\n")) { fail("driver-identity", "persistent artifacts or identities are incomplete"); }; let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi")); @@ -1224,9 +1224,9 @@ fn writediamond(td: str, reverse: bool) str = { "export fn nestedvalue() i32 = { return 41; };\n")); let ca: str = strings.concat(td, "/nested-c.a"); let wa: str = strings.concat(td, "/nested-w.a"); - let cav: []str = [testenv.driver("ww"), "build", "-p", "-I", root, + let cav: []str = [testenv.driver("ww"), "build", "-I", root, "-o", ca, "foo.bar"]; - let wav: []str = [testenv.driver("ww_ww"), "build", "-p", "-I", root, + let wav: []str = [testenv.driver("ww_ww"), "build", "-I", root, "-o", wa, "foo.bar"]; if (code(td, "nested_package_c", cav) != 0 || code(td, "nested_package_w", wav) != 0) { @@ -1247,22 +1247,575 @@ fn writediamond(td: str, reverse: bool) str = { let i: i32 = 0; for (i < drivers.len) { let badout: str = strings.concat(td, "/bad-flags-", drivers[i]); - let av: []str = [testenv.driver(drivers[i]), "build", "-p", "-S", + let av: []str = [testenv.driver(drivers[i]), "build", "-p", "-I", root, "-o", badout, "foo.bar"]; let co: testenv.commandout; command(td, strings.concat("package_flag_contract_", drivers[i]), av, &co); if (co.termination != exec.termination.EXIT || co.code == 0 - || !testenv.has(co.stderr, - "ww build: -p and -S cannot be combined")) { + || !testenv.has(co.stderr, "ww build: unknown flag")) { fail("package-flags", strings.concat(drivers[i], - " accepted -p -S")); + " accepted the removed package-action flag")); }; i += 1; }; testenv.clean(td); }; +@test fn package_kind_selects_build_action() void = { + let td: str = testenv.fresh(); + let source: str = strings.concat(td, "/source"); + let foo: str = strings.concat(source, "/foo"); + let dep: str = strings.concat(foo, "/dep"); + let bar: str = strings.concat(foo, "/bar"); + let commanddir: str = strings.concat(foo, "/cmd"); + let cyclea: str = strings.concat(foo, "/cyclea"); + let cycleb: str = strings.concat(foo, "/cycleb"); + let tools: str = strings.concat(td, "/tools"); + mkdir(source); mkdir(foo); mkdir(dep); mkdir(bar); mkdir(commanddir); + mkdir(cyclea); mkdir(cycleb); mkdir(tools); + let depsrc: str = strings.concat(dep, "/dep.ww"); + let depbase: str = strings.concat( + "package dep;\n", + "// DEP_SOURCE\n", + "fn hidden() i32 = { return 40; };\n", + "export fn value() i32 = { return hidden(); };\n"); + let depprivate: str = strings.concat( + "package dep;\n", + "// DEP_SOURCE\n", + "fn hidden() i32 = { return 41; };\n", + "export fn value() i32 = { return hidden(); };\n"); + let depexported: str = strings.concat(depprivate, + "export fn additional() i32 = { return 1; };\n"); + testenv.writefile(depsrc, depbase); + testenv.writefile(strings.concat(bar, "/a.ww"), strings.concat( + "package bar;\nimport foo.dep;\n", + "// ROOT_A\n", + "export fn value() i32 = { return dep.value() + 2; };\n")); + testenv.writefile(strings.concat(bar, "/z.ww"), strings.concat( + "package bar;\nimport foo.dep;\n", + "// ROOT_Z\n", + "export fn other() i32 = { return 9; };\n")); + testenv.writefile(strings.concat(commanddir, "/main.ww"), strings.concat( + "package main;\nimport foo.bar;\n", + "// COMMAND_OWNER\n", + "fn main() i32 = { return bar.value(); };\n")); + testenv.writefile(strings.concat(cyclea, "/a.ww"), strings.concat( + "package cyclea;\nimport foo.cycleb;\n", + "export fn value() i32 = { return cycleb.value(); };\n")); + testenv.writefile(strings.concat(cycleb, "/b.ww"), strings.concat( + "package cycleb;\nimport foo.cyclea;\n", + "export fn value() i32 = { return cyclea.value(); };\n")); + + let compiler: str = strings.concat(tools, "/w6c.sh"); + let assembler: str = strings.concat(tools, "/w6a.sh"); + let linker: str = strings.concat(tools, "/w6l.sh"); + testenv.writeexecutable(compiler, strings.concat( + "#!/bin/sh\n", + "printf 'BEGIN' >> \"$WW_ROOT_COMPILER_TRACE\"\n", + "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", + "\"$WW_ROOT_COMPILER_TRACE\"; done\n", + "printf '\\n' >> \"$WW_ROOT_COMPILER_TRACE\"\n", + "exec \"$WW_ROOT_REAL_COMPILER\" \"$@\"\n")); + testenv.writeexecutable(assembler, strings.concat( + "#!/bin/sh\n", + "printf 'BEGIN' >> \"$WW_ROOT_ASSEMBLER_TRACE\"\n", + "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", + "\"$WW_ROOT_ASSEMBLER_TRACE\"; done\n", + "printf '\\n' >> \"$WW_ROOT_ASSEMBLER_TRACE\"\n", + "exec \"$WW_ROOT_REAL_ASSEMBLER\" \"$@\"\n")); + testenv.writeexecutable(linker, strings.concat( + "#!/bin/sh\n", + "printf 'BEGIN' >> \"$WW_ROOT_LINKER_TRACE\"\n", + "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", + "\"$WW_ROOT_LINKER_TRACE\"; done\n", + "printf '\\n' >> \"$WW_ROOT_LINKER_TRACE\"\n", + "exec \"$WW_ROOT_REAL_LINKER\" \"$@\"\n")); + + let stages: []str = ["ww", "ww_ww"]; + let compilers: []str = ["w6c", "w6c_ww"]; + let assemblers: []str = ["w6a", "w6a_ww"]; + let linkers: []str = ["w6l", "w6l_ww"]; + let tags: []str = ["c", "ww"]; + let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; + let rootreference: []str = ["", "", "", "", ""]; + let depreference: []str = ["", "", "", "", ""]; + let commandreference: []str = ["", "", "", "", ""]; + let nooutrootreference: []str = ["", "", "", "", ""]; + let nooutdepreference: []str = ["", "", "", "", ""]; + let publishreference: str = ""; + let exportreference: str = ""; + let binaryreference: str = ""; + let diagnosticreference: str = ""; + let cyclediagreference: str = ""; + let cyclepathdiagreference: str = ""; + let pathdiagreference: str = ""; + let runtime: str = strings.concat(testenv.repo(), "/out/lib"); + let si: i32 = 0; + for (si < stages.len) { + let work: str = strings.concat(td, "/work-", tags[si]); + let outpath: str = strings.concat(td, "/libbar-", tags[si], ".a"); + let compilertrace: str = strings.concat(td, "/compiler-", tags[si]); + let assemblertrace: str = strings.concat(td, "/assembler-", tags[si]); + let linkertrace: str = strings.concat(td, "/linker-", tags[si]); + mkdir(work); + testenv.writefile(compilertrace, ""); + testenv.writefile(assemblertrace, ""); + testenv.writefile(linkertrace, ""); + let env: []str = roottraceenv(source, runtime, + compiler, assembler, linker, + compilertrace, assemblertrace, linkertrace, + testenv.driver(compilers[si]), + testenv.driver(assemblers[si]), + testenv.driver(linkers[si])); + let av: []str = [testenv.driver(stages[si]), "build", + "-w", work, "-I", source, "-o", outpath, "foo.bar"]; + let out: testenv.commandout; + testenv.runcommandenv(td, td, strings.concat("auto-cold-", tags[si]), + av, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0) { + fail("package-autoaction", strings.concat(tags[si], + " cold library build failed: ", out.stderr)); + }; + let ctrace: str = testenv.readfile(compilertrace); + let atrace: str = testenv.readfile(assemblertrace); + let wantcompiler: str = strings.concat( + "BEGIN<-c><-I><", work, + "/foo.dep.wwi.new><-o><", work, + "/foo.dep.s.new><", work, "/foo.dep.unit.new>\n", + "BEGIN<-c><--import><", work, + "/foo.dep.wwi><-I><", work, + "/foo.bar.wwi.new><-o><", work, + "/foo.bar.s.new><", work, "/foo.bar.unit.new>\n"); + let wantassembler: str = strings.concat( + "BEGIN<-o><", work, "/foo.dep.o.new><", work, + "/foo.dep.s.new>\n", + "BEGIN<-o><", work, "/foo.bar.o.new><", work, + "/foo.bar.s.new>\n"); + if (!testenv.same(ctrace, wantcompiler) + || !testenv.same(atrace, wantassembler) + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + "library action tool arguments are not compile-only/direct"); + }; + let rootunit: str = testenv.readfile(strings.concat(work, + "/foo.bar.unit.ww")); + if (testenv.pos(rootunit, "// ROOT_A") < 0 + || testenv.pos(rootunit, "// ROOT_Z") + <= testenv.pos(rootunit, "// ROOT_A") + || testenv.has(rootunit, "DEP_SOURCE") + || testenv.occurrences(rootunit, + "//ww:module-reset foo.bar\n") != 2) { + fail("package-autoaction", + "library unit is not owner-only and byte-sorted"); + }; + if (!testenv.exists(outpath) + || !testenv.exists(strings.concat(outpath, ".wwi")) + || !testenv.same(testenv.readfile(outpath), + testenv.readfile(strings.concat(work, "/foo.bar.a"))) + || !testenv.same(testenv.readfile(strings.concat(outpath, ".wwi")), + testenv.readfile(strings.concat(work, "/foo.bar.wwi")))) { + fail("package-autoaction", "explicit package publication changed bytes"); + }; + let ai: i32 = 0; + for (ai < suffixes.len) { + let rootbytes: str = testenv.readfile(strings.concat(work, + "/foo.bar", suffixes[ai])); + let depbytes: str = testenv.readfile(strings.concat(work, + "/foo.dep", suffixes[ai])); + if (si == 0) { + rootreference[ai] = strings.dup(rootbytes); + depreference[ai] = strings.dup(depbytes); + } else { if (!testenv.same(rootreference[ai], rootbytes) + || !testenv.same(depreference[ai], depbytes)) { + fail("package-autoaction", + "Cstage and WWstage package artifacts differ"); + }; }; + ai += 1; + }; + if (si == 0) { + publishreference = strings.dup(testenv.readfile(outpath)); + exportreference = strings.dup(testenv.readfile(strings.concat( + outpath, ".wwi"))); + } else { if (!testenv.same(publishreference, + testenv.readfile(outpath)) || !testenv.same(exportreference, + testenv.readfile(strings.concat(outpath, ".wwi")))) { + fail("package-autoaction", "published stage artifacts differ"); + }; }; + + // The other AutoAction half remains declaration-selected: package main + // alone receives --entry and its complete archive-only link closure. + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let commandwork: str = strings.concat(td, "/command-work-", tags[si]); + let commandbin: str = strings.concat(td, "/command-", tags[si]); + mkdir(commandwork); + let commandav: []str = [testenv.driver(stages[si]), "build", + "-w", commandwork, "-I", source, "-o", commandbin, "foo.cmd"]; + testenv.runcommandenv(td, td, strings.concat("auto-command-", tags[si]), + commandav, env, tmo(), &out); + ctrace = testenv.readfile(compilertrace); + atrace = testenv.readfile(assemblertrace); + let commandlink: str = testenv.readfile(linkertrace); + let wantcommandcompiler: str = strings.concat( + "BEGIN<-c><-I><", commandwork, + "/foo.dep.wwi.new><-o><", commandwork, + "/foo.dep.s.new><", commandwork, "/foo.dep.unit.new>\n", + "BEGIN<-c><--import><", commandwork, + "/foo.dep.wwi><-I><", commandwork, + "/foo.bar.wwi.new><-o><", commandwork, + "/foo.bar.s.new><", commandwork, "/foo.bar.unit.new>\n", + "BEGIN<--entry><-c><--import><", commandwork, + "/foo.bar.wwi><-I><", commandwork, + "/foo.cmd.wwi.new><-o><", commandwork, + "/foo.cmd.s.new><", commandwork, "/foo.cmd.unit.new>\n"); + let wantcommandassembler: str = strings.concat( + "BEGIN<-o><", commandwork, "/foo.dep.o.new><", commandwork, + "/foo.dep.s.new>\n", + "BEGIN<-o><", commandwork, "/foo.bar.o.new><", commandwork, + "/foo.bar.s.new>\n", + "BEGIN<-o><", commandwork, "/foo.cmd.o.new><", commandwork, + "/foo.cmd.s.new>\n"); + let wantcommandlink: str = strings.concat("BEGIN<-o><", commandbin, + "><", commandwork, "/foo.cmd.a><", commandwork, + "/foo.bar.a><", commandwork, "/foo.dep.a><", runtime, + "/libwwrt.a>\n"); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 + || !testenv.same(ctrace, wantcommandcompiler) + || !testenv.same(atrace, wantcommandassembler) + || !testenv.same(commandlink, wantcommandlink) + || testenv.has(commandlink, ".wwi>")) { + fail("package-autoaction", + "main action arguments or archive closure changed"); + }; + let commandunit: str = testenv.readfile(strings.concat(commandwork, + "/foo.cmd.unit.ww")); + if (!testenv.has(commandunit, "// COMMAND_OWNER") + || testenv.has(commandunit, "// ROOT_A") + || testenv.has(commandunit, "// DEP_SOURCE")) { + fail("package-autoaction", "command unit contains foreign sources"); + }; + ai = 0; + for (ai < suffixes.len) { + let commandbytes: str = testenv.readfile(strings.concat(commandwork, + "/foo.cmd", suffixes[ai])); + if (si == 0) { commandreference[ai] = strings.dup(commandbytes); } + else { if (!testenv.same(commandreference[ai], commandbytes)) { + fail("package-autoaction", + "Cstage and WWstage command artifacts differ"); + }; }; + ai += 1; + }; + let commandrun: []str = [commandbin]; + if (code(td, strings.concat("auto-command-run-", tags[si]), + commandrun) != 42) { + fail("package-autoaction", "main action binary returned wrong value"); + }; + // The public run command must make the same declaration-driven choice; + // its private temp paths make exact argv intentionally inapplicable here. + let drivercommandrun: []str = [testenv.driver(stages[si]), "run", + "-I", source, "foo.cmd"]; + testenv.runcommand(td, td, strings.concat("auto-driver-command-run-", + tags[si]), drivercommandrun, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 42 + || out.stdout.len != 0 || out.stderr.len != 0) { + fail("package-autoaction", "ww run rejected or misran package main"); + }; + if (si == 0) { + binaryreference = strings.dup(testenv.readfile(commandbin)); + } else { if (!testenv.same(binaryreference, + testenv.readfile(commandbin))) { + fail("package-autoaction", "linked stage binaries differ"); + }; }; + + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let nooutwork: str = strings.concat(td, "/no-output-work-", tags[si]); + mkdir(nooutwork); + let noout: []str = [testenv.driver(stages[si]), "build", + "-w", nooutwork, "-I", source, "foo.bar"]; + testenv.runcommandenv(td, td, strings.concat("auto-no-output-", tags[si]), + noout, env, tmo(), &out); + ctrace = testenv.readfile(compilertrace); + atrace = testenv.readfile(assemblertrace); + let wantnooutcompiler: str = strings.concat( + "BEGIN<-c><-I><", nooutwork, + "/foo.dep.wwi.new><-o><", nooutwork, + "/foo.dep.s.new><", nooutwork, "/foo.dep.unit.new>\n", + "BEGIN<-c><--import><", nooutwork, + "/foo.dep.wwi><-I><", nooutwork, + "/foo.bar.wwi.new><-o><", nooutwork, + "/foo.bar.s.new><", nooutwork, "/foo.bar.unit.new>\n"); + let wantnooutassembler: str = strings.concat( + "BEGIN<-o><", nooutwork, "/foo.dep.o.new><", nooutwork, + "/foo.dep.s.new>\n", + "BEGIN<-o><", nooutwork, "/foo.bar.o.new><", nooutwork, + "/foo.bar.s.new>\n"); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 || testenv.exists(strings.concat(td, "/bar")) + || !testenv.same(ctrace, wantnooutcompiler) + || !testenv.same(atrace, wantnooutassembler) + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + "cold no-output library build did not remain compile-only"); + }; + ai = 0; + for (ai < suffixes.len) { + let nooutroot: str = testenv.readfile(strings.concat(nooutwork, + "/foo.bar", suffixes[ai])); + let nooutdep: str = testenv.readfile(strings.concat(nooutwork, + "/foo.dep", suffixes[ai])); + if (!testenv.same(nooutroot, rootreference[ai]) + || !testenv.same(nooutdep, depreference[ai])) { + fail("package-autoaction", + "publication request changed package artifact bytes"); + }; + if (si == 0) { + nooutrootreference[ai] = strings.dup(nooutroot); + nooutdepreference[ai] = strings.dup(nooutdep); + } else { if (!testenv.same(nooutrootreference[ai], nooutroot) + || !testenv.same(nooutdepreference[ai], nooutdep)) { + fail("package-autoaction", + "cold no-output artifacts differ by stage"); + }; }; + ai += 1; + }; + // An explicitly empty -o is observably the same no-publication request + // in both drivers and therefore reuses the same semantic actions. + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let emptyout: []str = [testenv.driver(stages[si]), "build", + "-w", nooutwork, "-I", source, "-o", "", "foo.bar"]; + testenv.runcommandenv(td, td, strings.concat("auto-empty-output-", + tags[si]), emptyout, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + "empty -o changed no-publication action semantics"); + }; + + // Publication is not semantic action identity: an already-populated + // package workdir is reusable when the next request omits -o. + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let warmnoout: []str = [testenv.driver(stages[si]), "build", + "-w", work, "-I", source, "foo.bar"]; + testenv.runcommandenv(td, td, strings.concat("auto-warm-no-output-", + tags[si]), warmnoout, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + "publication request entered persistent action identity"); + }; + + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let pathwork: str = strings.concat(td, "/path-work-", tags[si]); + mkdir(pathwork); + let longout: str = strings.concat(td, "/"); + for (longout.len < 4090) { longout = strings.concat(longout, "x"); }; + let pathav: []str = [testenv.driver(stages[si]), "build", + "-w", pathwork, "-I", source, "-o", longout, "foo.bar"]; + testenv.runcommandenv(td, td, strings.concat("auto-output-path-", tags[si]), + pathav, env, tmo(), &out); + let wantpathdiag: str = "ww: package output path is too long\n"; + if (out.termination != exec.termination.EXIT || out.code != 1 + || !testenv.same(out.stderr, wantpathdiag) + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0 + || testenv.exists(strings.concat(pathwork, "/foo.dep.unit.ww")) + || testenv.exists(strings.concat(pathwork, "/foo.bar.unit.ww"))) { + fail("package-autoaction", + "package publication path failed after the tool boundary"); + }; + if (si == 0) { pathdiagreference = strings.dup(out.stderr); } + else { if (!testenv.same(pathdiagreference, out.stderr)) { + fail("package-autoaction", "output path diagnostics differ by stage"); + }; }; + + // Output publication is unused under -S, so even this spelling must not + // participate in an assembly-only action or its failure behavior. + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let asmwork: str = strings.concat(td, "/asm-work-", tags[si]); + mkdir(asmwork); + let asmav: []str = [testenv.driver(stages[si]), "build", "-S", + "-w", asmwork, "-I", source, "-o", longout, "foo.bar"]; + testenv.runcommandenv(td, td, strings.concat("auto-asm-long-output-", + tags[si]), asmav, env, tmo(), &out); + let wantasmcompiler: str = strings.concat( + "BEGIN<-c><-I><", asmwork, + "/foo.dep.wwi.new><-o><", asmwork, + "/foo.dep.s.new><", asmwork, "/foo.dep.unit.new>\n", + "BEGIN<-c><--import><", asmwork, + "/foo.dep.wwi><-I><", asmwork, + "/foo.bar.wwi.new><-o><", asmwork, + "/foo.bar.s.new><", asmwork, "/foo.bar.unit.new>\n"); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 + || !testenv.same(testenv.readfile(compilertrace), wantasmcompiler) + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0 + || testenv.exists(strings.concat(asmwork, "/foo.dep.o")) + || testenv.exists(strings.concat(asmwork, "/foo.dep.a")) + || testenv.exists(strings.concat(asmwork, "/foo.bar.o")) + || testenv.exists(strings.concat(asmwork, "/foo.bar.a"))) { + fail("package-autoaction", + "assembly-only action consumed an unused publication path"); + }; + + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + let runav: []str = [testenv.driver(stages[si]), "run", + "-I", source, "foo.bar"]; + testenv.runcommandenv(td, td, strings.concat("auto-run-reject-", tags[si]), + runav, env, tmo(), &out); + let wantdiag: str = "ww: package foo.bar is not a main package\n"; + if (out.termination != exec.termination.EXIT || out.code != 1 + || !testenv.same(out.stderr, wantdiag) + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", "run crossed the non-main tool boundary"); + }; + if (si == 0) { diagnosticreference = strings.dup(out.stderr); } + else { if (!testenv.same(diagnosticreference, out.stderr)) { + fail("package-autoaction", "run diagnostics differ by stage"); + }; }; + + let cyclerun: []str = [testenv.driver(stages[si]), "run", + "-I", source, "foo.cyclea"]; + testenv.runcommandenv(td, td, strings.concat("auto-run-cycle-", tags[si]), + cyclerun, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 1 + || !testenv.has(out.stderr, + "ww: dependency cycle: foo.cyclea -> foo.cycleb -> foo.cyclea\n") + || testenv.has(out.stderr, "is not a main package") + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + "run command-kind validation masked a graph failure"); + }; + if (si == 0) { cyclediagreference = strings.dup(out.stderr); } + else { if (!testenv.same(cyclediagreference, out.stderr)) { + fail("package-autoaction", "run cycle diagnostics differ by stage"); + }; }; + + let cyclepathwork: str = strings.concat(td, "/cycle-path-work-", + tags[si]); + mkdir(cyclepathwork); + let cyclepathav: []str = [testenv.driver(stages[si]), "build", + "-w", cyclepathwork, "-I", source, "-o", longout, + "foo.cyclea"]; + testenv.runcommandenv(td, td, strings.concat("auto-cycle-path-", tags[si]), + cyclepathav, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 1 + || !testenv.has(out.stderr, "ww: dependency cycle: ") + || !testenv.has(out.stderr, "foo.cyclea") + || !testenv.has(out.stderr, "foo.cycleb") + || testenv.has(out.stderr, "package output path is too long") + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + strings.concat("publication path validation masked a graph failure: ", + out.stderr)); + }; + if (si == 0) { cyclepathdiagreference = strings.dup(out.stderr); } + else { if (!testenv.same(cyclepathdiagreference, out.stderr)) { + fail("package-autoaction", + "cycle/output-path diagnostic differs by stage"); + }; }; + + assert(os.remove(depsrc) == 0); + testenv.writefile(depsrc, depprivate); + testenv.runcommandenv(td, td, strings.concat("auto-private-", tags[si]), + av, env, tmo(), &out); + ctrace = testenv.readfile(compilertrace); + atrace = testenv.readfile(assemblertrace); + let wantprivatecompiler: str = strings.concat( + "BEGIN<-c><-I><", work, + "/foo.dep.wwi.new><-o><", work, + "/foo.dep.s.new><", work, "/foo.dep.unit.new>\n"); + let wantprivateassembler: str = strings.concat( + "BEGIN<-o><", work, "/foo.dep.o.new><", work, + "/foo.dep.s.new>\n"); + if (out.termination != exec.termination.EXIT || out.code != 0 + || !testenv.same(ctrace, wantprivatecompiler) + || !testenv.same(atrace, wantprivateassembler) + || testenv.readfile(linkertrace).len != 0 + || !testenv.same(rootreference[4], testenv.readfile(strings.concat( + work, "/foo.bar.a")))) { + fail("package-autoaction", + "private dependency change escaped its export boundary"); + }; + + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + assert(os.remove(depsrc) == 0); + testenv.writefile(depsrc, depexported); + testenv.runcommandenv(td, td, strings.concat("auto-export-", tags[si]), + av, env, tmo(), &out); + ctrace = testenv.readfile(compilertrace); + atrace = testenv.readfile(assemblertrace); + let wantexportcompiler: str = strings.concat( + "BEGIN<-c><-I><", work, + "/foo.dep.wwi.new><-o><", work, + "/foo.dep.s.new><", work, "/foo.dep.unit.new>\n", + "BEGIN<-c><--import><", work, + "/foo.dep.wwi><-I><", work, + "/foo.bar.wwi.new><-o><", work, + "/foo.bar.s.new><", work, "/foo.bar.unit.new>\n"); + let wantexportassembler: str = strings.concat( + "BEGIN<-o><", work, "/foo.dep.o.new><", work, + "/foo.dep.s.new>\n", + "BEGIN<-o><", work, "/foo.bar.o.new><", work, + "/foo.bar.s.new>\n"); + if (out.termination != exec.termination.EXIT || out.code != 0 + || !testenv.same(ctrace, wantexportcompiler) + || !testenv.same(atrace, wantexportassembler) + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", + "exported dependency change did not reach its direct importer"); + }; + + testenv.clean(compilertrace); testenv.writefile(compilertrace, ""); + testenv.clean(assemblertrace); testenv.writefile(assemblertrace, ""); + testenv.clean(linkertrace); testenv.writefile(linkertrace, ""); + testenv.runcommandenv(td, td, strings.concat("auto-warm-", tags[si]), + av, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 + || testenv.readfile(compilertrace).len != 0 + || testenv.readfile(assemblertrace).len != 0 + || testenv.readfile(linkertrace).len != 0) { + fail("package-autoaction", "warm library build did not fully reuse"); + }; + assert(os.remove(depsrc) == 0); + testenv.writefile(depsrc, depbase); + si += 1; + }; + testenv.clean(td); +}; + @test fn generated_test_hook_is_not_a_user_exemption() void = { let td: str = testenv.fresh(); let src: str = strings.concat(td, "/case.ww"); diff --git a/test/tool/driver_test.ww b/test/tool/driver_test.ww index 3669d80d..b6a70fe5 100644 --- a/test/tool/driver_test.ww +++ b/test/tool/driver_test.ww @@ -249,6 +249,7 @@ fn runrootargv(dir: str, root: str, name: str, drv: str, let td: str = testenv.fresh(); let src: str = strings.concat(td, "/inline.ww"); testenv.writefile(src, strings.concat( + "package main;\n", "package aa;\n", "export fn getv() i32 = { return 7; };\n", "package main;\n", diff --git a/test/tool/rejects_test.ww b/test/tool/rejects_test.ww index 860ad86c..eb3dd89e 100644 --- a/test/tool/rejects_test.ww +++ b/test/tool/rejects_test.ww @@ -19,7 +19,7 @@ package rejects_test; // paramshadow (#19/#16) — value names and module names are disjoint: // a param/let/mlet/for-range/match-case binding named `shadowmod` in // a file importing module shadowmod is rejected at the decl site; the -// renamed binding builds+runs 42 (no over-trigger); a param named +// renamed binding in a real `package main` builds+runs 42 (no over-trigger); a param named // like a module a SIBLING module imports does not trip (src_imports // filters by the binding's own module — build+run exit 2). The // carrier's neg_selfimp leg is DROPPED here: diff --git a/test/wcc/data/fnlabelmangle/pos.ww b/test/wcc/data/fnlabelmangle/pos.ww index f439fec3..240c77a4 100644 --- a/test/wcc/data/fnlabelmangle/pos.ww +++ b/test/wcc/data/fnlabelmangle/pos.ww @@ -12,7 +12,7 @@ // p2() = mod2.ping = 31 // total = 112 -package fnlabelmangle; +package main; import mod1; import mod2; diff --git a/test/wcc/data/paramshadowmod/pos_crossmod.ww b/test/wcc/data/paramshadowmod/pos_crossmod.ww index 46454422..d60e0bce 100644 --- a/test/wcc/data/paramshadowmod/pos_crossmod.ww +++ b/test/wcc/data/paramshadowmod/pos_crossmod.ww @@ -6,7 +6,7 @@ // own module — must NOT trip crossmod's param, even though a sibling // module in the same bundle imports that leaf. Build + run; exit = 2. -package paramshadowmod; +package main; import shadowmod; import crossmod; diff --git a/test/wcc/data/paramshadowmod/pos_rename.ww b/test/wcc/data/paramshadowmod/pos_rename.ww index e5677a44..b96844ee 100644 --- a/test/wcc/data/paramshadowmod/pos_rename.ww +++ b/test/wcc/data/paramshadowmod/pos_rename.ww @@ -2,7 +2,7 @@ // imported module's bareword, so the rule doesn't fire and the body // can call `shadowmod.say()` cleanly. Built + run; exit code = 42. -package paramshadowmod; +package main; import shadowmod; diff --git a/test/wcc/data/r696_modtype_leaf_pos/case.ww b/test/wcc/data/r696_modtype_leaf_pos/case.ww index a6c8a62a..c2cc6e2c 100644 --- a/test/wcc/data/r696_modtype_leaf_pos/case.ww +++ b/test/wcc/data/r696_modtype_leaf_pos/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 26 +package main; // migrated from test/wcc/696_modtype_leaf_collision.c: same-leaf cross-module `type stream` must stay mod-tagged (pre-fix sym smash cross-bound the fields). package mod1; export type stream = struct { diff --git a/test/wcc/data/r699_usepromote_def/case.ww b/test/wcc/data/r699_usepromote_def/case.ww index b0863169..0962a4e2 100644 --- a/test/wcc/data/r699_usepromote_def/case.ww +++ b/test/wcc/data/r699_usepromote_def/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_DEF promotion must keep use_alias so `defmod.flag` resolves. package defmod; export def defmod: i32 = 0i32; diff --git a/test/wcc/data/r699_usepromote_fn/case.ww b/test/wcc/data/r699_usepromote_fn/case.ww index 9f38383f..c74ee78d 100644 --- a/test/wcc/data/r699_usepromote_fn/case.ww +++ b/test/wcc/data/r699_usepromote_fn/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_FN promotion (the original bug) must keep use_alias or `fnmod.flag` fails "unknown type". package fnmod; export type flag = enum i32 { diff --git a/test/wcc/data/r699_usepromote_type/case.ww b/test/wcc/data/r699_usepromote_type/case.ww index 5d9ed93a..d0ce6705 100644 --- a/test/wcc/data/r699_usepromote_type/case.ww +++ b/test/wcc/data/r699_usepromote_type/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_TYPE in-place promotion keeps use_alias so `typmod.flag` resolves (check.c self-import branch). package typmod; export type typmod = struct { diff --git a/test/wcc/data/r699_usepromote_var/case.ww b/test/wcc/data/r699_usepromote_var/case.ww index 0d6b0c64..07bbd4db 100644 --- a/test/wcc/data/r699_usepromote_var/case.ww +++ b/test/wcc/data/r699_usepromote_var/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_VAR promotion must keep use_alias so `varmod.flag` resolves. package varmod; export let varmod: i32 = 0i32; diff --git a/test/wcc/data/r700_alloc_shadow_myos/case.ww b/test/wcc/data/r700_alloc_shadow_myos/case.ww index 4ceba569..5225cb0c 100644 --- a/test/wcc/data/r700_alloc_shadow_myos/case.ww +++ b/test/wcc/data/r700_alloc_shadow_myos/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 107 +package main; // Migrated from 700_e2e row 40. package myos; fn alloc(n: i64) i64 = { return n + 100; }; diff --git a/test/wcc/data/r700_enum_cross_module/case.ww b/test/wcc/data/r700_enum_cross_module/case.ww index 21952ca1..8f06b9f9 100644 --- a/test/wcc/data/r700_enum_cross_module/case.ww +++ b/test/wcc/data/r700_enum_cross_module/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // Migrated from 700_e2e row 123. package pkg; export type base = enum i32 { DEC = 10, HEX = 16 }; diff --git a/test/wcc/data/r700_enum_pkg_qual/case.ww b/test/wcc/data/r700_enum_pkg_qual/case.ww index 464b0a0a..75c2e671 100644 --- a/test/wcc/data/r700_enum_pkg_qual/case.ww +++ b/test/wcc/data/r700_enum_pkg_qual/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 1 +package main; // Migrated from 700_e2e row 118. package pkg; type dir = enum { NORTH, SOUTH, EAST, WEST }; diff --git a/test/wcc/data/r732_def_xmod_fold/case.ww b/test/wcc/data/r732_def_xmod_fold/case.ww index 9b9abfc5..65f793bc 100644 --- a/test/wcc/data/r732_def_xmod_fold/case.ww +++ b/test/wcc/data/r732_def_xmod_fold/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // migrated from test/wcc/732_def_const_fold.c: cross-module def-RHS fold (`def K = a.J + 1`) must emit the folded DATA row; run-exit links AND reads the value. package a; export def J: i32 = 41; diff --git a/test/wcc/data/r79_xmod_valglobal_def/case.ww b/test/wcc/data/r79_xmod_valglobal_def/case.ww index 64ef9d85..a2dcf5e5 100644 --- a/test/wcc/data/r79_xmod_valglobal_def/case.ww +++ b/test/wcc/data/r79_xmod_valglobal_def/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 5 +package main; package aa; export def K: i32 = 5; export fn getk() i32 = { return K; }; diff --git a/test/wcc/data/r79_xmod_valglobal_dot_addrof/case.ww b/test/wcc/data/r79_xmod_valglobal_dot_addrof/case.ww index 2b159c46..59dbec68 100644 --- a/test/wcc/data/r79_xmod_valglobal_dot_addrof/case.ww +++ b/test/wcc/data/r79_xmod_valglobal_dot_addrof/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 7 +package main; package aa; export let v: i32 = 7; package main; diff --git a/test/wcc/data/r79_xmod_valglobal_dot_read/case.ww b/test/wcc/data/r79_xmod_valglobal_dot_read/case.ww index 67aa3841..e787dbcc 100644 --- a/test/wcc/data/r79_xmod_valglobal_dot_read/case.ww +++ b/test/wcc/data/r79_xmod_valglobal_dot_read/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 7 +package main; package aa; export let v: i32 = 7; package main; diff --git a/test/wcc/data/r79_xmod_valglobal_f64/case.ww b/test/wcc/data/r79_xmod_valglobal_f64/case.ww index dd766c55..4a580888 100644 --- a/test/wcc/data/r79_xmod_valglobal_f64/case.ww +++ b/test/wcc/data/r79_xmod_valglobal_f64/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 2 +package main; package aa; export let f: f64 = 2.5; export fn getf() f64 = { return f; }; diff --git a/test/wcc/data/r79_xmod_valglobal_i32/case.ww b/test/wcc/data/r79_xmod_valglobal_i32/case.ww index ec61c80d..41b93909 100644 --- a/test/wcc/data/r79_xmod_valglobal_i32/case.ww +++ b/test/wcc/data/r79_xmod_valglobal_i32/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 7 +package main; package aa; export let v: i32 = 7; export fn getv() i32 = { return v; }; diff --git a/test/wcc/data/r839_xmod_a6_concrete/case.ww b/test/wcc/data/r839_xmod_a6_concrete/case.ww index 9dbac414..d90f8c69 100644 --- a/test/wcc/data/r839_xmod_a6_concrete/case.ww +++ b/test/wcc/data/r839_xmod_a6_concrete/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/839_xmod_nominal_typeeqast.c: A6 — concrete e.myerr returned into e.res (bare-vs-qualified nominal forward), both stages accept. package e; export type myerr = !i64; diff --git a/test/wcc/data/r839_xmod_nominal_match/case.ww b/test/wcc/data/r839_xmod_nominal_match/case.ww index 62a3a148..389649ca 100644 --- a/test/wcc/data/r839_xmod_nominal_match/case.ww +++ b/test/wcc/data/r839_xmod_nominal_match/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // migrated from test/wcc/839_xmod_nominal_typeeqast.c: bare-spelled union variants matched via QUALIFIED case patterns (`case let x: e.myerr`) — cross-module nominal cover. package e; export type myerr = !i64; diff --git a/test/wcc/data/r84_dupentry_single_nonmain/case.ww b/test/wcc/data/r84_dupentry_single_nonmain/case.ww index e8e299a1..0a9f0dc3 100644 --- a/test/wcc/data/r84_dupentry_single_nonmain/case.ww +++ b/test/wcc/data/r84_dupentry_single_nonmain/case.ww @@ -1,3 +1,4 @@ //ww:run-exit 7 +package main; package cmatrix; fn main() i32 = { return 7; }; diff --git a/test/wcc/data/r84_qualstruct_fields/case.ww b/test/wcc/data/r84_qualstruct_fields/case.ww index 0948c680..c4ee309e 100644 --- a/test/wcc/data/r84_qualstruct_fields/case.ww +++ b/test/wcc/data/r84_qualstruct_fields/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 37 +package main; package pkg; export type point = struct { x: i64, y: i64 }; export type rect = struct { lo: point, hi: point }; diff --git a/test/wcc/data/r84_qualstruct_nested/case.ww b/test/wcc/data/r84_qualstruct_nested/case.ww index e0fbe0e0..e19f2274 100644 --- a/test/wcc/data/r84_qualstruct_nested/case.ww +++ b/test/wcc/data/r84_qualstruct_nested/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 18 +package main; package pkg; export type point = struct { x: i64, y: i64 }; export type rect = struct { lo: point, hi: point }; diff --git a/test/wcc/data/r84_qualstruct_ret_assign/case.ww b/test/wcc/data/r84_qualstruct_ret_assign/case.ww index 6f5d19c6..b282278e 100644 --- a/test/wcc/data/r84_qualstruct_ret_assign/case.ww +++ b/test/wcc/data/r84_qualstruct_ret_assign/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 27 +package main; package pkg; export type point = struct { x: i64, y: i64 }; export type rect = struct { lo: point, hi: point }; diff --git a/test/wcc/data/r915_arr_mod_idx0/case.ww b/test/wcc/data/r915_arr_mod_idx0/case.ww index 9b339767..a6badb48 100644 --- a/test/wcc/data/r915_arr_mod_idx0/case.ww +++ b/test/wcc/data/r915_arr_mod_idx0/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/915_arr_module_index_run.c: cross-package mod.arr[0] — LEAQ base + u16 load width (#128b). package wcmodarr; export let probe_table: [8]u16 = [0u16, 0x0800u16, 0x0801u16, 0x0803u16, 0x1006u16, 0x1009u16, 0x100Du16, 0x1812u16]; diff --git a/test/wcc/data/r915_arr_mod_idx2/case.ww b/test/wcc/data/r915_arr_mod_idx2/case.ww index 9b75104b..7e34ae58 100644 --- a/test/wcc/data/r915_arr_mod_idx2/case.ww +++ b/test/wcc/data/r915_arr_mod_idx2/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 1 +package main; // migrated from test/wcc/915_arr_module_index_run.c: nontrivial index — the pre-fix MOVQ-not-LEAQ segfault repro; 0x0801 mod 256 = 1. package wcmodarr; export let probe_table: [8]u16 = [0u16, 0x0800u16, 0x0801u16, 0x0803u16, 0x1006u16, 0x1009u16, 0x100Du16, 0x1812u16]; diff --git a/test/wcc/data/r915_arr_mod_idx4/case.ww b/test/wcc/data/r915_arr_mod_idx4/case.ww index 57e68b5f..32b20597 100644 --- a/test/wcc/data/r915_arr_mod_idx4/case.ww +++ b/test/wcc/data/r915_arr_mod_idx4/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 6 +package main; // migrated from test/wcc/915_arr_module_index_run.c: per-element stride pin; 0x1006 mod 256 = 6. package wcmodarr; export let probe_table: [8]u16 = [0u16, 0x0800u16, 0x0801u16, 0x0803u16, 0x1006u16, 0x1009u16, 0x100Du16, 0x1812u16]; diff --git a/test/wcc/data/r921_amp_xmod_def/case.ww b/test/wcc/data/r921_amp_xmod_def/case.ww index 89a21df2..1cf40c7d 100644 --- a/test/wcc/data/r921_amp_xmod_def/case.ww +++ b/test/wcc/data/r921_amp_xmod_def/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 18 +package main; package myf; export type pt = struct { x: i32, y: i32 }; export def P: pt = pt{x=7, y=11}; diff --git a/test/wcc/data/r921_amp_xmod_fn/case.ww b/test/wcc/data/r921_amp_xmod_fn/case.ww index 73beba25..833a6f07 100644 --- a/test/wcc/data/r921_amp_xmod_fn/case.ww +++ b/test/wcc/data/r921_amp_xmod_fn/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 7 +package main; package myf; export fn helper() i32 = { return 42; }; package main; diff --git a/test/wcc/data/r921_amp_xmod_let/case.ww b/test/wcc/data/r921_amp_xmod_let/case.ww index bb0e4fe6..5c4c7034 100644 --- a/test/wcc/data/r921_amp_xmod_let/case.ww +++ b/test/wcc/data/r921_amp_xmod_let/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 18 +package main; package myf; export type pt = struct { x: i32, y: i32 }; export let L: pt = pt{x=7, y=11}; diff --git a/test/wcc/data/r921_amp_xmod_scalar/case.ww b/test/wcc/data/r921_amp_xmod_scalar/case.ww index f560d0a1..a4e9809d 100644 --- a/test/wcc/data/r921_amp_xmod_scalar/case.ww +++ b/test/wcc/data/r921_amp_xmod_scalar/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; package myf; export let S: i32 = 42; package main; diff --git a/test/wcc/data/r929_match_3arm_shadowed/case.ww b/test/wcc/data/r929_match_3arm_shadowed/case.ww index 69cceb10..0a6df2ce 100644 --- a/test/wcc/data/r929_match_3arm_shadowed/case.ww +++ b/test/wcc/data/r929_match_3arm_shadowed/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/929_match_4arm_cross_module_run.c: 3-arm boundary — arm 2 must reach its body under the shadowed callee. package a; export type more = void; diff --git a/test/wcc/data/r929_match_4arm_mixed_kinds/case.ww b/test/wcc/data/r929_match_4arm_mixed_kinds/case.ww index c8b57dbf..2230decd 100644 --- a/test/wcc/data/r929_match_4arm_mixed_kinds/case.ww +++ b/test/wcc/data/r929_match_4arm_mixed_kinds/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/929_match_4arm_cross_module_run.c: mixed variant kinds (i32|str|rune|u8) — the shadowed-resolution fix is not shape-specific. package a; export fn next(k: i32) (i32 | str | rune | u8) = { diff --git a/test/wcc/data/r929_match_4arm_shadowed_canonical/case.ww b/test/wcc/data/r929_match_4arm_shadowed_canonical/case.ww index b71a094e..302dce78 100644 --- a/test/wcc/data/r929_match_4arm_shadowed_canonical/case.ww +++ b/test/wcc/data/r929_match_4arm_shadowed_canonical/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/929_match_4arm_cross_module_run.c: canonical 4-arm — caller fn `next` shadows callee a.next; every arm body must fire (#31 fnretlookupmod). package a; export type more = void; diff --git a/test/wcc/data/r929_match_4arm_shadowed_reverse/case.ww b/test/wcc/data/r929_match_4arm_shadowed_reverse/case.ww index 74c581eb..17cb7c48 100644 --- a/test/wcc/data/r929_match_4arm_shadowed_reverse/case.ww +++ b/test/wcc/data/r929_match_4arm_shadowed_reverse/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/929_match_4arm_cross_module_run.c: reverse arm order — dispatch follows the callee's variant indices, not source order. package a; export type more = void; diff --git a/test/wcc/data/r929_match_5arm_shadowed/case.ww b/test/wcc/data/r929_match_5arm_shadowed/case.ww index 9367c4c4..91f33adf 100644 --- a/test/wcc/data/r929_match_5arm_shadowed/case.ww +++ b/test/wcc/data/r929_match_5arm_shadowed/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/929_match_4arm_cross_module_run.c: 5-arm scaling — arms 3 and 4 must each reach their body. package a; export type more = void; diff --git a/test/wcc/data/r929_match_6arm_shadowed/case.ww b/test/wcc/data/r929_match_6arm_shadowed/case.ww index 181540b8..b5c51f28 100644 --- a/test/wcc/data/r929_match_6arm_shadowed/case.ww +++ b/test/wcc/data/r929_match_6arm_shadowed/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/929_match_4arm_cross_module_run.c: 6-arm — every arm beyond the caller's variant count was broken, not just arm 2/3. package a; export type more = void; diff --git a/test/wcc/data/r949_xmod_fnptr_const_table/case.ww b/test/wcc/data/r949_xmod_fnptr_const_table/case.ww index 48cb03f4..45b7dd49 100644 --- a/test/wcc/data/r949_xmod_fnptr_const_table/case.ww +++ b/test/wcc/data/r949_xmod_fnptr_const_table/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; // migrated from test/wcc/949_xmod_fnptr_const_run.c: cross-module &cc.fn inside const table + scalar emits the &fn->DATAR reloc (#124); DISTINCT predicates catch a swapped reloc. package cc; export fn isa(c: rune) bool = { return c == 'a'; }; diff --git a/test/wcc/data/r953_f64crossmod_x101_neg/case.ww b/test/wcc/data/r953_f64crossmod_x101_neg/case.ww index ce65c0a2..98e0a11c 100644 --- a/test/wcc/data/r953_f64crossmod_x101_neg/case.ww +++ b/test/wcc/data/r953_f64crossmod_x101_neg/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 249 +package main; package myf; export fn g() f64 = { return -7.0; }; package main; diff --git a/test/wcc/data/r953_f64crossmod_x101_trunc_neg/case.ww b/test/wcc/data/r953_f64crossmod_x101_trunc_neg/case.ww index 065669bd..7bb18fa6 100644 --- a/test/wcc/data/r953_f64crossmod_x101_trunc_neg/case.ww +++ b/test/wcc/data/r953_f64crossmod_x101_trunc_neg/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 253 +package main; package myf; export fn g() f64 = { return -3.9; }; package main; diff --git a/test/wcc/data/r953_f64crossmod_x101_trunc_pos/case.ww b/test/wcc/data/r953_f64crossmod_x101_trunc_pos/case.ww index 1496b6a7..0e158c25 100644 --- a/test/wcc/data/r953_f64crossmod_x101_trunc_pos/case.ww +++ b/test/wcc/data/r953_f64crossmod_x101_trunc_pos/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 3 +package main; package myf; export fn g() f64 = { return 3.9; }; package main; diff --git a/test/wcc/data/r953_f64crossmod_x98_nested_arg/case.ww b/test/wcc/data/r953_f64crossmod_x98_nested_arg/case.ww index 6948a91c..bae40dd6 100644 --- a/test/wcc/data/r953_f64crossmod_x98_nested_arg/case.ww +++ b/test/wcc/data/r953_f64crossmod_x98_nested_arg/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 242 +package main; package myf; export fn g() f64 = { return -7.0; }; package main; diff --git a/test/wcc/data/r953_f64crossmod_x98_xmm_pressure/case.ww b/test/wcc/data/r953_f64crossmod_x98_xmm_pressure/case.ww index 00ba88be..6dff1523 100644 --- a/test/wcc/data/r953_f64crossmod_x98_xmm_pressure/case.ww +++ b/test/wcc/data/r953_f64crossmod_x98_xmm_pressure/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 8 +package main; package myf; export fn g() f64 = { return -7.0; }; package main; diff --git a/test/wcc/data/r956_modqual_mq_f64_i64_destr/case.ww b/test/wcc/data/r956_modqual_mq_f64_i64_destr/case.ww index d30b7b4c..3434a026 100644 --- a/test/wcc/data/r956_modqual_mq_f64_i64_destr/case.ww +++ b/test/wcc/data/r956_modqual_mq_f64_i64_destr/case.ww @@ -1,4 +1,5 @@ //ww:run +package main; package myf; export fn frexp(n: f64) (f64, i64) = { if (n == 0.0) { return (0.0, 0i64); }; diff --git a/test/wcc/data/r956_modqual_mq_f64_str_destr/case.ww b/test/wcc/data/r956_modqual_mq_f64_str_destr/case.ww index 87b11a0e..5ffea8c3 100644 --- a/test/wcc/data/r956_modqual_mq_f64_str_destr/case.ww +++ b/test/wcc/data/r956_modqual_mq_f64_str_destr/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 4 +package main; package myf; export fn fs(n: f64) (f64, str) = { if (n == 0.0) { return (n, "x"); }; diff --git a/test/wcc/data/r956_modqual_mq_i64_bool_destr/case.ww b/test/wcc/data/r956_modqual_mq_i64_bool_destr/case.ww index 63934ea0..659de060 100644 --- a/test/wcc/data/r956_modqual_mq_i64_bool_destr/case.ww +++ b/test/wcc/data/r956_modqual_mq_i64_bool_destr/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 15 +package main; package myf; export fn addi64(a: i64, b: i64) (i64, bool) = { let s: i64 = a + b; diff --git a/test/wcc/data/r956_modqual_mq_nondestr_shadow/case.ww b/test/wcc/data/r956_modqual_mq_nondestr_shadow/case.ww index f34bf4a7..9795c471 100644 --- a/test/wcc/data/r956_modqual_mq_nondestr_shadow/case.ww +++ b/test/wcc/data/r956_modqual_mq_nondestr_shadow/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 10 +package main; package beta; export fn dup() (i64, i64) = { return (3i64, 7i64); }; package main; diff --git a/test/wcc/data/r957_assert_imported_mod/case.ww b/test/wcc/data/r957_assert_imported_mod/case.ww index a65c4aa1..864b37a9 100644 --- a/test/wcc/data/r957_assert_imported_mod/case.ww +++ b/test/wcc/data/r957_assert_imported_mod/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; package m; export fn f() i32 = { assert(3 > 2, "m.f invariant"); diff --git a/test/wcc/data/r957_assert_shadow_xmod/case.ww b/test/wcc/data/r957_assert_shadow_xmod/case.ww index 1f45a85a..412c13fe 100644 --- a/test/wcc/data/r957_assert_shadow_xmod/case.ww +++ b/test/wcc/data/r957_assert_shadow_xmod/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; package m; export fn assert(b: bool, msg: str) void = { }; package main; diff --git a/test/wcc/data/r989_ampfncollide_loud/case.ww b/test/wcc/data/r989_ampfncollide_loud/case.ww index 21590bd6..fe97db0b 100644 --- a/test/wcc/data/r989_ampfncollide_loud/case.ww +++ b/test/wcc/data/r989_ampfncollide_loud/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; // Current-module &fn lookup must beat a later same-leaf declaration. package beta; export type hfn = fn(x: i32) i32; diff --git a/test/wcc/data/r989_trycallcollide_call/case.ww b/test/wcc/data/r989_trycallcollide_call/case.ww index 65f6e8fb..79e8f363 100644 --- a/test/wcc/data/r989_trycallcollide_call/case.ww +++ b/test/wcc/data/r989_trycallcollide_call/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; package beta; export type berr = !void; export fn op() (i32 | berr) = { return 5; }; diff --git a/test/wcc/data/r989_trycallcollide_control/case.ww b/test/wcc/data/r989_trycallcollide_control/case.ww index c85e367d..6e65537e 100644 --- a/test/wcc/data/r989_trycallcollide_control/case.ww +++ b/test/wcc/data/r989_trycallcollide_control/case.ww @@ -1,4 +1,5 @@ //ww:run-exit 42 +package main; package beta; export type berr = !void; export fn op() (i32 | berr) = { return 5; }; diff --git a/test/wcc/data/selfhost_smoke/case.ww b/test/wcc/data/selfhost_smoke/case.ww index 25d0e1d0..58346abe 100644 --- a/test/wcc/data/selfhost_smoke/case.ww +++ b/test/wcc/data/selfhost_smoke/case.ww @@ -18,7 +18,7 @@ // task; until then we exercise polymorphism via ctx pointers, which // is what the real port wants anyway. -package test; +package main; import os; import strconv; diff --git a/test/xmod/direnum_test.ww b/test/xmod/direnum_test.ww index cc337727..4b1e772e 100644 --- a/test/xmod/direnum_test.ww +++ b/test/xmod/direnum_test.ww @@ -15,7 +15,7 @@ package direnum_test; // Both stages must FAIL with "conflicting package names", and the // two stages' diagnostics must be byte-identical. // -// rootorder — a private rootok/ dir built DIRECTLY (z.ww ORDER-Z +// rootorder — a private rootok/ command dir built DIRECTLY (z.ww ORDER-Z // value()=17 vs a.ww ORDER-A leading comment + main): build exit 0, // the binary exits 17, and the driver's local-identity owner unit // stores ORDER-A strictly before ORDER-Z (byte-sorted deterministic @@ -121,14 +121,14 @@ fn rejectpair(label: str, td: str, target: str, needle: str) void = { let rootok: str = strings.concat(td, "/rootok"); assert(os.mkdir(rootok, 493) == 0); testenv.writefile(strings.concat(rootok, "/z.ww"), strings.concat( - "package rootok;\n// ORDER-Z\n", + "package main;\n// ORDER-Z\n", "fn value() i32 = { return 17; };\n")); testenv.writefile(strings.concat(rootok, "/a.ww"), strings.concat( "// leading comment is part of the loader grammar\n", - "package rootok;\n// ORDER-A\n", + "package main;\n// ORDER-A\n", "fn main() i32 = { return value(); };\n")); let drvs: []str = ["ww", "ww_ww"]; - let identity: str = testenv.localpackageidentity(rootok, "rootok"); + let identity: str = testenv.localpackageidentity(rootok, "main"); let units: []str = ["", ""]; let s: i32 = 0; for (s < 2) {