ww: select build action from package declaration
This commit is contained in:
148
cmd/ww/main.c
148
cmd/ww/main.c
@@ -24,7 +24,7 @@
|
||||
static const char *usage =
|
||||
"usage: ww [-V] <subcommand> [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 <basename>.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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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] <subcommand> [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 <basename>.ww\n";
|
||||
let s: str = "usage: ww [-V] <subcommand> [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 <basename>.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));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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/");
|
||||
|
||||
@@ -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><foo.dep><", 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><foo.dep><", 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><foo.bar><", 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><foo.dep><", 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><foo.dep><", 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><foo.dep><", 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");
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// p2() = mod2.ping = 31
|
||||
// total = 112
|
||||
|
||||
package fnlabelmangle;
|
||||
package main;
|
||||
|
||||
import mod1;
|
||||
import mod2;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 5
|
||||
package main;
|
||||
package aa;
|
||||
export def K: i32 = 5;
|
||||
export fn getk() i32 = { return K; };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 7
|
||||
package main;
|
||||
package aa;
|
||||
export let v: i32 = 7;
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 7
|
||||
package main;
|
||||
package aa;
|
||||
export let v: i32 = 7;
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 2
|
||||
package main;
|
||||
package aa;
|
||||
export let f: f64 = 2.5;
|
||||
export fn getf() f64 = { return f; };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 7
|
||||
package main;
|
||||
package aa;
|
||||
export let v: i32 = 7;
|
||||
export fn getv() i32 = { return v; };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//ww:run-exit 7
|
||||
package main;
|
||||
package cmatrix;
|
||||
fn main() i32 = { return 7; };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 7
|
||||
package main;
|
||||
package myf;
|
||||
export fn helper() i32 = { return 42; };
|
||||
package main;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 42
|
||||
package main;
|
||||
package myf;
|
||||
export let S: i32 = 42;
|
||||
package main;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'; };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 249
|
||||
package main;
|
||||
package myf;
|
||||
export fn g() f64 = { return -7.0; };
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 253
|
||||
package main;
|
||||
package myf;
|
||||
export fn g() f64 = { return -3.9; };
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 3
|
||||
package main;
|
||||
package myf;
|
||||
export fn g() f64 = { return 3.9; };
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 242
|
||||
package main;
|
||||
package myf;
|
||||
export fn g() f64 = { return -7.0; };
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 8
|
||||
package main;
|
||||
package myf;
|
||||
export fn g() f64 = { return -7.0; };
|
||||
package main;
|
||||
|
||||
@@ -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); };
|
||||
|
||||
@@ -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"); };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 10
|
||||
package main;
|
||||
package beta;
|
||||
export fn dup() (i64, i64) = { return (3i64, 7i64); };
|
||||
package main;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 42
|
||||
package main;
|
||||
package m;
|
||||
export fn f() i32 = {
|
||||
assert(3 > 2, "m.f invariant");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 42
|
||||
package main;
|
||||
package m;
|
||||
export fn assert(b: bool, msg: str) void = { };
|
||||
package main;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 42
|
||||
package main;
|
||||
package beta;
|
||||
export type berr = !void;
|
||||
export fn op() (i32 | berr) = { return 5; };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//ww:run-exit 42
|
||||
package main;
|
||||
package beta;
|
||||
export type berr = !void;
|
||||
export fn op() (i32 | berr) = { return 5; };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user