build: make executable and test roots package actions
This commit is contained in:
246
cmd/ww/main.c
246
cmd/ww/main.c
@@ -322,9 +322,11 @@ source_has_test_decl(const char *path)
|
|||||||
#define SEP_VARIANT_PRODUCTION 0
|
#define SEP_VARIANT_PRODUCTION 0
|
||||||
#define SEP_VARIANT_SAME_TEST 1
|
#define SEP_VARIANT_SAME_TEST 1
|
||||||
#define SEP_VARIANT_EXTERNAL 2
|
#define SEP_VARIANT_EXTERNAL 2
|
||||||
|
#define SEP_VARIANT_TEST_MAIN 3
|
||||||
#define SEP_ROLE_NORMAL 0
|
#define SEP_ROLE_NORMAL 0
|
||||||
#define SEP_ROLE_EXTERNAL_PRODUCTION 1
|
#define SEP_ROLE_EXTERNAL_PRODUCTION 1
|
||||||
#define SEP_ROLE_TEST_SUPPORT 2
|
#define SEP_ROLE_TEST_SUPPORT 2
|
||||||
|
#define SEP_ROLE_GENERATED_MAIN 3
|
||||||
#define SEP_TEST_SUPPORT_MODULE "__wwtest"
|
#define SEP_TEST_SUPPORT_MODULE "__wwtest"
|
||||||
#define SEP_MAXPRODUCT 256
|
#define SEP_MAXPRODUCT 256
|
||||||
#define SEP_MAXCONTEXT (SEP_MAXPRODUCT + 1)
|
#define SEP_MAXCONTEXT (SEP_MAXPRODUCT + 1)
|
||||||
@@ -508,7 +510,7 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
|
|||||||
#define SEP_MAXPKG 256
|
#define SEP_MAXPKG 256
|
||||||
|
|
||||||
struct seppkg {
|
struct seppkg {
|
||||||
char path[256]; /* dotted import path; "" == root/primary */
|
char path[256]; /* canonical dotted package identity */
|
||||||
char entry[1024]; /* resolved package dir (or file, for a file root) */
|
char entry[1024]; /* resolved package dir (or file, for a file root) */
|
||||||
char canon[1024]; /* canonical location; never package identity */
|
char canon[1024]; /* canonical location; never package identity */
|
||||||
char artifact[64]; /* non-importable product-root artifact key */
|
char artifact[64]; /* non-importable product-root artifact key */
|
||||||
@@ -519,7 +521,9 @@ struct seppkg {
|
|||||||
int is_dir;
|
int is_dir;
|
||||||
int variant; /* SEP_VARIANT_*; dependencies are production */
|
int variant; /* SEP_VARIANT_*; dependencies are production */
|
||||||
int role; /* normal, external-production, or test support */
|
int role; /* normal, external-production, or test support */
|
||||||
int root; /* independently compiled/linkable product root */
|
int root; /* requested package action (possibly a test variant) */
|
||||||
|
int link_entry; /* package supplies the executable's bare main */
|
||||||
|
int generated_main; /* compiler-owned generated test-main package */
|
||||||
int failed; /* discovery/compile failure reaches this action */
|
int failed; /* discovery/compile failure reaches this action */
|
||||||
int test_support; /* compiler-generated -T support package */
|
int test_support; /* compiler-generated -T support package */
|
||||||
int loaded; /* directory membership/name loaded exactly once */
|
int loaded; /* directory membership/name loaded exactly once */
|
||||||
@@ -554,6 +558,7 @@ struct sepproduct {
|
|||||||
int variant;
|
int variant;
|
||||||
int context;
|
int context;
|
||||||
int root;
|
int root;
|
||||||
|
int variant_root; /* production-plus-test or external test package */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SEP_MAXLFLAGS 32
|
#define SEP_MAXLFLAGS 32
|
||||||
@@ -591,8 +596,17 @@ sep_find_or_add_variant(struct sepgraph *g, const char *path,
|
|||||||
if (root && g->pkg[i].root) {
|
if (root && g->pkg[i].root) {
|
||||||
if (!same_location) continue;
|
if (!same_location) continue;
|
||||||
if (variant != g->pkg[i].variant) continue;
|
if (variant != g->pkg[i].variant) continue;
|
||||||
|
if (g->pkg[i].role == role
|
||||||
|
&& strcmp(g->pkg[i].path, path) == 0
|
||||||
|
&& strcmp(g->pkg[i].test_package,
|
||||||
|
test_package ? test_package : "") == 0) {
|
||||||
|
/* One canonical directory variant is one compile action,
|
||||||
|
* even when more than one product requests it. */
|
||||||
|
free(canon);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ww: duplicate package-test root %s\n", entry);
|
"ww: incompatible package-test roots %s\n", entry);
|
||||||
free(canon);
|
free(canon);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -693,6 +707,8 @@ sep_find_or_add_variant(struct sepgraph *g, const char *path,
|
|||||||
p->variant = variant;
|
p->variant = variant;
|
||||||
p->role = role;
|
p->role = role;
|
||||||
p->root = root;
|
p->root = root;
|
||||||
|
p->link_entry = 0;
|
||||||
|
p->generated_main = 0;
|
||||||
p->failed = 0;
|
p->failed = 0;
|
||||||
p->test_support = 0;
|
p->test_support = 0;
|
||||||
p->loaded = 0;
|
p->loaded = 0;
|
||||||
@@ -1135,6 +1151,62 @@ sep_dep_cmp(const struct sepgraph *g, int a, int b)
|
|||||||
return strcmp(g->pkg[a].artifact, g->pkg[b].artifact);
|
return strcmp(g->pkg[a].artifact, g->pkg[b].artifact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add the compiler-owned test main as a real package action. Its semantic
|
||||||
|
* identity and artifact key are distinct from every directory variant; its
|
||||||
|
* only dependencies are the selected test variant and dispatcher support. */
|
||||||
|
static int
|
||||||
|
sep_add_generated_main(struct sepgraph *g, struct sepproduct *product,
|
||||||
|
int ordinal, int support)
|
||||||
|
{
|
||||||
|
if (g->n >= SEP_MAXPKG) {
|
||||||
|
fprintf(stderr, "ww: too many packages (limit %d)\n", SEP_MAXPKG);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int variant = product->variant_root;
|
||||||
|
if (variant < 0 || variant >= g->n) return -1;
|
||||||
|
char variantcanon[sizeof g->pkg[0].canon];
|
||||||
|
char variantentry[sizeof g->pkg[0].entry];
|
||||||
|
snprintf(variantcanon, sizeof variantcanon, "%s", g->pkg[variant].canon);
|
||||||
|
snprintf(variantentry, sizeof variantentry, "%s", g->pkg[variant].entry);
|
||||||
|
struct seppkg *p = &g->pkg[g->n];
|
||||||
|
memset(p, 0, sizeof *p);
|
||||||
|
int pn = snprintf(p->path, sizeof p->path,
|
||||||
|
"__wwtestmain.%03d.main", ordinal);
|
||||||
|
int an = snprintf(p->artifact, sizeof p->artifact,
|
||||||
|
"__ww-test-%03d-main", ordinal);
|
||||||
|
int cn = snprintf(p->canon, sizeof p->canon, "%s#test-main-%03d",
|
||||||
|
variantcanon, ordinal);
|
||||||
|
if (pn < 0 || (size_t)pn >= sizeof p->path
|
||||||
|
|| an < 0 || (size_t)an >= sizeof p->artifact
|
||||||
|
|| cn < 0 || (size_t)cn >= sizeof p->canon) {
|
||||||
|
fprintf(stderr, "ww: generated test-main identity is too long\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
snprintf(p->entry, sizeof p->entry, "%s", variantentry);
|
||||||
|
snprintf(p->name, sizeof p->name, "main");
|
||||||
|
p->variant = SEP_VARIANT_TEST_MAIN;
|
||||||
|
p->role = SEP_ROLE_GENERATED_MAIN;
|
||||||
|
p->root = 1;
|
||||||
|
p->link_entry = 1;
|
||||||
|
p->generated_main = 1;
|
||||||
|
p->loaded = 1;
|
||||||
|
p->emit_context = product->context;
|
||||||
|
p->context_state[product->context] = 2;
|
||||||
|
p->deps[p->ndeps++] = variant;
|
||||||
|
if (support >= 0 && support != variant)
|
||||||
|
p->deps[p->ndeps++] = support;
|
||||||
|
for (int i = 1; i < p->ndeps; i++) {
|
||||||
|
int v = p->deps[i];
|
||||||
|
int j = i;
|
||||||
|
while (j > 0 && sep_dep_cmp(g, p->deps[j - 1], v) > 0) {
|
||||||
|
p->deps[j] = p->deps[j - 1];
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
p->deps[j] = v;
|
||||||
|
}
|
||||||
|
return g->n++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Load one canonical package under one selected-root resolution context.
|
/* Load one canonical package under one selected-root resolution context.
|
||||||
* Source membership is owned once, but a shared package's imports are checked
|
* Source membership is owned once, but a shared package's imports are checked
|
||||||
* under every context that reaches it. The first canonical binding set owns
|
* under every context that reaches it. The first canonical binding set owns
|
||||||
@@ -1224,10 +1296,11 @@ sep_load_pkg(struct sepgraph *g, int pi, int context)
|
|||||||
g->pkg[pi].failed = 1;
|
g->pkg[pi].failed = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Give a non-main root its declared identity before recursively loading
|
/* Give a directory root its declared package identity before recursively
|
||||||
* dependencies. A back-edge can then reuse the root and reach the normal
|
* loading dependencies. Explicit raw single-file compiler fixtures retain
|
||||||
* cycle detector instead of looking like a location alias. */
|
* their historical anonymous multi-package boundary. */
|
||||||
if (g->pkg[pi].root && g->pkg[pi].path[0] == '\0'
|
if (g->pkg[pi].root && g->pkg[pi].is_dir
|
||||||
|
&& g->pkg[pi].path[0] == '\0'
|
||||||
&& g->pkg[pi].name[0] != '\0') {
|
&& g->pkg[pi].name[0] != '\0') {
|
||||||
size_t n = strlen(g->pkg[pi].name);
|
size_t n = strlen(g->pkg[pi].name);
|
||||||
memcpy(g->pkg[pi].path, g->pkg[pi].name, n + 1);
|
memcpy(g->pkg[pi].path, g->pkg[pi].name, n + 1);
|
||||||
@@ -1358,7 +1431,15 @@ sep_compose_unit(struct sepgraph *g, int pi, const char *unitf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int bodyrc = 0;
|
int bodyrc = 0;
|
||||||
if (g->pkg[pi].is_dir) {
|
if (g->pkg[pi].generated_main) {
|
||||||
|
if (fprintf(u, "//ww:module-reset %s\npackage main;\n",
|
||||||
|
g->pkg[pi].path) < 0)
|
||||||
|
bodyrc = -1;
|
||||||
|
for (int i = 0; i < g->pkg[pi].ndeps && bodyrc == 0; i++)
|
||||||
|
if (fprintf(u, "import %s;\n",
|
||||||
|
g->pkg[g->pkg[pi].deps[i]].path) < 0)
|
||||||
|
bodyrc = -1;
|
||||||
|
} else if (g->pkg[pi].is_dir) {
|
||||||
for (int i = 0; i < g->pkg[pi].nsources && bodyrc == 0; i++)
|
for (int i = 0; i < g->pkg[pi].nsources && bodyrc == 0; i++)
|
||||||
bodyrc = sep_emit_body(u, g->pkg[pi].sources[i],
|
bodyrc = sep_emit_body(u, g->pkg[pi].sources[i],
|
||||||
g->pkg[pi].path);
|
g->pkg[pi].path);
|
||||||
@@ -1536,7 +1617,7 @@ static void
|
|||||||
workdir_stamp_text(char *buf, size_t bufsz, int is_test, int emit_asm)
|
workdir_stamp_text(char *buf, size_t bufsz, int is_test, int emit_asm)
|
||||||
{
|
{
|
||||||
snprintf(buf, bufsz, "ww workdir fmt %d mode %s asm %d\n",
|
snprintf(buf, bufsz, "ww workdir fmt %d mode %s asm %d\n",
|
||||||
is_test ? 7 : 6, is_test ? "test" : "build", emit_asm);
|
is_test ? 8 : 7, is_test ? "test" : "build", emit_asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A stale global builder identity invalidates every committed unit voucher in
|
/* A stale global builder identity invalidates every committed unit voucher in
|
||||||
@@ -1574,8 +1655,8 @@ invalidate_workdir_units(const char *scratch)
|
|||||||
* package universe, compile the dependency-first union once, then link each
|
* package universe, compile the dependency-first union once, then link each
|
||||||
* root from its own complete reachable archive closure. The dependency-first
|
* root from its own complete reachable archive closure. The dependency-first
|
||||||
* producer loop (one `w6c -c -I` per package,
|
* producer loop (one `w6c -c -I` per package,
|
||||||
* each DEP `.o` wrapped in its own deterministic `.a`), then a
|
* each package `.o` wrapped in its own deterministic `.a`), then a
|
||||||
* reverse-topo `w6l` of each root `.o` + dep `.a` set + libwwrt.a. Side
|
* reverse-topo `w6l` of each root `.a` + reachable `.a` set + libwwrt.a. Side
|
||||||
* files land in a cold `<stem>.sepwork` dir, or under the persistent
|
* files land in a cold `<stem>.sepwork` dir, or under the persistent
|
||||||
* `-w` workdir with content-identity package reuse. */
|
* `-w` workdir with content-identity package reuse. */
|
||||||
static int
|
static int
|
||||||
@@ -1696,6 +1777,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
if (graphout) *graphout = g;
|
if (graphout) *graphout = g;
|
||||||
const char *rootpath = package_only && root_identity
|
const char *rootpath = package_only && root_identity
|
||||||
? root_identity : "";
|
? root_identity : "";
|
||||||
|
int support_for[SEP_MAXPRODUCT];
|
||||||
|
for (int i = 0; i < nproducts; i++) support_for[i] = -1;
|
||||||
for (int i = 0; i < nproducts; i++) {
|
for (int i = 0; i < nproducts; i++) {
|
||||||
const char *entry = products[i].dir != NULL
|
const char *entry = products[i].dir != NULL
|
||||||
? products[i].dir : src;
|
? products[i].dir : src;
|
||||||
@@ -1720,11 +1803,15 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
entry_is_dir, products[i].variant, products[i].test_package,
|
entry_is_dir, products[i].variant, products[i].test_package,
|
||||||
SEP_ROLE_NORMAL, products[i].artifact, 1);
|
SEP_ROLE_NORMAL, products[i].artifact, 1);
|
||||||
if (products[i].root < 0) return 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";
|
const char *test_support_module = "test";
|
||||||
/* -T generates a dispatcher whose support qualifier is selected by the
|
/* -T generates a dispatcher whose support qualifier is selected by the
|
||||||
* command. Represent that compiler-generated requirement as a direct root
|
* command. Represent that compiler-generated requirement as a direct edge
|
||||||
* edge. It normally coalesces with an explicit toolchain `import test`;
|
* of the generated-main action. It normally coalesces with an explicit
|
||||||
|
* toolchain `import test`;
|
||||||
* when user source occupies that identity, the reserved graph alias keeps
|
* when user source occupies that identity, the reserved graph alias keeps
|
||||||
* it distinct. The linker receives the same support archive closure. */
|
* it distinct. The linker receives the same support archive closure. */
|
||||||
if (is_test) {
|
if (is_test) {
|
||||||
@@ -1770,8 +1857,10 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
* colocated production node, which is also its support dep. */
|
* colocated production node, which is also its support dep. */
|
||||||
if (root_is_support
|
if (root_is_support
|
||||||
&& strcmp(test_support_module, "test") == 0
|
&& strcmp(test_support_module, "test") == 0
|
||||||
&& products[i].variant != SEP_VARIANT_EXTERNAL)
|
&& products[i].variant != SEP_VARIANT_EXTERNAL) {
|
||||||
|
support_for[i] = root;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
int ti;
|
int ti;
|
||||||
if (strcmp(test_support_module,
|
if (strcmp(test_support_module,
|
||||||
SEP_TEST_SUPPORT_MODULE) == 0)
|
SEP_TEST_SUPPORT_MODULE) == 0)
|
||||||
@@ -1782,19 +1871,27 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
tdir);
|
tdir);
|
||||||
if (ti < 0) return 1;
|
if (ti < 0) return 1;
|
||||||
g->pkg[ti].test_support = 1;
|
g->pkg[ti].test_support = 1;
|
||||||
int seen = 0;
|
support_for[i] = ti;
|
||||||
for (int k = 0; k < g->pkg[root].ndeps; k++)
|
|
||||||
if (g->pkg[root].deps[k] == ti) {
|
|
||||||
seen = 1; break;
|
|
||||||
}
|
|
||||||
if (!seen && g->pkg[root].ndeps < SEP_MAXPKG)
|
|
||||||
g->pkg[root].deps[g->pkg[root].ndeps++] = ti;
|
|
||||||
}
|
}
|
||||||
free(tc);
|
free(tc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < nproducts; i++) {
|
for (int i = 0; i < nproducts; i++) {
|
||||||
int root = products[i].root;
|
int root = products[i].variant_root;
|
||||||
|
/* Raw single-file test fixtures are the one retained non-directory
|
||||||
|
* exception: keep compiler-owned test-main synthesis in that action.
|
||||||
|
* Its support export is still an exact direct input. */
|
||||||
|
if (is_test && !entry_is_dir) {
|
||||||
|
int support = support_for[i];
|
||||||
|
if (support >= 0 && support != root) {
|
||||||
|
int seen = 0;
|
||||||
|
for (int k = 0; k < g->pkg[root].ndeps; k++)
|
||||||
|
if (g->pkg[root].deps[k] == support) seen = 1;
|
||||||
|
if (!seen)
|
||||||
|
g->pkg[root].deps[g->pkg[root].ndeps++] = support;
|
||||||
|
}
|
||||||
|
g->pkg[root].link_entry = 1;
|
||||||
|
}
|
||||||
if (sep_load_pkg(g, root, products[i].context) < 0) {
|
if (sep_load_pkg(g, root, products[i].context) < 0) {
|
||||||
g->pkg[root].failed = 1;
|
g->pkg[root].failed = 1;
|
||||||
continue;
|
continue;
|
||||||
@@ -1808,6 +1905,22 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
g->pkg[root].failed = 1;
|
g->pkg[root].failed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (is_test && entry_is_dir) {
|
||||||
|
for (int i = 0; i < nproducts; i++) {
|
||||||
|
int variant = products[i].variant_root;
|
||||||
|
int support = support_for[i];
|
||||||
|
if (support >= 0 && support != variant
|
||||||
|
&& sep_load_pkg(g, support, products[i].context) < 0)
|
||||||
|
g->pkg[variant].failed = 1;
|
||||||
|
int mainpkg = sep_add_generated_main(g, &products[i], i,
|
||||||
|
support);
|
||||||
|
if (mainpkg < 0) return 1;
|
||||||
|
if (g->pkg[variant].failed
|
||||||
|
|| (support >= 0 && g->pkg[support].failed))
|
||||||
|
g->pkg[mainpkg].failed = 1;
|
||||||
|
products[i].root = mainpkg;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sep_validate_artifact_paths(g, scratch) < 0)
|
if (sep_validate_artifact_paths(g, scratch) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
int root_package = package_only;
|
int root_package = package_only;
|
||||||
@@ -1830,8 +1943,7 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
||||||
int ignored = 0;
|
int ignored = 0;
|
||||||
if (sep_topo_visit(g, root, order, &ignored, stack, 0) < 0
|
if (sep_topo_visit(g, root, order, &ignored, stack, 0) < 0
|
||||||
|| sep_validate_module_closure(g, order, ignored,
|
|| sep_validate_module_closure(g, order, ignored, 1) < 0)
|
||||||
root_package) < 0)
|
|
||||||
g->pkg[root].failed = 1;
|
g->pkg[root].failed = 1;
|
||||||
}
|
}
|
||||||
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
||||||
@@ -1843,11 +1955,6 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(stack);
|
free(stack);
|
||||||
if (!root_package)
|
|
||||||
for (int i = 0; i < nproducts; i++)
|
|
||||||
if (g->pkg[products[i].root].path[0] != '\0')
|
|
||||||
g->pkg[products[i].root].path[0] = '\0';
|
|
||||||
|
|
||||||
int any_failed = 0;
|
int any_failed = 0;
|
||||||
for (int i = 0; i < nproducts; i++)
|
for (int i = 0; i < nproducts; i++)
|
||||||
if (g->pkg[products[i].root].failed) any_failed = 1;
|
if (g->pkg[products[i].root].failed) any_failed = 1;
|
||||||
@@ -1882,8 +1989,6 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
const char *cs = warm ? asmnew : asmf;
|
const char *cs = warm ? asmnew : asmf;
|
||||||
const char *co = warm ? objnew : obj;
|
const char *co = warm ? objnew : obj;
|
||||||
const char *ca = warm ? anew : apath;
|
const char *ca = warm ? anew : apath;
|
||||||
int needs_export = !g->pkg[pi].root || root_package;
|
|
||||||
int needs_archive = !g->pkg[pi].root || root_package;
|
|
||||||
if (sep_compose_unit(g, pi, cu) < 0) {
|
if (sep_compose_unit(g, pi, cu) < 0) {
|
||||||
g->pkg[pi].failed = 1;
|
g->pkg[pi].failed = 1;
|
||||||
any_failed = 1;
|
any_failed = 1;
|
||||||
@@ -1896,9 +2001,9 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
if (warm && !stale_all && !deps_changed
|
if (warm && !stale_all && !deps_changed
|
||||||
&& file_equal(unitnew, unitf)
|
&& file_equal(unitnew, unitf)
|
||||||
&& file_is_reg(asmf)
|
&& file_is_reg(asmf)
|
||||||
&& (!needs_export || file_is_reg(wwi))
|
&& file_is_reg(wwi)
|
||||||
&& (emit_asm || (file_size_nonzero(obj)
|
&& (emit_asm || (file_size_nonzero(obj)
|
||||||
&& (!needs_archive || file_size_nonzero(apath))))) {
|
&& file_size_nonzero(apath)))) {
|
||||||
if (unlink(unitnew) != 0) {
|
if (unlink(unitnew) != 0) {
|
||||||
fprintf(stderr, "ww: cannot remove %s\n",
|
fprintf(stderr, "ww: cannot remove %s\n",
|
||||||
unitnew);
|
unitnew);
|
||||||
@@ -1907,13 +2012,6 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* BUG-1 (#69): -I <wwi> is purely the root's UNUSED
|
|
||||||
* `.wwi` output path, but it triggers wwi_emit →
|
|
||||||
* check_exported_type on the root. A terminal binary's
|
|
||||||
* root legitimately has `export fn` over an unexported
|
|
||||||
* LOCAL type (the root is never imported), which the
|
|
||||||
* export-check rejects. Skip -I for the root; its `.wwi`
|
|
||||||
* is never consumed. */
|
|
||||||
size_t cargvcap = (size_t)(12 + 3 * g->pkg[pi].ndeps);
|
size_t cargvcap = (size_t)(12 + 3 * g->pkg[pi].ndeps);
|
||||||
char **cargv = calloc(cargvcap, sizeof *cargv);
|
char **cargv = calloc(cargvcap, sizeof *cargv);
|
||||||
char (*importfiles)[SEP_ARTIFACT_MAX] = NULL;
|
char (*importfiles)[SEP_ARTIFACT_MAX] = NULL;
|
||||||
@@ -1930,16 +2028,21 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
}
|
}
|
||||||
int cpos = 0;
|
int cpos = 0;
|
||||||
cargv[cpos++] = "w6c";
|
cargv[cpos++] = "w6c";
|
||||||
if (!needs_export && is_test && g->pkg[pi].root) {
|
if (g->pkg[pi].generated_main
|
||||||
/* #79: the root carries -T under `ww test`
|
|| (is_test && g->pkg[pi].root && !g->pkg[pi].is_dir)) {
|
||||||
* so w6c synthesizes the test main. Deps never
|
|
||||||
* get -T. */
|
|
||||||
cargv[cpos++] = "-T";
|
cargv[cpos++] = "-T";
|
||||||
|
cargv[cpos++] = "--entry";
|
||||||
cargv[cpos++] = "--test-support-module";
|
cargv[cpos++] = "--test-support-module";
|
||||||
cargv[cpos++] = (char *)test_support_module;
|
cargv[cpos++] = (char *)test_support_module;
|
||||||
} else if (needs_export && g->pkg[pi].test_support) {
|
} else {
|
||||||
cargv[cpos++] = "--test-support-module";
|
if (is_test && g->pkg[pi].root)
|
||||||
cargv[cpos++] = (char *)test_support_module;
|
cargv[cpos++] = "--test-package";
|
||||||
|
if (g->pkg[pi].link_entry)
|
||||||
|
cargv[cpos++] = "--entry";
|
||||||
|
if (g->pkg[pi].test_support) {
|
||||||
|
cargv[cpos++] = "--test-support-module";
|
||||||
|
cargv[cpos++] = (char *)test_support_module;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cargv[cpos++] = "-c";
|
cargv[cpos++] = "-c";
|
||||||
for (int k = 0; k < g->pkg[pi].ndeps; k++) {
|
for (int k = 0; k < g->pkg[pi].ndeps; k++) {
|
||||||
@@ -1950,10 +2053,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
cargv[cpos++] = g->pkg[dj].path;
|
cargv[cpos++] = g->pkg[dj].path;
|
||||||
cargv[cpos++] = importfiles[k];
|
cargv[cpos++] = importfiles[k];
|
||||||
}
|
}
|
||||||
if (needs_export) {
|
cargv[cpos++] = "-I";
|
||||||
cargv[cpos++] = "-I";
|
cargv[cpos++] = (char *)cw;
|
||||||
cargv[cpos++] = (char *)cw;
|
|
||||||
}
|
|
||||||
cargv[cpos++] = "-o";
|
cargv[cpos++] = "-o";
|
||||||
cargv[cpos++] = (char *)cs;
|
cargv[cpos++] = (char *)cs;
|
||||||
cargv[cpos++] = (char *)cu;
|
cargv[cpos++] = (char *)cu;
|
||||||
@@ -1968,9 +2069,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
any_failed = 1;
|
any_failed = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (needs_export)
|
g->pkg[pi].export_changed = !warm
|
||||||
g->pkg[pi].export_changed = !warm
|
|| !file_equal(wwinew, wwi);
|
||||||
|| !file_equal(wwinew, wwi);
|
|
||||||
if (!emit_asm) {
|
if (!emit_asm) {
|
||||||
char *aargv[] = {"w6a", "-o", (char *)co,
|
char *aargv[] = {"w6a", "-o", (char *)co,
|
||||||
(char *)cs, NULL};
|
(char *)cs, NULL};
|
||||||
@@ -1982,12 +2082,9 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* wrap each DEP package's `.o` in its own deterministic `.a`
|
/* Every package action, including executable and generated-test roots,
|
||||||
* (5a). The ROOT stays a positional `.o` (force-loaded — it's
|
* produces the existing deterministic single-member archive. */
|
||||||
* the build target, always fully linked), so `main` is defined
|
if (!emit_asm) {
|
||||||
* before any archive is processed. The link consumes `.o`/`.a`,
|
|
||||||
* never `.wwi`. */
|
|
||||||
if (!emit_asm && needs_archive) {
|
|
||||||
if (archive_o(co, ca) != 0) {
|
if (archive_o(co, ca) != 0) {
|
||||||
fprintf(stderr, "ww: archive failed for %s\n",
|
fprintf(stderr, "ww: archive failed for %s\n",
|
||||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||||
@@ -1999,11 +2096,10 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
/* Commit order: artifacts before the unit that vouches for
|
/* Commit order: artifacts before the unit that vouches for
|
||||||
* them, unit strictly last. */
|
* them, unit strictly last. */
|
||||||
if (warm) {
|
if (warm) {
|
||||||
if ((needs_export && rename(wwinew, wwi) != 0)
|
if (rename(wwinew, wwi) != 0
|
||||||
|| rename(asmnew, asmf) != 0
|
|| rename(asmnew, asmf) != 0
|
||||||
|| (!emit_asm && rename(objnew, obj) != 0)
|
|| (!emit_asm && rename(objnew, obj) != 0)
|
||||||
|| (!emit_asm && needs_archive
|
|| (!emit_asm && rename(anew, apath) != 0)
|
||||||
&& rename(anew, apath) != 0)
|
|
||||||
|| rename(unitnew, unitf) != 0) {
|
|| rename(unitnew, unitf) != 0) {
|
||||||
fprintf(stderr, "ww: cannot commit %s\n",
|
fprintf(stderr, "ww: cannot commit %s\n",
|
||||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||||
@@ -2066,10 +2162,10 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(order);
|
free(order);
|
||||||
/* Each product gets its own reverse-topological closure: root `.o` first,
|
/* Each product gets its own reverse-topological archive closure: root `.a`
|
||||||
* then every transitively reachable dependency `.a`, then libwwrt.a. A
|
* first, then every transitively reachable package `.a`, then libwwrt.a. An
|
||||||
* same-test root already contains its production sources, so its colocated
|
* internal test variant already contains production sources, so its
|
||||||
* production archive is omitted without dropping that node's dependencies. */
|
* colocated production archive is omitted without dropping dependencies. */
|
||||||
char rtpaths[2][1024];
|
char rtpaths[2][1024];
|
||||||
int nrt = 1;
|
int nrt = 1;
|
||||||
snprintf(rtpaths[0], sizeof rtpaths[0], "%s/libwwrt.a", libdir);
|
snprintf(rtpaths[0], sizeof rtpaths[0], "%s/libwwrt.a", libdir);
|
||||||
@@ -2084,6 +2180,7 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
int nlibs = linkflags ? linkflags->nlibs : 0;
|
int nlibs = linkflags ? linkflags->nlibs : 0;
|
||||||
for (int i = 0; i < nproducts; i++) {
|
for (int i = 0; i < nproducts; i++) {
|
||||||
int root = products[i].root;
|
int root = products[i].root;
|
||||||
|
int variant_root = products[i].variant_root;
|
||||||
if (g->pkg[root].failed) { any_failed = 1; continue; }
|
if (g->pkg[root].failed) { any_failed = 1; continue; }
|
||||||
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
||||||
int *linkorder = calloc((size_t)g->n, sizeof *linkorder);
|
int *linkorder = calloc((size_t)g->n, sizeof *linkorder);
|
||||||
@@ -2110,14 +2207,15 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
|||||||
largv[pos++] = (char *)products[i].out;
|
largv[pos++] = (char *)products[i].out;
|
||||||
for (int oi = nlink - 1; oi >= 0; oi--) {
|
for (int oi = nlink - 1; oi >= 0; oi--) {
|
||||||
int pi = linkorder[oi];
|
int pi = linkorder[oi];
|
||||||
if (g->pkg[root].variant == SEP_VARIANT_SAME_TEST
|
if (variant_root >= 0
|
||||||
&& pi != root
|
&& g->pkg[variant_root].variant == SEP_VARIANT_SAME_TEST
|
||||||
|
&& pi != variant_root
|
||||||
&& g->pkg[pi].variant == SEP_VARIANT_PRODUCTION
|
&& g->pkg[pi].variant == SEP_VARIANT_PRODUCTION
|
||||||
&& g->pkg[pi].role != SEP_ROLE_TEST_SUPPORT
|
&& g->pkg[pi].role != SEP_ROLE_TEST_SUPPORT
|
||||||
&& strcmp(g->pkg[pi].canon, g->pkg[root].canon) == 0)
|
&& strcmp(g->pkg[pi].canon,
|
||||||
|
g->pkg[variant_root].canon) == 0)
|
||||||
continue;
|
continue;
|
||||||
sep_fname(g, pi, scratch,
|
sep_fname(g, pi, scratch, ".a", linkpaths[npath],
|
||||||
pi == root ? ".o" : ".a", linkpaths[npath],
|
|
||||||
sizeof linkpaths[npath]);
|
sizeof linkpaths[npath]);
|
||||||
largv[pos++] = linkpaths[npath++];
|
largv[pos++] = linkpaths[npath++];
|
||||||
}
|
}
|
||||||
@@ -2174,7 +2272,10 @@ build_one_sep(const char *src, int entry_is_dir, const char *root_identity,
|
|||||||
.artifact = {0},
|
.artifact = {0},
|
||||||
.variant = root_variant,
|
.variant = root_variant,
|
||||||
.root = -1,
|
.root = -1,
|
||||||
|
.variant_root = -1,
|
||||||
};
|
};
|
||||||
|
if (!package_only)
|
||||||
|
snprintf(product.artifact, sizeof product.artifact, "__root");
|
||||||
int r = build_one_sep_impl(src, entry_is_dir, root_identity, out, objstem,
|
int r = build_one_sep_impl(src, entry_is_dir, root_identity, out, objstem,
|
||||||
extra_includes, linkflags, package_only, is_test,
|
extra_includes, linkflags, package_only, is_test,
|
||||||
&product, 1, emit_asm, workdir, scratch,
|
&product, 1, emit_asm, workdir, scratch,
|
||||||
@@ -2612,6 +2713,7 @@ do_test(int argc, char **argv)
|
|||||||
products[nproducts].artifact[0] = '\0';
|
products[nproducts].artifact[0] = '\0';
|
||||||
products[nproducts].variant = variant;
|
products[nproducts].variant = variant;
|
||||||
products[nproducts].root = -1;
|
products[nproducts].root = -1;
|
||||||
|
products[nproducts].variant_root = -1;
|
||||||
nproducts++;
|
nproducts++;
|
||||||
} else if (strcmp(argv[i], "-S") == 0) {
|
} else if (strcmp(argv[i], "-S") == 0) {
|
||||||
emit_asm = 1;
|
emit_asm = 1;
|
||||||
|
|||||||
@@ -2810,15 +2810,16 @@ the final component of its import path; two logical identities for one physical
|
|||||||
directory are rejected rather than compiled twice.
|
directory are rejected rather than compiled twice.
|
||||||
|
|
||||||
Packages compile serially in dependency-first postorder. The compiler emits the
|
Packages compile serially in dependency-first postorder. The compiler emits the
|
||||||
existing deterministic `.wwi` interface for every importable package. Its
|
existing deterministic `.wwi` interface for every directory-package action,
|
||||||
primary section contains that package's byte-sorted direct imports and exported
|
including an executable root. Its primary section contains that package's
|
||||||
declarations. The compiler then appends byte-sorted, origin-tagged sections for
|
byte-sorted direct imports and exported declarations. The compiler then appends
|
||||||
only the exported foreign type and constant facts recursively reachable from
|
byte-sorted, origin-tagged sections for only the foreign type and constant facts
|
||||||
the primary public signatures. This makes each direct dependency interface
|
recursively reachable from the primary public signatures. Reachable owner-local
|
||||||
self-contained for the public type information its consumers need while
|
private nominal types are carried without `export`: they make the export
|
||||||
retaining the deeper declarations' original package identity. Checked fixed
|
self-contained for type checking, but qualified source lookup still rejects
|
||||||
array dimensions are emitted as numeric type facts, so a public layout never
|
their names. Checked fixed array dimensions are emitted as numeric type facts,
|
||||||
requires exposing the private constant spelling that produced its length.
|
so a public layout never requires exposing the private constant spelling that
|
||||||
|
produced its length.
|
||||||
|
|
||||||
A package compilation unit contains only that package's own byte-sorted sources
|
A package compilation unit contains only that package's own byte-sorted sources
|
||||||
and deterministic `//ww:module-reset` separators. Each **direct** import is a
|
and deterministic `//ww:module-reset` separators. Each **direct** import is a
|
||||||
@@ -2835,19 +2836,25 @@ source-like `.wwi` syntax remains a transitional export encoding pending the
|
|||||||
binary `.wwe` format described above, but the separate direct-input ownership
|
binary `.wwe` format described above, but the separate direct-input ownership
|
||||||
boundary is live in production Cstage and WWstage compilers and drivers.
|
boundary is live in production Cstage and WWstage compilers and drivers.
|
||||||
|
|
||||||
An ordinary root is linked with the full reachable object closure into the
|
An ordinary executable directory root is one normal package action. Its
|
||||||
requested executable (legacy WW programs may use a package name other than
|
declared package identity tags its owner-only unit; it receives only direct
|
||||||
`main`). `ww build -p -o lib.a DIR` explicitly requests a non-main package
|
exports, emits `.wwi`, `.o`, and a deterministic `.a`, and is compiled exactly
|
||||||
product: it emits a deterministic archive at `lib.a` and its compiler interface
|
once. The narrow compiler `--entry` flag controls only bare `main` codegen and is
|
||||||
at `lib.a.wwi`, without invoking the linker. A logical target retains its full
|
independent of export production. 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.
|
||||||
|
|
||||||
|
`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),
|
identity (`ww build -p -I ROOT -o bar.a foo.bar` emits `foo.bar.*` symbols),
|
||||||
while a literal directory uses its declared leaf package. Package output
|
while a literal directory uses its declared leaf package. Package output
|
||||||
requires a directory and `-p` cannot be combined with assembly-only `-S`. Two
|
requires a directory and `-p` cannot be combined with assembly-only `-S`. Two
|
||||||
cold builds with identical inputs are required to produce byte-identical
|
cold builds with identical inputs are required to produce byte-identical
|
||||||
requested products. Compiler intrinsics keep their package-mode runtime ABI
|
requested products. Compiler intrinsics keep their package-mode runtime ABI
|
||||||
independent of transitive source interfaces (for example, `alloc` lowers to the
|
independent of transitive source interfaces (for example, `alloc` lowers to the
|
||||||
runtime allocator without requiring an `rt.wwi` compiler input), while the
|
runtime allocator without requiring an `rt.wwi` compiler input).
|
||||||
linker still receives every reachable package archive plus the runtime archive.
|
|
||||||
|
|
||||||
### 11.7 Implemented directory package-test slice
|
### 11.7 Implemented directory package-test slice
|
||||||
|
|
||||||
@@ -2868,11 +2875,14 @@ semantic selections are only the directory and selected variant/package
|
|||||||
identities; it also carries output destinations, coordinator-private completion
|
identities; it also carries output destinations, coordinator-private completion
|
||||||
paths, import search roots, and the optional command-scoped work-directory
|
paths, import search roots, and the optional command-scoped work-directory
|
||||||
policy. The command owns source selection, package loading, compiler inputs,
|
policy. The command owns source selection, package loading, compiler inputs,
|
||||||
archive construction, and linking for every non-importable root:
|
archive construction, generated-main construction, and linking for every
|
||||||
|
package variant:
|
||||||
|
|
||||||
- `same-test` selects the byte-sorted production files followed by the
|
- The ordinary production action selects the directory's byte-sorted
|
||||||
byte-sorted matching `package p` test files. They form one compiler unit, so
|
non-test files and is reused wherever that canonical package is imported.
|
||||||
tests can use private production declarations.
|
- `same-test` is a distinct internal production-plus-test action. It selects
|
||||||
|
the byte-sorted production files followed by the byte-sorted matching
|
||||||
|
`package p` test files, so tests can use private production declarations.
|
||||||
- `external-test` selects only matching `package p_test` files. Its `import p`
|
- `external-test` selects only matching `package p_test` files. Its `import p`
|
||||||
is a direct edge to the canonical production action for that directory.
|
is a direct edge to the canonical production action for that directory.
|
||||||
That action compiles with module qualifier `p`, selects every production
|
That action compiles with module qualifier `p`, selects every production
|
||||||
@@ -2882,17 +2892,23 @@ archive construction, and linking for every non-importable root:
|
|||||||
owning root, such as `__ww-test-001-external-production`; a normal import of
|
owning root, such as `__ww-test-001-external-production`; a normal import of
|
||||||
the same `p` and canonical directory reuses that action rather than creating
|
the same `p` and canonical directory reuses that action rather than creating
|
||||||
a second compilation.
|
a second compilation.
|
||||||
|
- Each selected internal or external variant gets a distinct generated-main
|
||||||
|
package action. Its generated owner-only unit declares `package main` and
|
||||||
|
imports exactly the selected variant and test-support package. It consumes
|
||||||
|
exactly those direct `.wwi` artifacts, emits its own `.wwi/.o/.a`, and alone
|
||||||
|
receives compiler `-T --entry`.
|
||||||
|
|
||||||
The command loads all roots into one command-scoped package universe. Each root
|
The command loads all variants into one command-scoped package universe.
|
||||||
retains an injective artifact key derived from its deterministic request ordinal
|
Directory variants retain injective artifact keys such as
|
||||||
and variant, such as `__ww-test-000-same` or
|
`__ww-test-000-same` or `__ww-test-003-external`; their generated mains use
|
||||||
`__ww-test-003-external`. Hyphens make that namespace illegal as a WW import
|
matching `__ww-test-NNN-main` keys and distinct internal package identities.
|
||||||
identity. Imports of the same canonical production directory intern to one
|
Hyphens keep artifact keys illegal as WW import identities. Repeated requests
|
||||||
production node across every selected test directory. A deterministic
|
for the same canonical directory and variant reuse one compile action, and
|
||||||
dependency-first traversal of the complete union therefore invokes the
|
imports of the same canonical production directory intern to one production
|
||||||
compiler and archiver once for every reachable canonical production package,
|
action across every selected test product. A deterministic dependency-first
|
||||||
even when many directory products need it. Each root is still compiled once
|
traversal of the complete union therefore invokes the compiler and archiver
|
||||||
with its own selected sources and linked separately. The shared plan is
|
once per package variant, even when many products share it. Generated-main
|
||||||
|
actions remain product-specific and are linked separately. The shared plan is
|
||||||
deliberately package-test-specific: it is not a generalized scheduler, action
|
deliberately package-test-specific: it is not a generalized scheduler, action
|
||||||
schema, cache, or protocol.
|
schema, cache, or protocol.
|
||||||
|
|
||||||
@@ -2914,26 +2930,30 @@ missing product as a build failure. The single union build and completed test
|
|||||||
products share the coordinator's existing `-j` process bound; captured output
|
products share the coordinator's existing `-j` process bound; captured output
|
||||||
is still emitted only in byte-sorted directory/package order.
|
is still emitted only in byte-sorted directory/package order.
|
||||||
|
|
||||||
Every non-root dependency is always a production variant, so dependency
|
Every source-imported dependency is a production variant, so dependency
|
||||||
`*_test.ww` files never enter the graph. Imports that occur only in selected
|
`*_test.ww` files never enter the graph. Imports that occur only in selected
|
||||||
test files add edges only to that test root. Each compiler unit contains only
|
test files add edges only to that internal or external variant. Each compiler
|
||||||
the variant's owned source set, while its invocation receives only the
|
unit contains only its action's owned source set, while its invocation receives
|
||||||
byte-sorted direct dependency `.wwi` artifacts as separate inputs. The final
|
only the byte-sorted direct dependency `.wwi` artifacts as separate inputs.
|
||||||
test link still receives the root object and the complete reverse-topological
|
Variant compiles receive `--test-package`, which validates and retains private
|
||||||
archive closure. The compiler-generated `-T` dispatcher owns the implicit
|
`@test` declarations as compiler-only export metadata without synthesizing an
|
||||||
direct test-runtime support edge and remains embedded in each independently
|
entry point. The distinct generated-main action consumes that metadata from its
|
||||||
compiled test root; it is the narrow test-main variant, not a
|
direct variant export and synthesizes the dispatcher with `-T`.
|
||||||
coordinator-generated graph package. The command-scoped plan compiles the
|
|
||||||
common runtime production package once for the complete test request. The
|
The generated-main action, rather than the tested variant, owns the implicit
|
||||||
command resolves that edge from the selected toolchain source tree, not the
|
direct test-runtime support edge. The command-scoped plan compiles the common
|
||||||
user search path; the support package's own imports are also loaded in that
|
support production package once for the complete test request. The command
|
||||||
toolchain context. Normally its graph
|
resolves that edge from the selected toolchain source tree, not the user search
|
||||||
|
path; the support package's own imports are also loaded in that toolchain
|
||||||
|
context. Normally its graph
|
||||||
qualifier is `test`, so an explicit source `import test` coalesces with the same
|
qualifier is `test`, so an explicit source `import test` coalesces with the same
|
||||||
canonical package. When a real user package occupies that identity, the command
|
canonical package. When a real user package occupies that identity, the command
|
||||||
presents the runtime edge to the compiler under the reserved `__wwtest`
|
presents the runtime edge to the compiler under the reserved `__wwtest`
|
||||||
qualifier. This keeps a production package named `test` available to external
|
qualifier. This keeps a production package named `test` available to external
|
||||||
tests while preserving raw `w6c -T` compatibility, whose default unresolved
|
tests. Explicit raw single-file `ww test FILE` fixtures retain the narrow fused
|
||||||
qualifier remains `test`.
|
`-T` compatibility path because an anonymous multi-package raw unit is not a
|
||||||
|
canonical directory package; that path still consumes support as a direct
|
||||||
|
export and emits a root `.wwi/.a`.
|
||||||
|
|
||||||
The reserved support action and an ordinary source-imported toolchain `test`
|
The reserved support action and an ordinary source-imported toolchain `test`
|
||||||
action may coexist in the command universe because their compiler qualifiers
|
action may coexist in the command universe because their compiler qualifiers
|
||||||
@@ -2947,24 +2967,25 @@ only narrow action-role exceptions: each product closure is checked to contain
|
|||||||
at most one importable action for a compiler module qualifier, so unrelated
|
at most one importable action for a compiler module qualifier, so unrelated
|
||||||
roles can never introduce duplicate linked package symbols.
|
roles can never introduce duplicate linked package symbols.
|
||||||
|
|
||||||
The selected test roots and a production variant reached by their imports or
|
The selected internal/external variants and a production action reached by
|
||||||
test-runtime closure are the only sanctioned graph nodes that may share a
|
their imports or test-runtime closure are the sanctioned graph nodes that may
|
||||||
physical directory. This also lets a toolchain package's own tests coexist with
|
share a physical directory. This also lets a toolchain package's own tests
|
||||||
the production variant required by the test runtime. A same-package root
|
coexist with the production action required by the test runtime. An internal
|
||||||
already defines those production symbols, so the production archive is omitted
|
variant already defines those production symbols, so the colocated production
|
||||||
from that product's final link while the production node's dependency archives
|
archive is omitted from that product's final link while the production action's
|
||||||
remain in its closure. A reserved compiler-support action at that same physical
|
dependency archives remain in the closure. The external product includes the
|
||||||
directory is still retained. The external product includes the production
|
production archive. Variant-only archives are never linked into another
|
||||||
archive.
|
product. All ordinary logical and physical package-identity collision checks
|
||||||
Variant-only archives are never linked into the other product. All ordinary
|
remain unchanged.
|
||||||
logical and physical package-identity collision checks remain unchanged.
|
|
||||||
The Cstage linker, like the WWstage linker, passes the root object, every
|
Both stage linkers receive the generated-main archive first, followed by the
|
||||||
reachable archive, the runtime, and explicit `-L`/`-l` values through a
|
complete reverse-topological reachable package-archive closure, runtime, and
|
||||||
structured argument vector; no fixed flattened command buffer can truncate a
|
explicit `-L`/`-l` values through a structured argument vector. No `.wwi` or
|
||||||
large closure. WWstage emits joined `-Ldir` and `-lname` arguments accepted by
|
special root `.o` appears in linker argv, and no fixed flattened command buffer
|
||||||
its native linker, while Cstage preserves the equivalent split forms. Generated
|
can truncate a large closure. WWstage emits joined `-Ldir` and `-lname`
|
||||||
artifact paths are bounds-checked before any unit is opened, so distinct root
|
arguments accepted by its native linker, while Cstage preserves the equivalent
|
||||||
keys cannot alias by truncation.
|
split forms. Generated artifact paths are bounds-checked before any unit is
|
||||||
|
opened, so distinct root keys cannot alias by truncation.
|
||||||
Recursive discovery groups by physical directory before sorting filenames, and
|
Recursive discovery groups by physical directory before sorting filenames, and
|
||||||
one stable escaped request key names the persistent command work directory.
|
one stable escaped request key names the persistent command work directory.
|
||||||
Every `*_test.ww` package variant is built even when a file only
|
Every `*_test.ww` package variant is built even when a file only
|
||||||
@@ -3021,7 +3042,7 @@ package, compiler actions receive direct dependency exports as individual
|
|||||||
arguments beside an owner-only `.unit.ww`, and links receive the complete
|
arguments beside an owner-only `.unit.ww`, and links receive the complete
|
||||||
per-root `.a` closure. Repository-native coverage wraps all three real stage
|
per-root `.a` closure. Repository-native coverage wraps all three real stage
|
||||||
tools at executable paths containing spaces, records every argument boundary,
|
tools at executable paths containing spaces, records every argument boundary,
|
||||||
inspects `.unit.ww`, `.wwi`, `.a`, and root object placement, runs the published
|
inspects `.unit.ww`, `.wwi`, `.a`, and root archive placement, runs the published
|
||||||
binary, compares repeated Cstage/WWstage artifacts and traces, and removes one
|
binary, compares repeated Cstage/WWstage artifacts and traces, and removes one
|
||||||
direct export at compiler entry to compare package-attributed diagnostics.
|
direct export at compiler entry to compare package-attributed diagnostics.
|
||||||
|
|
||||||
@@ -3198,22 +3219,26 @@ schema or identity record.
|
|||||||
The exact-argv regression uses the real diamond
|
The exact-argv regression uses the real diamond
|
||||||
`base -> {left,right} -> root`. It proves one compile per node; no input for
|
`base -> {left,right} -> root`. It proves one compile per node; no input for
|
||||||
`base`; only `base.wwi` for each middle node; only sorted `left.wwi` and
|
`base`; only `base.wwi` for each middle node; only sorted `left.wwi` and
|
||||||
`right.wwi` for `root`; exact owner-only unit bytes; the complete three-archive
|
`right.wwi` for `root`; exact owner-only unit bytes; the complete four-package
|
||||||
link closure; no link-time `.wwi`; exit status 42; and byte-identical units,
|
link closure including the root archive; no link-time `.wwi`; exit status 42;
|
||||||
exports, archives, executables, and tool argument vectors across two clean
|
and byte-identical units, exports, archives, executables, and tool argument
|
||||||
|
vectors across two clean
|
||||||
Cstage builds and two clean WWstage builds. The existing directory-package
|
Cstage builds and two clean WWstage builds. The existing directory-package
|
||||||
variant regression checks exact direct inputs for internal and external
|
variant regression checks separate production, internal, external, and
|
||||||
generated roots and the external-production action; both stages also compile
|
generated-main actions, exact generated-main direct variant/support exports,
|
||||||
and run ordinary production and support actions with owner-only units and
|
the external-production action, and archive-only link closures. Both stages
|
||||||
byte-identical artifacts.
|
compile and run those actions with owner-only units and byte-identical
|
||||||
|
artifacts.
|
||||||
|
|
||||||
The pinned Go 1.26.5 implementation supplies the design boundary:
|
The pinned official Go 1.26.5 tag (commit
|
||||||
|
`c19862e5f8415b4f24b189d065ed739517c548ba`) supplies the design boundary:
|
||||||
|
|
||||||
- Directory identity starts with `ImportDir`'s named directory
|
- Directory identity starts with `ImportDir`'s named directory
|
||||||
([`go/build/build.go`, lines 521–524](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#521)); directory reads are name-sorted
|
([`go/build/build.go`, lines 521–524](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#521)); directory reads are name-sorted
|
||||||
([lines 108–111](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#108)), lookup selects directory candidates
|
([lines 108–111](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#108)), lookup selects directory candidates
|
||||||
([lines 725–809](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#725)), and the selected directory is enumerated
|
([lines 725–809](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#725)), and the selected directory is enumerated
|
||||||
([lines 859–900](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#859)).
|
([lines 859–900](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#859)). The sorted iteration filters files and appends each source to exactly one ordinary/internal/external-test bucket
|
||||||
|
([lines 895–1036](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/build.go#895)).
|
||||||
- The loader records direct imports
|
- The loader records direct imports
|
||||||
([`load/pkg.go`, lines 220–225](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#220)), guarantees repeated cache loads return the same package pointer
|
([`load/pkg.go`, lines 220–225](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#220)), guarantees repeated cache loads return the same package pointer
|
||||||
([lines 633–636](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#633)), keys reuse by canonical import path
|
([lines 633–636](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#633)), keys reuse by canonical import path
|
||||||
@@ -3221,22 +3246,26 @@ The pinned Go 1.26.5 implementation supplies the design boundary:
|
|||||||
([lines 2776–2795](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#2776)).
|
([lines 2776–2795](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#2776)).
|
||||||
- Build actions are interned by mode and package identity
|
- Build actions are interned by mode and package identity
|
||||||
([`work/action.go`, lines 437–447](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#437)); compilation depends only on direct imports
|
([`work/action.go`, lines 437–447](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#437)); compilation depends only on direct imports
|
||||||
([lines 628–659](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#628)), whereas link actions expand transitive dependencies
|
([lines 628–659](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#628)), and even package `main` receives that normal interned archive-producing compile action
|
||||||
|
([lines 641–647](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#641)). A link action places that main compile action at its first dependency and expands transitive dependencies
|
||||||
([lines 918–957](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#918),
|
([lines 918–957](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#918),
|
||||||
[lines 1034–1068](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#1034)). The executor derives compiler import inputs from those direct actions
|
[lines 1034–1068](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#1034)). The executor derives compiler import inputs from those direct actions
|
||||||
([`work/exec.go`, lines 864–884](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#864)), passes them separately from source files
|
([`work/exec.go`, lines 864–884](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#864)), passes them separately from source files
|
||||||
([lines 928–930](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#928)), and separately emits the expanded linker closure
|
([lines 928–930](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#928)), packs remaining objects into the package archive and records it as the built result
|
||||||
([lines 1592–1647](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#1592)).
|
([lines 1017–1033](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#1017)), then supplies the root archive and all expanded package inputs to linking
|
||||||
|
([lines 1592–1624](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#1592),
|
||||||
|
[lines 1635–1647](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#1635)).
|
||||||
- Tests preserve four package roles
|
- Tests preserve four package roles
|
||||||
([`load/test.go`, lines 85–102](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#85)): internal production-plus-test
|
([`load/test.go`, lines 85–102](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#85)): internal production-plus-test
|
||||||
([lines 175–225](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#175)), external test
|
([lines 175–225](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#175)), external test
|
||||||
([lines 228–265](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#228)), and generated main
|
([lines 228–265](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#228)), and generated main
|
||||||
([lines 272–293](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#272)), with their distinct imports attached at
|
([lines 272–293](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#272)). Its support imports are loaded for that generated package
|
||||||
|
([lines 307–332](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#307)), with the selected internal/external variants attached as distinct direct imports at
|
||||||
[lines 351–373](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#351).
|
[lines 351–373](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#351).
|
||||||
- Unified export writing re-links, re-exports, and prunes facts
|
- Unified export writing re-links, re-exports, and prunes facts
|
||||||
([`noder/unified.go`, lines 152–165](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/unified.go#152)), finalizes self-contained data
|
([`noder/unified.go`, lines 152–165](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/unified.go#152)), finalizes self-contained data
|
||||||
([lines 463–470](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/unified.go#463)), and sorts declarations and bodies before serialization
|
([lines 463–470](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/unified.go#463)), selects export roots, and sorts declaration and body indices before serialization
|
||||||
([lines 514–570](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/unified.go#514)). Compiler import lookup opens the separately mapped artifact
|
([lines 495–570](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/unified.go#495)). Compiler import lookup opens the separately mapped artifact
|
||||||
([`noder/import.go`, lines 61–101](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/import.go#61)) and decodes its exports independently of source parsing
|
([`noder/import.go`, lines 61–101](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/import.go#61)) and decodes its exports independently of source parsing
|
||||||
([lines 170–225](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/import.go#170)); `ReadPackage` consumes that package decoder
|
([lines 170–225](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/import.go#170)); `ReadPackage` consumes that package decoder
|
||||||
([`importer/ureader.go`, lines 28–62](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/importer/ureader.go#28)).
|
([`importer/ureader.go`, lines 28–62](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/importer/ureader.go#28)).
|
||||||
|
|||||||
@@ -447,9 +447,11 @@ fn dirfileattest(dirpath: *u8, name: *u8) i32 = {
|
|||||||
def SEP_VARIANT_PRODUCTION: i32 = 0;
|
def SEP_VARIANT_PRODUCTION: i32 = 0;
|
||||||
def SEP_VARIANT_SAME_TEST: i32 = 1;
|
def SEP_VARIANT_SAME_TEST: i32 = 1;
|
||||||
def SEP_VARIANT_EXTERNAL: i32 = 2;
|
def SEP_VARIANT_EXTERNAL: i32 = 2;
|
||||||
|
def SEP_VARIANT_TEST_MAIN: i32 = 3;
|
||||||
def SEP_ROLE_NORMAL: i32 = 0;
|
def SEP_ROLE_NORMAL: i32 = 0;
|
||||||
def SEP_ROLE_EXTERNAL_PRODUCTION: i32 = 1;
|
def SEP_ROLE_EXTERNAL_PRODUCTION: i32 = 1;
|
||||||
def SEP_ROLE_TEST_SUPPORT: i32 = 2;
|
def SEP_ROLE_TEST_SUPPORT: i32 = 2;
|
||||||
|
def SEP_ROLE_GENERATED_MAIN: i32 = 3;
|
||||||
def SEP_TEST_SUPPORT_MODULE: str = "__wwtest";
|
def SEP_TEST_SUPPORT_MODULE: str = "__wwtest";
|
||||||
def SEP_MAXPRODUCT: i32 = 256;
|
def SEP_MAXPRODUCT: i32 = 256;
|
||||||
def SEP_MAXCONTEXT: i32 = 257;
|
def SEP_MAXCONTEXT: i32 = 257;
|
||||||
@@ -757,7 +759,7 @@ type sepbind = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type seppkg = struct {
|
type seppkg = struct {
|
||||||
path: *u8, // dotted import path, NUL-term; root path[0]==0
|
path: *u8, // canonical dotted package identity, NUL-term
|
||||||
entry: *u8, // resolved package dir (or file, file root), NUL-term
|
entry: *u8, // resolved package dir (or file, file root), NUL-term
|
||||||
artifact: *u8, // non-importable product-root artifact key
|
artifact: *u8, // non-importable product-root artifact key
|
||||||
name: *u8, // validated declared name; directory packages only
|
name: *u8, // validated declared name; directory packages only
|
||||||
@@ -768,6 +770,8 @@ type seppkg = struct {
|
|||||||
variant: i32,
|
variant: i32,
|
||||||
role: i32,
|
role: i32,
|
||||||
root: bool,
|
root: bool,
|
||||||
|
linkentry: bool,
|
||||||
|
generatedmain: bool,
|
||||||
failed: bool,
|
failed: bool,
|
||||||
testsupport: bool,
|
testsupport: bool,
|
||||||
loaded: bool,
|
loaded: bool,
|
||||||
@@ -802,6 +806,7 @@ type sepproduct = struct {
|
|||||||
variant: i32,
|
variant: i32,
|
||||||
context: i32,
|
context: i32,
|
||||||
root: i32,
|
root: i32,
|
||||||
|
variantroot: i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
||||||
@@ -819,7 +824,17 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
|||||||
if (root && g.pkg[i].root) {
|
if (root && g.pkg[i].root) {
|
||||||
if (!samelocation) { i += 1; continue; };
|
if (!samelocation) { i += 1; continue; };
|
||||||
if (variant != g.pkg[i].variant) { i += 1; continue; };
|
if (variant != g.pkg[i].variant) { i += 1; continue; };
|
||||||
cerr("ww: duplicate package-test root ");
|
let sametest: bool = testpackage == nil
|
||||||
|
&& g.pkg[i].testpackage == nil;
|
||||||
|
if (testpackage != nil && g.pkg[i].testpackage != nil) {
|
||||||
|
sametest = cstreq(testpackage, g.pkg[i].testpackage);
|
||||||
|
};
|
||||||
|
if (g.pkg[i].role == role && cstreq(g.pkg[i].path, path)
|
||||||
|
&& sametest) {
|
||||||
|
// One directory variant is one compile action across products.
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
cerr("ww: incompatible package-test roots ");
|
||||||
cerr(pathstr(entry)); cerr("\n");
|
cerr(pathstr(entry)); cerr("\n");
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
@@ -923,6 +938,8 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
|||||||
g.pkg[g.n].variant = variant;
|
g.pkg[g.n].variant = variant;
|
||||||
g.pkg[g.n].role = role;
|
g.pkg[g.n].role = role;
|
||||||
g.pkg[g.n].root = root;
|
g.pkg[g.n].root = root;
|
||||||
|
g.pkg[g.n].linkentry = false;
|
||||||
|
g.pkg[g.n].generatedmain = false;
|
||||||
g.pkg[g.n].failed = false;
|
g.pkg[g.n].failed = false;
|
||||||
g.pkg[g.n].testsupport = false;
|
g.pkg[g.n].testsupport = false;
|
||||||
g.pkg[g.n].loaded = false;
|
g.pkg[g.n].loaded = false;
|
||||||
@@ -1356,6 +1373,79 @@ fn sepdepcmp(g: *sepgraph, a: i32, b: i32) i32 = {
|
|||||||
pathstr(g.pkg[b].artifact)): i32;
|
pathstr(g.pkg[b].artifact)): i32;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn generatedmainpath(index: i32) *u8 = {
|
||||||
|
let buf: []u8 = alloc([], 64u64)!;
|
||||||
|
buf.len = 64;
|
||||||
|
let off: u64 = strinto(buf.ptr, 0u64, "__wwtestmain.");
|
||||||
|
buf[off] = (((index / 100) % 10) + 48): u8; off += 1u64;
|
||||||
|
buf[off] = (((index / 10) % 10) + 48): u8; off += 1u64;
|
||||||
|
buf[off] = ((index % 10) + 48): u8; off += 1u64;
|
||||||
|
off = strinto(buf.ptr, off, ".main");
|
||||||
|
cstrseal(buf.ptr, off);
|
||||||
|
return buf.ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Materialize the generated test dispatcher as a normal package action. It
|
||||||
|
// owns a generated source unit and imports exactly its test variant/support.
|
||||||
|
fn sepaddgeneratedmain(g: *sepgraph, product: *sepproduct, ordinal: i32,
|
||||||
|
support: i32) i32 = {
|
||||||
|
if (g.n >= SEP_MAXPKG) {
|
||||||
|
cerr("ww: too many packages\n");
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
let variant: i32 = product.variantroot;
|
||||||
|
if (variant < 0 || variant >= g.n) { return -1; };
|
||||||
|
let p: *seppkg = &g.pkg[g.n];
|
||||||
|
p.path = generatedmainpath(ordinal);
|
||||||
|
p.entry = g.pkg[variant].entry;
|
||||||
|
p.artifact = productartifact(ordinal, SEP_VARIANT_TEST_MAIN);
|
||||||
|
p.name = arenadupcstr("main\0".ptr, 4u64);
|
||||||
|
p.testpackage = nil;
|
||||||
|
p.sources = nil;
|
||||||
|
p.nsources = 0;
|
||||||
|
p.isdir = 0;
|
||||||
|
p.variant = SEP_VARIANT_TEST_MAIN;
|
||||||
|
p.role = SEP_ROLE_GENERATED_MAIN;
|
||||||
|
p.root = true;
|
||||||
|
p.linkentry = true;
|
||||||
|
p.generatedmain = true;
|
||||||
|
p.failed = false;
|
||||||
|
p.testsupport = false;
|
||||||
|
p.loaded = true;
|
||||||
|
p.exportchanged = false;
|
||||||
|
p.emitcontext = product.context;
|
||||||
|
let cslot: []u8 = alloc([], SEP_MAXCONTEXT: u64)!;
|
||||||
|
cslot.len = SEP_MAXCONTEXT;
|
||||||
|
p.contextstate = cslot;
|
||||||
|
p.contextstate[product.context] = 2u8;
|
||||||
|
let emptybindings: []sepbind;
|
||||||
|
p.bindings = emptybindings;
|
||||||
|
let dslot: []i32 = alloc([], SEP_MAXPKG: u64)!;
|
||||||
|
dslot.len = SEP_MAXPKG;
|
||||||
|
p.deps = dslot;
|
||||||
|
p.ndeps = 1;
|
||||||
|
p.deps[0] = variant;
|
||||||
|
if (support >= 0 && support != variant) {
|
||||||
|
p.deps[p.ndeps] = support;
|
||||||
|
p.ndeps += 1;
|
||||||
|
};
|
||||||
|
let i: i32 = 1;
|
||||||
|
for (i < p.ndeps) {
|
||||||
|
let v: i32 = p.deps[i];
|
||||||
|
let j: i32 = i;
|
||||||
|
for (j > 0 && sepdepcmp(g, p.deps[j - 1], v) > 0) {
|
||||||
|
p.deps[j] = p.deps[j - 1];
|
||||||
|
j -= 1;
|
||||||
|
};
|
||||||
|
p.deps[j] = v;
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
p.color = 0;
|
||||||
|
let r: i32 = g.n;
|
||||||
|
g.n += 1;
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
// Load pi once: a directory node takes ownership of its sorted production
|
// Load pi once: a directory node takes ownership of its sorted production
|
||||||
// paths, then every selected-root context verifies the same canonical import
|
// paths, then every selected-root context verifies the same canonical import
|
||||||
// bindings before the package is compiled once.
|
// bindings before the package is compiled once.
|
||||||
@@ -1450,7 +1540,10 @@ fn seploadpkg(g: *sepgraph, pi: i32, context: i32) i32 = {
|
|||||||
g.pkg[pi].failed = true;
|
g.pkg[pi].failed = true;
|
||||||
return rc;
|
return rc;
|
||||||
};
|
};
|
||||||
if (g.pkg[pi].root && g.pkg[pi].path[0u64] == 0u8
|
// Directory roots acquire their canonical package identity. Explicit raw
|
||||||
|
// single-file compiler fixtures retain their anonymous multi-package reset.
|
||||||
|
if (g.pkg[pi].root && g.pkg[pi].isdir != 0
|
||||||
|
&& g.pkg[pi].path[0u64] == 0u8
|
||||||
&& g.pkg[pi].name != nil) {
|
&& g.pkg[pi].name != nil) {
|
||||||
g.pkg[pi].path = arenadupcstr(g.pkg[pi].name,
|
g.pkg[pi].path = arenadupcstr(g.pkg[pi].name,
|
||||||
cstrlen(g.pkg[pi].name));
|
cstrlen(g.pkg[pi].name));
|
||||||
@@ -1598,7 +1691,27 @@ fn sepcomposeunit(g: *sepgraph, pi: i32, unitf: *u8) i32 = {
|
|||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
let bodyrc: i32 = 0;
|
let bodyrc: i32 = 0;
|
||||||
if (g.pkg[pi].isdir != 0) {
|
if (g.pkg[pi].generatedmain) {
|
||||||
|
let head: str = "//ww:module-reset ";
|
||||||
|
let pkg: str = "\npackage main;\n";
|
||||||
|
if (!sepwriteall(u, head.ptr, head.len: u64)
|
||||||
|
|| !sepwriteall(u, g.pkg[pi].path, cstrlen(g.pkg[pi].path))
|
||||||
|
|| !sepwriteall(u, pkg.ptr, pkg.len: u64)) {
|
||||||
|
bodyrc = -1;
|
||||||
|
};
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < g.pkg[pi].ndeps && bodyrc == 0) {
|
||||||
|
let pre: str = "import ";
|
||||||
|
let end: str = ";\n";
|
||||||
|
let dep: *u8 = g.pkg[g.pkg[pi].deps[i]].path;
|
||||||
|
if (!sepwriteall(u, pre.ptr, pre.len: u64)
|
||||||
|
|| !sepwriteall(u, dep, cstrlen(dep))
|
||||||
|
|| !sepwriteall(u, end.ptr, end.len: u64)) {
|
||||||
|
bodyrc = -1;
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
} else { if (g.pkg[pi].isdir != 0) {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < g.pkg[pi].nsources && bodyrc == 0) {
|
for (i < g.pkg[pi].nsources && bodyrc == 0) {
|
||||||
bodyrc = sepemitbody(u, g.pkg[pi].sources[i], g.pkg[pi].path);
|
bodyrc = sepemitbody(u, g.pkg[pi].sources[i], g.pkg[pi].path);
|
||||||
@@ -1606,7 +1719,7 @@ fn sepcomposeunit(g: *sepgraph, pi: i32, unitf: *u8) i32 = {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
bodyrc = sepemitbody(u, g.pkg[pi].entry, g.pkg[pi].path);
|
bodyrc = sepemitbody(u, g.pkg[pi].entry, g.pkg[pi].path);
|
||||||
};
|
}; };
|
||||||
if (os.close(u) != 0) {
|
if (os.close(u) != 0) {
|
||||||
cerr("ww: cannot close package unit\n");
|
cerr("ww: cannot close package unit\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1691,8 +1804,8 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
|||||||
|
|
||||||
// buildonesep — discover deps, reverse-topo,
|
// buildonesep — discover deps, reverse-topo,
|
||||||
// the dependency-first producer loop (one `w6c -c -I` per package,
|
// the dependency-first producer loop (one `w6c -c -I` per package,
|
||||||
// each dependency `.o` wrapped in its own deterministic per-package `.a`), then a
|
// each package `.o` wrapped in its own deterministic per-package `.a`), then a
|
||||||
// reverse-topo `w6l` of the root `.o` + dependency `.a` set + libwwrt.a.
|
// reverse-topo `w6l` of the root `.a` + reachable `.a` set + libwwrt.a.
|
||||||
// Side files land in a cold `<stem>.sepwork` scratch dir. Twin of cstage
|
// Side files land in a cold `<stem>.sepwork` scratch dir. Twin of cstage
|
||||||
// build_one_sep.
|
// build_one_sep.
|
||||||
|
|
||||||
@@ -1811,14 +1924,14 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
|||||||
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||||
if (istest != 0) {
|
if (istest != 0) {
|
||||||
if (emitasm != 0) {
|
if (emitasm != 0) {
|
||||||
return "ww workdir fmt 7 mode test asm 1\n";
|
return "ww workdir fmt 8 mode test asm 1\n";
|
||||||
};
|
};
|
||||||
return "ww workdir fmt 7 mode test asm 0\n";
|
return "ww workdir fmt 8 mode test asm 0\n";
|
||||||
};
|
};
|
||||||
if (emitasm != 0) {
|
if (emitasm != 0) {
|
||||||
return "ww workdir fmt 6 mode build asm 1\n";
|
return "ww workdir fmt 7 mode build asm 1\n";
|
||||||
};
|
};
|
||||||
return "ww workdir fmt 6 mode build asm 0\n";
|
return "ww workdir fmt 7 mode build asm 0\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
fn stampmatches(path: *u8, want: str) bool = {
|
fn stampmatches(path: *u8, want: str) bool = {
|
||||||
@@ -2097,7 +2210,11 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
if (graphout != nil) { *graphout = g; };
|
if (graphout != nil) { *graphout = g; };
|
||||||
let rootpath: *u8 = "\0".ptr;
|
let rootpath: *u8 = "\0".ptr;
|
||||||
if (packageonly != 0 && rootidentity != nil) { rootpath = rootidentity; };
|
if (packageonly != 0 && rootidentity != nil) { rootpath = rootidentity; };
|
||||||
|
let supportfor: []i32 = alloc([], nproducts: u64)!;
|
||||||
|
supportfor.len = nproducts;
|
||||||
let producti: i32 = 0;
|
let producti: i32 = 0;
|
||||||
|
for (producti < nproducts) { supportfor[producti] = -1; producti += 1; };
|
||||||
|
producti = 0;
|
||||||
for (producti < nproducts) {
|
for (producti < nproducts) {
|
||||||
let entry: *u8 = src;
|
let entry: *u8 = src;
|
||||||
if (products[producti].dir != nil) {
|
if (products[producti].dir != nil) {
|
||||||
@@ -2113,12 +2230,16 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
products[producti].testpackage,
|
products[producti].testpackage,
|
||||||
SEP_ROLE_NORMAL, products[producti].artifact, true);
|
SEP_ROLE_NORMAL, products[producti].artifact, true);
|
||||||
if (products[producti].root < 0) { return 1; };
|
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;
|
producti += 1;
|
||||||
};
|
};
|
||||||
let testsupportmodule: str = "test";
|
let testsupportmodule: str = "test";
|
||||||
// -T generates a dispatcher whose support qualifier is selected by the
|
// -T generates a dispatcher whose support qualifier is selected by the
|
||||||
// command. Represent that compiler-generated requirement as a direct root
|
// command. Represent that requirement as a direct generated-main edge. It
|
||||||
// edge. It normally coalesces with an explicit toolchain `import test`;
|
// normally coalesces with an explicit toolchain `import test`;
|
||||||
// when user source occupies that identity, the reserved graph alias keeps
|
// when user source occupies that identity, the reserved graph alias keeps
|
||||||
// it distinct. The linker receives the same support archive closure.
|
// it distinct. The linker receives the same support archive closure.
|
||||||
if (istest != 0) {
|
if (istest != 0) {
|
||||||
@@ -2168,6 +2289,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
if (rootissupport
|
if (rootissupport
|
||||||
&& syntax.streq(testsupportmodule, "test")
|
&& syntax.streq(testsupportmodule, "test")
|
||||||
&& products[producti].variant != SEP_VARIANT_EXTERNAL) {
|
&& products[producti].variant != SEP_VARIANT_EXTERNAL) {
|
||||||
|
supportfor[producti] = root;
|
||||||
producti += 1;
|
producti += 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -2181,25 +2303,32 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
if (ti < 0) { return 1; };
|
if (ti < 0) { return 1; };
|
||||||
g.pkg[ti].testsupport = true;
|
g.pkg[ti].testsupport = true;
|
||||||
let seen: bool = false;
|
supportfor[producti] = ti;
|
||||||
let m: i32 = 0;
|
|
||||||
for (m < g.pkg[root].ndeps) {
|
|
||||||
if (g.pkg[root].deps[m] == ti) { seen = true; };
|
|
||||||
m += 1;
|
|
||||||
};
|
|
||||||
if (!seen) {
|
|
||||||
if (g.pkg[root].ndeps < SEP_MAXPKG) {
|
|
||||||
g.pkg[root].deps[g.pkg[root].ndeps] = ti;
|
|
||||||
g.pkg[root].ndeps += 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
producti += 1;
|
producti += 1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
producti = 0;
|
producti = 0;
|
||||||
for (producti < nproducts) {
|
for (producti < nproducts) {
|
||||||
let root: i32 = products[producti].root;
|
let root: i32 = products[producti].variantroot;
|
||||||
|
// Raw single-file tests retain the explicit fixture exception: test-main
|
||||||
|
// synthesis stays in that action and support remains a direct export.
|
||||||
|
if (istest != 0 && entryisdir == 0) {
|
||||||
|
let support: i32 = supportfor[producti];
|
||||||
|
if (support >= 0 && support != root) {
|
||||||
|
let seen: bool = false;
|
||||||
|
let sk: i32 = 0;
|
||||||
|
for (sk < g.pkg[root].ndeps) {
|
||||||
|
if (g.pkg[root].deps[sk] == support) { seen = true; };
|
||||||
|
sk += 1;
|
||||||
|
};
|
||||||
|
if (!seen) {
|
||||||
|
g.pkg[root].deps[g.pkg[root].ndeps] = support;
|
||||||
|
g.pkg[root].ndeps += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
g.pkg[root].linkentry = true;
|
||||||
|
};
|
||||||
if (seploadpkg(g, root, products[producti].context) < 0) {
|
if (seploadpkg(g, root, products[producti].context) < 0) {
|
||||||
g.pkg[root].failed = true;
|
g.pkg[root].failed = true;
|
||||||
producti += 1;
|
producti += 1;
|
||||||
@@ -2214,6 +2343,27 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
producti += 1;
|
producti += 1;
|
||||||
};
|
};
|
||||||
|
if (istest != 0 && entryisdir != 0) {
|
||||||
|
producti = 0;
|
||||||
|
for (producti < nproducts) {
|
||||||
|
let variant: i32 = products[producti].variantroot;
|
||||||
|
let support: i32 = supportfor[producti];
|
||||||
|
if (support >= 0 && support != variant) {
|
||||||
|
if (seploadpkg(g, support, products[producti].context) < 0) {
|
||||||
|
g.pkg[variant].failed = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let mainpkg: i32 = sepaddgeneratedmain(g, &products[producti],
|
||||||
|
producti, support);
|
||||||
|
if (mainpkg < 0) { return 1; };
|
||||||
|
if (g.pkg[variant].failed
|
||||||
|
|| (support >= 0 && g.pkg[support].failed)) {
|
||||||
|
g.pkg[mainpkg].failed = true;
|
||||||
|
};
|
||||||
|
products[producti].root = mainpkg;
|
||||||
|
producti += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
||||||
let rootpackage: bool = packageonly != 0;
|
let rootpackage: bool = packageonly != 0;
|
||||||
if (rootpackage && !g.pkg[products[0].root].failed
|
if (rootpackage && !g.pkg[products[0].root].failed
|
||||||
@@ -2239,8 +2389,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
let ignored: i32 = 0;
|
let ignored: i32 = 0;
|
||||||
if (septopovisit(g, root, order,
|
if (septopovisit(g, root, order,
|
||||||
&ignored, stack, 0) < 0
|
&ignored, stack, 0) < 0
|
||||||
|| sepvalidatemoduleclosure(g, order, ignored,
|
|| sepvalidatemoduleclosure(g, order, ignored, true) < 0) {
|
||||||
rootpackage) < 0) {
|
|
||||||
g.pkg[root].failed = true;
|
g.pkg[root].failed = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -2257,14 +2406,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
producti += 1;
|
producti += 1;
|
||||||
};
|
};
|
||||||
if (!rootpackage) {
|
|
||||||
producti = 0;
|
|
||||||
for (producti < nproducts) {
|
|
||||||
g.pkg[products[producti].root].path = "\0".ptr;
|
|
||||||
producti += 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let anyfailed: bool = false;
|
let anyfailed: bool = false;
|
||||||
producti = 0;
|
producti = 0;
|
||||||
for (producti < nproducts) {
|
for (producti < nproducts) {
|
||||||
@@ -2307,8 +2448,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
cu = unitnew; cw = wwinew; cs = asmnew;
|
cu = unitnew; cw = wwinew; cs = asmnew;
|
||||||
co = objnew; ca = anew;
|
co = objnew; ca = anew;
|
||||||
};
|
};
|
||||||
let needsexport: bool = !g.pkg[pi].root || rootpackage;
|
|
||||||
let needsarchive: bool = !g.pkg[pi].root || rootpackage;
|
|
||||||
if (sepcomposeunit(g, pi, cu) < 0) {
|
if (sepcomposeunit(g, pi, cu) < 0) {
|
||||||
g.pkg[pi].failed = true;
|
g.pkg[pi].failed = true;
|
||||||
anyfailed = true;
|
anyfailed = true;
|
||||||
@@ -2328,20 +2467,14 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
if (!staleall && !depschanged) {
|
if (!staleall && !depschanged) {
|
||||||
fresh = fileequal(unitnew, unitf);
|
fresh = fileequal(unitnew, unitf);
|
||||||
if (fresh) { fresh = fileisreg(asmf); };
|
if (fresh) { fresh = fileisreg(asmf); };
|
||||||
if (fresh) {
|
if (fresh) { fresh = fileisreg(wwi); };
|
||||||
if (needsexport) {
|
|
||||||
fresh = fileisreg(wwi);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (fresh) {
|
if (fresh) {
|
||||||
if (emitasm == 0) {
|
if (emitasm == 0) {
|
||||||
fresh = filesizenonzero(objf);
|
fresh = filesizenonzero(objf);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (fresh) {
|
if (fresh && emitasm == 0) {
|
||||||
if (emitasm == 0 && needsarchive) {
|
fresh = filesizenonzero(apath);
|
||||||
fresh = filesizenonzero(apath);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -2355,31 +2488,34 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
// BUG-1 (#69): -I <wwi> is purely the root's UNUSED
|
let rawtest: bool = (istest != 0) && g.pkg[pi].root
|
||||||
// `.wwi` output path, but it triggers wwiemit ->
|
&& g.pkg[pi].isdir == 0;
|
||||||
// checkexportedtype on the root. A terminal binary's
|
let gent: bool = g.pkg[pi].generatedmain || rawtest;
|
||||||
// root legitimately has `export fn` over an unexported
|
let testpkg: bool = g.pkg[pi].root && (istest != 0) && !gent;
|
||||||
// LOCAL type (the root is never imported), which the
|
let entry: bool = g.pkg[pi].linkentry;
|
||||||
// export-check rejects. Build a shorter root argv
|
let supportpkg: bool = g.pkg[pi].testsupport;
|
||||||
// without the -I/wwi pair; root's `.wwi` is unconsumed.
|
|
||||||
// #79: the root carries -T under `ww test` so w6c
|
|
||||||
// synthesizes the test main; deps never get -T.
|
|
||||||
let roott: bool = g.pkg[pi].root && (istest != 0);
|
|
||||||
let supportt: bool = g.pkg[pi].testsupport;
|
|
||||||
let alen: u64 = 8u64;
|
let alen: u64 = 8u64;
|
||||||
if (!needsexport) { alen = 6u64; if (roott) { alen = 9u64; }; };
|
if (gent) { alen += 4u64; }
|
||||||
if (supportt) { alen += 2u64; };
|
else {
|
||||||
|
if (testpkg) { alen += 1u64; };
|
||||||
|
if (entry) { alen += 1u64; };
|
||||||
|
if (supportpkg) { alen += 2u64; };
|
||||||
|
};
|
||||||
alen += (g.pkg[pi].ndeps: u64) * 3u64;
|
alen += (g.pkg[pi].ndeps: u64) * 3u64;
|
||||||
let argv: []str = alloc([], alen)!;
|
let argv: []str = alloc([], alen)!;
|
||||||
append(argv, "w6c");
|
append(argv, "w6c");
|
||||||
if (roott) {
|
if (gent) {
|
||||||
append(argv, "-T");
|
append(argv, "-T");
|
||||||
|
append(argv, "--entry");
|
||||||
append(argv, "--test-support-module");
|
append(argv, "--test-support-module");
|
||||||
append(argv, testsupportmodule);
|
append(argv, testsupportmodule);
|
||||||
};
|
} else {
|
||||||
if (supportt) {
|
if (testpkg) { append(argv, "--test-package"); };
|
||||||
append(argv, "--test-support-module");
|
if (entry) { append(argv, "--entry"); };
|
||||||
append(argv, testsupportmodule);
|
if (supportpkg) {
|
||||||
|
append(argv, "--test-support-module");
|
||||||
|
append(argv, testsupportmodule);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
append(argv, "-c");
|
append(argv, "-c");
|
||||||
let importk: i32 = 0;
|
let importk: i32 = 0;
|
||||||
@@ -2390,10 +2526,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
append(argv, pathstr(sepfname(g, dj, scratch, ".wwi")));
|
append(argv, pathstr(sepfname(g, dj, scratch, ".wwi")));
|
||||||
importk += 1;
|
importk += 1;
|
||||||
};
|
};
|
||||||
if (needsexport) {
|
append(argv, "-I");
|
||||||
append(argv, "-I");
|
append(argv, pathstr(cw));
|
||||||
append(argv, pathstr(cw));
|
|
||||||
};
|
|
||||||
append(argv, "-o");
|
append(argv, "-o");
|
||||||
append(argv, pathstr(cs));
|
append(argv, pathstr(cs));
|
||||||
append(argv, pathstr(cu));
|
append(argv, pathstr(cu));
|
||||||
@@ -2418,10 +2552,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (needsexport) {
|
if (!warm || !fileequal(wwinew, wwi)) {
|
||||||
if (!warm || !fileequal(wwinew, wwi)) {
|
g.pkg[pi].exportchanged = true;
|
||||||
g.pkg[pi].exportchanged = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
if (emitasm == 0) {
|
if (emitasm == 0) {
|
||||||
let argv: []str = alloc([], 4u64)!;
|
let argv: []str = alloc([], 4u64)!;
|
||||||
@@ -2450,12 +2582,9 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// Wrap each DEP package's `.o` in its own deterministic `.a`
|
// Every package action, including executable/generated roots, produces
|
||||||
// (5a). The ROOT stays a positional `.o` (force-loaded — it's
|
// the existing deterministic single-member archive.
|
||||||
// the build target), so `main` is defined before any archive is
|
if (emitasm == 0) {
|
||||||
// processed. The link
|
|
||||||
// consumes `.o`/`.a`, never `.wwi`.
|
|
||||||
if (emitasm == 0 && needsarchive) {
|
|
||||||
if (archiveo(co, ca) != 0) {
|
if (archiveo(co, ca) != 0) {
|
||||||
cerr("ww: archive failed\n");
|
cerr("ww: archive failed\n");
|
||||||
g.pkg[pi].failed = true;
|
g.pkg[pi].failed = true;
|
||||||
@@ -2468,10 +2597,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
// them, unit strictly last.
|
// them, unit strictly last.
|
||||||
if (warm) {
|
if (warm) {
|
||||||
let bad: bool = false;
|
let bad: bool = false;
|
||||||
if (needsexport) {
|
if (os.rename(pathstr(wwinew), pathstr(wwi)) != 0) {
|
||||||
if (os.rename(pathstr(wwinew), pathstr(wwi)) != 0) {
|
bad = true;
|
||||||
bad = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
if (!bad) {
|
if (!bad) {
|
||||||
if (os.rename(pathstr(asmnew), pathstr(asmf)) != 0) {
|
if (os.rename(pathstr(asmnew), pathstr(asmf)) != 0) {
|
||||||
@@ -2486,7 +2613,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (!bad) {
|
if (!bad) {
|
||||||
if (emitasm == 0 && needsarchive) {
|
if (emitasm == 0) {
|
||||||
if (os.rename(pathstr(anew), pathstr(apath)) != 0) {
|
if (os.rename(pathstr(anew), pathstr(apath)) != 0) {
|
||||||
bad = true;
|
bad = true;
|
||||||
};
|
};
|
||||||
@@ -2573,6 +2700,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
producti = 0;
|
producti = 0;
|
||||||
for (producti < nproducts) {
|
for (producti < nproducts) {
|
||||||
let root: i32 = products[producti].root;
|
let root: i32 = products[producti].root;
|
||||||
|
let variantroot: i32 = products[producti].variantroot;
|
||||||
if (g.pkg[root].failed) {
|
if (g.pkg[root].failed) {
|
||||||
anyfailed = true;
|
anyfailed = true;
|
||||||
producti += 1;
|
producti += 1;
|
||||||
@@ -2598,18 +2726,17 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
let li: i32 = nlink - 1;
|
let li: i32 = nlink - 1;
|
||||||
for (li >= 0) {
|
for (li >= 0) {
|
||||||
let pi: i32 = linkorder[li];
|
let pi: i32 = linkorder[li];
|
||||||
if (g.pkg[root].variant == SEP_VARIANT_SAME_TEST
|
if (variantroot >= 0
|
||||||
&& pi != root
|
&& g.pkg[variantroot].variant == SEP_VARIANT_SAME_TEST
|
||||||
|
&& pi != variantroot
|
||||||
&& g.pkg[pi].variant == SEP_VARIANT_PRODUCTION
|
&& g.pkg[pi].variant == SEP_VARIANT_PRODUCTION
|
||||||
&& g.pkg[pi].role != SEP_ROLE_TEST_SUPPORT
|
&& g.pkg[pi].role != SEP_ROLE_TEST_SUPPORT
|
||||||
&& os.samefile(pathstr(g.pkg[pi].entry),
|
&& os.samefile(pathstr(g.pkg[pi].entry),
|
||||||
pathstr(g.pkg[root].entry))) {
|
pathstr(g.pkg[variantroot].entry))) {
|
||||||
li -= 1;
|
li -= 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let suf: str = ".a";
|
largv[pos] = sepfname(g, pi, scratch, ".a");
|
||||||
if (pi == root) { suf = ".o"; };
|
|
||||||
largv[pos] = sepfname(g, pi, scratch, suf);
|
|
||||||
pos += 1;
|
pos += 1;
|
||||||
li -= 1;
|
li -= 1;
|
||||||
};
|
};
|
||||||
@@ -2694,8 +2821,10 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
product.testpackage = testpackage;
|
product.testpackage = testpackage;
|
||||||
product.status = nil;
|
product.status = nil;
|
||||||
product.artifact = nil;
|
product.artifact = nil;
|
||||||
|
if (packageonly == 0) { product.artifact = "__root\0".ptr; };
|
||||||
product.variant = rootvariant;
|
product.variant = rootvariant;
|
||||||
product.root = -1;
|
product.root = -1;
|
||||||
|
product.variantroot = -1;
|
||||||
let r: i32 = buildonesepimpl(selfdir, src, entryisdir, rootidentity,
|
let r: i32 = buildonesepimpl(selfdir, src, entryisdir, rootidentity,
|
||||||
out, objstem,
|
out, objstem,
|
||||||
incs, lf, packageonly, istest, &product, 1,
|
incs, lf, packageonly, istest, &product, 1,
|
||||||
@@ -2755,9 +2884,11 @@ fn productartifact(index: i32, variant: i32) *u8 = {
|
|||||||
off = byteinto(buf.ptr, off, '-': u8);
|
off = byteinto(buf.ptr, off, '-': u8);
|
||||||
if (variant == SEP_VARIANT_SAME_TEST) {
|
if (variant == SEP_VARIANT_SAME_TEST) {
|
||||||
off = strinto(buf.ptr, off, "same");
|
off = strinto(buf.ptr, off, "same");
|
||||||
|
} else { if (variant == SEP_VARIANT_TEST_MAIN) {
|
||||||
|
off = strinto(buf.ptr, off, "main");
|
||||||
} else {
|
} else {
|
||||||
off = strinto(buf.ptr, off, "external");
|
off = strinto(buf.ptr, off, "external");
|
||||||
};
|
}; };
|
||||||
cstrseal(buf.ptr, off);
|
cstrseal(buf.ptr, off);
|
||||||
return buf.ptr;
|
return buf.ptr;
|
||||||
};
|
};
|
||||||
@@ -3446,6 +3577,7 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
product.artifact = nil;
|
product.artifact = nil;
|
||||||
product.variant = variant;
|
product.variant = variant;
|
||||||
product.root = -1;
|
product.root = -1;
|
||||||
|
product.variantroot = -1;
|
||||||
append(products, product);
|
append(products, product);
|
||||||
i += 6;
|
i += 6;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ package packedwwi_test;
|
|||||||
// type.ha:122-126). Both driver stages must build the -I tree and run
|
// type.ha:122-126). Both driver stages must build the -I tree and run
|
||||||
// exit 91 (9*10+1; a dropped @packed gives 168). Strengthened over
|
// exit 91 (9*10+1; a dropped @packed gives 168). Strengthened over
|
||||||
// the carrier: the re-emitted `struct @packed {` is also asserted in
|
// the carrier: the re-emitted `struct @packed {` is also asserted in
|
||||||
// the retained sepwork pk2.wwi. A single-file two-package form
|
// the retained sepwork pk2.wwi. A single-file two-package form produces
|
||||||
// produces NO .wwi (one __root unit), so the real -I tree is
|
// only one raw `__root.wwi`, not an independently importable pk2 package,
|
||||||
// irreducible here.
|
// so the real directory-package -I tree is irreducible here.
|
||||||
//
|
//
|
||||||
// identityreject: assigning packed A to a structurally-identical
|
// identityreject: assigning packed A to a structurally-identical
|
||||||
// unpacked B — packed is type identity (harec types.c:621). STAGE-
|
// unpacked B — packed is type identity (harec types.c:621). STAGE-
|
||||||
|
|||||||
@@ -786,6 +786,11 @@ fn workescape(s: str) str = {
|
|||||||
let referencesameunit: str = "";
|
let referencesameunit: str = "";
|
||||||
let referenceexternalunit: str = "";
|
let referenceexternalunit: str = "";
|
||||||
let referenceproductionunit: str = "";
|
let referenceproductionunit: str = "";
|
||||||
|
let packageactions: []str = ["__ww-test-000-same",
|
||||||
|
"__ww-test-000-main", "__ww-test-001-external",
|
||||||
|
"__ww-test-001-main"];
|
||||||
|
let referenceactionexports: []str = ["", "", "", ""];
|
||||||
|
let referenceactionarchives: []str = ["", "", "", ""];
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < drivers.len) {
|
for (i < drivers.len) {
|
||||||
let av: []str = [driver(drivers[i]), "test", "-c", "-I", root,
|
let av: []str = [driver(drivers[i]), "test", "-c", "-I", root,
|
||||||
@@ -807,6 +812,10 @@ fn workescape(s: str) str = {
|
|||||||
"__ww-test-001-external.unit.ww"));
|
"__ww-test-001-external.unit.ww"));
|
||||||
let externalproduction: str = readfile(strings.concat(sharedwork,
|
let externalproduction: str = readfile(strings.concat(sharedwork,
|
||||||
"__ww-test-001-external-production.unit.ww"));
|
"__ww-test-001-external-production.unit.ww"));
|
||||||
|
let samemainunit: str = readfile(strings.concat(sharedwork,
|
||||||
|
"__ww-test-000-main.unit.ww"));
|
||||||
|
let externalmainunit: str = readfile(strings.concat(sharedwork,
|
||||||
|
"__ww-test-001-main.unit.ww"));
|
||||||
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
|
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
|
||||||
assert(!has(sameunit, "//ww:module "));
|
assert(!has(sameunit, "//ww:module "));
|
||||||
assert(os.exists(strings.concat(sharedwork,
|
assert(os.exists(strings.concat(sharedwork,
|
||||||
@@ -824,28 +833,43 @@ fn workescape(s: str) str = {
|
|||||||
assert(!has(externalproduction, "//ww:module "));
|
assert(!has(externalproduction, "//ww:module "));
|
||||||
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
||||||
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
||||||
|
assert(same(samemainunit, strings.concat(
|
||||||
|
"//ww:module-reset __wwtestmain.000.main\n",
|
||||||
|
"package main;\nimport pkg;\nimport test;\n")));
|
||||||
|
assert(same(externalmainunit, strings.concat(
|
||||||
|
"//ww:module-reset __wwtestmain.001.main\n",
|
||||||
|
"package main;\nimport pkg_test;\nimport test;\n")));
|
||||||
|
assert(!has(samemainunit, "PACKAGE_PRODUCTION"));
|
||||||
|
assert(!has(samemainunit, "SAME_TEST_SOURCE"));
|
||||||
|
assert(!has(externalmainunit, "EXTERNAL_TEST_SOURCE"));
|
||||||
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
|
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
|
||||||
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
|
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
|
||||||
let artifacts: []str = ["implementation", "api",
|
let artifacts: []str = ["implementation", "api",
|
||||||
"__ww-test-001-external-production",
|
"__ww-test-001-external-production",
|
||||||
"__same", "__external", "test"];
|
"__same", "__external", "test", "__ww-test-000-same",
|
||||||
|
"__ww-test-000-main", "__ww-test-001-external",
|
||||||
|
"__ww-test-001-main"];
|
||||||
let ai: i32 = 0;
|
let ai: i32 = 0;
|
||||||
for (ai < artifacts.len) {
|
for (ai < artifacts.len) {
|
||||||
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".wwi")));
|
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".wwi")));
|
||||||
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".a")));
|
assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".a")));
|
||||||
ai += 1;
|
ai += 1;
|
||||||
};
|
};
|
||||||
assert(os.exists(strings.concat(sharedwork, "__ww-test-000-same.o")));
|
ai = 0;
|
||||||
assert(os.exists(strings.concat(sharedwork,
|
for (ai < packageactions.len) {
|
||||||
"__ww-test-001-external.o")));
|
let ex: str = readfile(strings.concat(sharedwork,
|
||||||
assert(!os.exists(strings.concat(sharedwork,
|
packageactions[ai], ".wwi"));
|
||||||
"__ww-test-000-same.wwi")));
|
let ar: str = readfile(strings.concat(sharedwork,
|
||||||
assert(!os.exists(strings.concat(sharedwork,
|
packageactions[ai], ".a"));
|
||||||
"__ww-test-001-external.wwi")));
|
if (i == 0) {
|
||||||
assert(!os.exists(strings.concat(sharedwork,
|
referenceactionexports[ai] = strings.dup(ex);
|
||||||
"__ww-test-000-same.a")));
|
referenceactionarchives[ai] = strings.dup(ar);
|
||||||
assert(!os.exists(strings.concat(sharedwork,
|
} else {
|
||||||
"__ww-test-001-external.a")));
|
assert(same(referenceactionexports[ai], ex));
|
||||||
|
assert(same(referenceactionarchives[ai], ar));
|
||||||
|
};
|
||||||
|
ai += 1;
|
||||||
|
};
|
||||||
assert(os.exists(samebin));
|
assert(os.exists(samebin));
|
||||||
assert(os.exists(externalbin));
|
assert(os.exists(externalbin));
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@@ -862,7 +886,11 @@ fn workescape(s: str) str = {
|
|||||||
assert(occurrences(ctrace,
|
assert(occurrences(ctrace,
|
||||||
"__ww-test-001-external.unit.ww") == 1);
|
"__ww-test-001-external.unit.ww") == 1);
|
||||||
assert(occurrences(ctrace,
|
assert(occurrences(ctrace,
|
||||||
"-T --test-support-module") == 2);
|
"__ww-test-000-main.unit.ww") == 1);
|
||||||
|
assert(occurrences(ctrace,
|
||||||
|
"__ww-test-001-main.unit.ww") == 1);
|
||||||
|
assert(occurrences(ctrace, "-T --entry --test-support-module") == 2);
|
||||||
|
assert(occurrences(ctrace, "--test-package") == 2);
|
||||||
let samecompile: str = linecontaining(ctrace,
|
let samecompile: str = linecontaining(ctrace,
|
||||||
"__ww-test-000-same.unit.ww");
|
"__ww-test-000-same.unit.ww");
|
||||||
let externalcompile: str = linecontaining(ctrace,
|
let externalcompile: str = linecontaining(ctrace,
|
||||||
@@ -870,18 +898,36 @@ fn workescape(s: str) str = {
|
|||||||
let productioncompile: str = linecontaining(ctrace,
|
let productioncompile: str = linecontaining(ctrace,
|
||||||
"__ww-test-001-external-production.unit.ww");
|
"__ww-test-001-external-production.unit.ww");
|
||||||
assert(same(samecompile, strings.concat(
|
assert(same(samecompile, strings.concat(
|
||||||
"-T --test-support-module test -c --import __same ",
|
"--test-package -c --import __same ",
|
||||||
sharedwork, "__same.wwi --import api ", sharedwork,
|
sharedwork, "__same.wwi --import api ", sharedwork,
|
||||||
"api.wwi --import test ", sharedwork, "test.wwi -o ",
|
"api.wwi -I ", sharedwork, "__ww-test-000-same.wwi -o ",
|
||||||
sharedwork, "__ww-test-000-same.s ", sharedwork,
|
sharedwork, "__ww-test-000-same.s ", sharedwork,
|
||||||
"__ww-test-000-same.unit.ww")));
|
"__ww-test-000-same.unit.ww")));
|
||||||
assert(same(externalcompile, strings.concat(
|
assert(same(externalcompile, strings.concat(
|
||||||
"-T --test-support-module test -c --import __external ",
|
"--test-package -c --import __external ",
|
||||||
sharedwork, "__external.wwi --import pkg ", sharedwork,
|
sharedwork, "__external.wwi --import pkg ", sharedwork,
|
||||||
"__ww-test-001-external-production.wwi --import test ",
|
"__ww-test-001-external-production.wwi -I ", sharedwork,
|
||||||
sharedwork, "test.wwi -o ", sharedwork,
|
"__ww-test-001-external.wwi -o ", sharedwork,
|
||||||
"__ww-test-001-external.s ", sharedwork,
|
"__ww-test-001-external.s ", sharedwork,
|
||||||
"__ww-test-001-external.unit.ww")));
|
"__ww-test-001-external.unit.ww")));
|
||||||
|
let samemaincompile: str = linecontaining(ctrace,
|
||||||
|
"__ww-test-000-main.unit.ww");
|
||||||
|
let externalmaincompile: str = linecontaining(ctrace,
|
||||||
|
"__ww-test-001-main.unit.ww");
|
||||||
|
assert(same(samemaincompile, strings.concat(
|
||||||
|
"-T --entry --test-support-module test -c --import pkg ",
|
||||||
|
sharedwork, "__ww-test-000-same.wwi --import test ",
|
||||||
|
sharedwork, "test.wwi -I ", sharedwork,
|
||||||
|
"__ww-test-000-main.wwi -o ", sharedwork,
|
||||||
|
"__ww-test-000-main.s ", sharedwork,
|
||||||
|
"__ww-test-000-main.unit.ww")));
|
||||||
|
assert(same(externalmaincompile, strings.concat(
|
||||||
|
"-T --entry --test-support-module test -c --import pkg_test ",
|
||||||
|
sharedwork, "__ww-test-001-external.wwi --import test ",
|
||||||
|
sharedwork, "test.wwi -I ", sharedwork,
|
||||||
|
"__ww-test-001-main.wwi -o ", sharedwork,
|
||||||
|
"__ww-test-001-main.s ", sharedwork,
|
||||||
|
"__ww-test-001-main.unit.ww")));
|
||||||
assert(same(productioncompile, strings.concat(
|
assert(same(productioncompile, strings.concat(
|
||||||
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
|
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
|
||||||
"__ww-test-001-external-production.wwi -o ", sharedwork,
|
"__ww-test-001-external-production.wwi -o ", sharedwork,
|
||||||
@@ -897,12 +943,22 @@ fn workescape(s: str) str = {
|
|||||||
assert(has(samelink,
|
assert(has(samelink,
|
||||||
strings.concat(sharedwork, "implementation.a")));
|
strings.concat(sharedwork, "implementation.a")));
|
||||||
assert(has(samelink, strings.concat(sharedwork, "__same.a")));
|
assert(has(samelink, strings.concat(sharedwork, "__same.a")));
|
||||||
|
assert(has(samelink, strings.concat(sharedwork,
|
||||||
|
"__ww-test-000-main.a")));
|
||||||
|
assert(has(samelink, strings.concat(sharedwork,
|
||||||
|
"__ww-test-000-same.a")));
|
||||||
assert(!has(samelink, strings.concat(sharedwork,
|
assert(!has(samelink, strings.concat(sharedwork,
|
||||||
"__ww-test-001-external-production.a")));
|
"__ww-test-001-external-production.a")));
|
||||||
assert(!has(samelink,
|
assert(!has(samelink,
|
||||||
strings.concat(sharedwork, "__external.a")));
|
strings.concat(sharedwork, "__external.a")));
|
||||||
assert(has(externallink, strings.concat(sharedwork,
|
assert(has(externallink, strings.concat(sharedwork,
|
||||||
"__ww-test-001-external-production.a")));
|
"__ww-test-001-external-production.a")));
|
||||||
|
assert(has(externallink, strings.concat(sharedwork,
|
||||||
|
"__ww-test-001-main.a")));
|
||||||
|
assert(has(externallink, strings.concat(sharedwork,
|
||||||
|
"__ww-test-001-external.a")));
|
||||||
|
assert(!has(samelink, ".wwi"));
|
||||||
|
assert(!has(externallink, ".wwi"));
|
||||||
assert(has(externallink, strings.concat(sharedwork, "api.a")));
|
assert(has(externallink, strings.concat(sharedwork, "api.a")));
|
||||||
assert(has(externallink,
|
assert(has(externallink,
|
||||||
strings.concat(sharedwork, "implementation.a")));
|
strings.concat(sharedwork, "implementation.a")));
|
||||||
@@ -1176,6 +1232,8 @@ fn workescape(s: str) str = {
|
|||||||
let rootkeys: []str = ["__ww-test-000-same",
|
let rootkeys: []str = ["__ww-test-000-same",
|
||||||
"__ww-test-001-external", "__ww-test-002-same",
|
"__ww-test-001-external", "__ww-test-002-same",
|
||||||
"__ww-test-003-external"];
|
"__ww-test-003-external"];
|
||||||
|
let mainkeys: []str = ["__ww-test-000-main", "__ww-test-001-main",
|
||||||
|
"__ww-test-002-main", "__ww-test-003-main"];
|
||||||
let alphaartifact: str = "__ww-test-001-external-production";
|
let alphaartifact: str = "__ww-test-001-external-production";
|
||||||
let betaartifact: str = "__ww-test-003-external-production";
|
let betaartifact: str = "__ww-test-003-external-production";
|
||||||
let expectedtests: []str = ["alpha_same_runs ... ok\n",
|
let expectedtests: []str = ["alpha_same_runs ... ok\n",
|
||||||
@@ -1248,7 +1306,11 @@ fn workescape(s: str) str = {
|
|||||||
assert(!has(roots[3], "MULTIDIR_BETA_SAME"));
|
assert(!has(roots[3], "MULTIDIR_BETA_SAME"));
|
||||||
let products: []str = ["leaf", "common", alphaartifact, betaartifact,
|
let products: []str = ["leaf", "common", alphaartifact, betaartifact,
|
||||||
"_alpha_same", "_alpha_external", "_beta_same",
|
"_alpha_same", "_alpha_external", "_beta_same",
|
||||||
"_beta_external", "test"];
|
"_beta_external", "test", "__ww-test-000-same",
|
||||||
|
"__ww-test-001-external", "__ww-test-002-same",
|
||||||
|
"__ww-test-003-external", "__ww-test-000-main",
|
||||||
|
"__ww-test-001-main", "__ww-test-002-main",
|
||||||
|
"__ww-test-003-main"];
|
||||||
let pi: i32 = 0;
|
let pi: i32 = 0;
|
||||||
for (pi < products.len) {
|
for (pi < products.len) {
|
||||||
assert(os.exists(strings.concat(sharedwork, products[pi],
|
assert(os.exists(strings.concat(sharedwork, products[pi],
|
||||||
@@ -1260,8 +1322,11 @@ fn workescape(s: str) str = {
|
|||||||
let ri: i32 = 0;
|
let ri: i32 = 0;
|
||||||
for (ri < rootkeys.len) {
|
for (ri < rootkeys.len) {
|
||||||
assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".o")));
|
assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".o")));
|
||||||
assert(!os.exists(strings.concat(sharedwork, rootkeys[ri], ".wwi")));
|
assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".wwi")));
|
||||||
assert(!os.exists(strings.concat(sharedwork, rootkeys[ri], ".a")));
|
assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".a")));
|
||||||
|
assert(os.exists(strings.concat(sharedwork, mainkeys[ri], ".unit.ww")));
|
||||||
|
assert(os.exists(strings.concat(sharedwork, mainkeys[ri], ".wwi")));
|
||||||
|
assert(os.exists(strings.concat(sharedwork, mainkeys[ri], ".a")));
|
||||||
assert(os.exists(bins[ri]));
|
assert(os.exists(bins[ri]));
|
||||||
if (ri > 0) {
|
if (ri > 0) {
|
||||||
assert(!os.exists(strings.concat(bins[ri], ".sepwork")));
|
assert(!os.exists(strings.concat(bins[ri], ".sepwork")));
|
||||||
@@ -1293,6 +1358,8 @@ fn workescape(s: str) str = {
|
|||||||
for (ri < rootkeys.len) {
|
for (ri < rootkeys.len) {
|
||||||
assert(occurrences(ctrace, strings.concat(rootkeys[ri],
|
assert(occurrences(ctrace, strings.concat(rootkeys[ri],
|
||||||
".unit.ww")) == 1);
|
".unit.ww")) == 1);
|
||||||
|
assert(occurrences(ctrace, strings.concat(mainkeys[ri],
|
||||||
|
".unit.ww")) == 1);
|
||||||
ri += 1;
|
ri += 1;
|
||||||
};
|
};
|
||||||
assert(pos(ctrace, "/leaf.unit.ww")
|
assert(pos(ctrace, "/leaf.unit.ww")
|
||||||
@@ -1309,7 +1376,9 @@ fn workescape(s: str) str = {
|
|||||||
for (ri < bins.len) {
|
for (ri < bins.len) {
|
||||||
let link: str = linecontaining(ltrace,
|
let link: str = linecontaining(ltrace,
|
||||||
strings.concat("-o ", bins[ri], " "));
|
strings.concat("-o ", bins[ri], " "));
|
||||||
assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".o")));
|
assert(has(link, strings.concat(sharedwork, mainkeys[ri], ".a")));
|
||||||
|
assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".a")));
|
||||||
|
assert(!has(link, ".wwi"));
|
||||||
assert(has(link, strings.concat(sharedwork, "common.a")));
|
assert(has(link, strings.concat(sharedwork, "common.a")));
|
||||||
assert(has(link, strings.concat(sharedwork, "leaf.a")));
|
assert(has(link, strings.concat(sharedwork, "leaf.a")));
|
||||||
assert(has(link, strings.concat(sharedwork, "test.a")));
|
assert(has(link, strings.concat(sharedwork, "test.a")));
|
||||||
@@ -1399,6 +1468,8 @@ fn workescape(s: str) str = {
|
|||||||
for (ri < rootkeys.len) {
|
for (ri < rootkeys.len) {
|
||||||
assert(occurrences(wwtrace, strings.concat(rootkeys[ri],
|
assert(occurrences(wwtrace, strings.concat(rootkeys[ri],
|
||||||
".unit.ww")) == 1);
|
".unit.ww")) == 1);
|
||||||
|
assert(occurrences(wwtrace, strings.concat(mainkeys[ri],
|
||||||
|
".unit.ww")) == 1);
|
||||||
ri += 1;
|
ri += 1;
|
||||||
};
|
};
|
||||||
assert(occurrences(readfile(wwlinkertrace), "\n") == 4);
|
assert(occurrences(readfile(wwlinkertrace), "\n") == 4);
|
||||||
@@ -1747,7 +1818,7 @@ fn workescape(s: str) str = {
|
|||||||
let cbin: str = readfile(bin);
|
let cbin: str = readfile(bin);
|
||||||
let rootunit: str = readfile(strings.concat(work,
|
let rootunit: str = readfile(strings.concat(work,
|
||||||
"__ww-test-000-same.unit.ww"));
|
"__ww-test-000-same.unit.ww"));
|
||||||
assert(has(rootunit, "//ww:module-reset\npackage target;"));
|
assert(has(rootunit, "//ww:module-reset target\npackage target;"));
|
||||||
assert(!has(rootunit, "//ww:module "));
|
assert(!has(rootunit, "//ww:module "));
|
||||||
let linkargs: str = readfile(trace);
|
let linkargs: str = readfile(trace);
|
||||||
assert(linkargs.len > 8192);
|
assert(linkargs.len > 8192);
|
||||||
@@ -2214,7 +2285,7 @@ fn workescape(s: str) str = {
|
|||||||
let workroot: str = strings.concat(bin, ".sepwork");
|
let workroot: str = strings.concat(bin, ".sepwork");
|
||||||
let work: str = strings.concat(workroot, "/");
|
let work: str = strings.concat(workroot, "/");
|
||||||
let artifacts: []str = ["ww_root_parity_base_7f3",
|
let artifacts: []str = ["ww_root_parity_base_7f3",
|
||||||
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3"];
|
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "__root"];
|
||||||
let unitartifacts: []str = ["ww_root_parity_base_7f3",
|
let unitartifacts: []str = ["ww_root_parity_base_7f3",
|
||||||
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "__root"];
|
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "__root"];
|
||||||
let wantunits: []str = [strings.concat(
|
let wantunits: []str = [strings.concat(
|
||||||
@@ -2224,10 +2295,10 @@ fn workescape(s: str) str = {
|
|||||||
leftbody, "\n"),
|
leftbody, "\n"),
|
||||||
strings.concat("//ww:module-reset ww_root_parity_right_7f3\n",
|
strings.concat("//ww:module-reset ww_root_parity_right_7f3\n",
|
||||||
rightbody, "\n"),
|
rightbody, "\n"),
|
||||||
strings.concat("//ww:module-reset\n", rootbody, "\n")];
|
strings.concat("//ww:module-reset main\n", rootbody, "\n")];
|
||||||
let referenceunits: []str = ["", "", "", ""];
|
let referenceunits: []str = ["", "", "", ""];
|
||||||
let referenceexports: []str = ["", "", ""];
|
let referenceexports: []str = ["", "", "", ""];
|
||||||
let referencearchives: []str = ["", "", ""];
|
let referencearchives: []str = ["", "", "", ""];
|
||||||
let referencebin: str = "";
|
let referencebin: str = "";
|
||||||
let referencecompiler: str = "";
|
let referencecompiler: str = "";
|
||||||
let referenceassembler: str = "";
|
let referenceassembler: str = "";
|
||||||
@@ -2327,8 +2398,6 @@ fn workescape(s: str) str = {
|
|||||||
};
|
};
|
||||||
ai += 1;
|
ai += 1;
|
||||||
};
|
};
|
||||||
assert(!os.exists(strings.concat(work, "__root.wwi")));
|
|
||||||
assert(!os.exists(strings.concat(work, "__root.a")));
|
|
||||||
assert(os.exists(bin));
|
assert(os.exists(bin));
|
||||||
|
|
||||||
let ctrace: str = readfile(compilertrace);
|
let ctrace: str = readfile(compilertrace);
|
||||||
@@ -2351,11 +2420,12 @@ fn workescape(s: str) str = {
|
|||||||
"ww_root_parity_right_7f3.wwi><-o><", work,
|
"ww_root_parity_right_7f3.wwi><-o><", work,
|
||||||
"ww_root_parity_right_7f3.s><", work,
|
"ww_root_parity_right_7f3.s><", work,
|
||||||
"ww_root_parity_right_7f3.unit.ww>");
|
"ww_root_parity_right_7f3.unit.ww>");
|
||||||
let rootline: str = strings.concat("BEGIN<-c><--import>",
|
let rootline: str = strings.concat("BEGIN<--entry><-c><--import>",
|
||||||
"<ww_root_parity_left_7f3><", work,
|
"<ww_root_parity_left_7f3><", work,
|
||||||
"ww_root_parity_left_7f3.wwi><--import>",
|
"ww_root_parity_left_7f3.wwi><--import>",
|
||||||
"<ww_root_parity_right_7f3><", work,
|
"<ww_root_parity_right_7f3><", work,
|
||||||
"ww_root_parity_right_7f3.wwi><-o><", work,
|
"ww_root_parity_right_7f3.wwi><-I><", work,
|
||||||
|
"__root.wwi><-o><", work,
|
||||||
"__root.s><", work, "__root.unit.ww>");
|
"__root.s><", work, "__root.unit.ww>");
|
||||||
assert(same(linecontaining(ctrace,
|
assert(same(linecontaining(ctrace,
|
||||||
"ww_root_parity_base_7f3.unit.ww"), baseline));
|
"ww_root_parity_base_7f3.unit.ww"), baseline));
|
||||||
@@ -2371,7 +2441,7 @@ fn workescape(s: str) str = {
|
|||||||
"ww_root_parity_left_7f3.s>")));
|
"ww_root_parity_left_7f3.s>")));
|
||||||
assert(occurrences(ltrace, "\n") == 1);
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
||||||
"__root.o>")));
|
"__root.a>")));
|
||||||
ai = 0;
|
ai = 0;
|
||||||
for (ai < artifacts.len) {
|
for (ai < artifacts.len) {
|
||||||
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
|
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
|
||||||
|
|||||||
@@ -97,12 +97,14 @@ fn samefile(a: str, b: str, why: str) void = {
|
|||||||
|| testenv.has(foounit, "//ww:module ")) {
|
|| testenv.has(foounit, "//ww:module ")) {
|
||||||
fail("foo unit is not exactly its sorted, owned source set");
|
fail("foo unit is not exactly its sorted, owned source set");
|
||||||
};
|
};
|
||||||
let wantroot: str = strings.concat("//ww:module-reset\n", appsrc, "\n");
|
let wantroot: str = strings.concat("//ww:module-reset main\n", appsrc,
|
||||||
|
"\n");
|
||||||
if (!testenv.same(wantroot, testenv.readfile(strings.concat(cwork,
|
if (!testenv.same(wantroot, testenv.readfile(strings.concat(cwork,
|
||||||
"__root.unit.ww")))) {
|
"__root.unit.ww")))) {
|
||||||
fail("root unit is not exactly its owned source");
|
fail("root unit is not exactly its owned source");
|
||||||
};
|
};
|
||||||
let keys: []str = ["example.base", "example.bar", "example.foo"];
|
let keys: []str = ["example.base", "example.bar", "example.foo",
|
||||||
|
"__root"];
|
||||||
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
|
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < keys.len) {
|
for (i < keys.len) {
|
||||||
@@ -117,10 +119,6 @@ fn samefile(a: str, b: str, why: str) void = {
|
|||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
samefile(strings.concat(cwork, "__root.unit.ww"), strings.concat(cwork2,
|
|
||||||
"__root.unit.ww"), "root unit changed across clean C builds");
|
|
||||||
samefile(strings.concat(cwork, "__root.unit.ww"), strings.concat(wwork,
|
|
||||||
"__root.unit.ww"), "root unit differs between stages");
|
|
||||||
samefile(stems[0], stems[1], "C executables are not deterministic");
|
samefile(stems[0], stems[1], "C executables are not deterministic");
|
||||||
samefile(stems[0], stems[2], "C/WW executables differ");
|
samefile(stems[0], stems[2], "C/WW executables differ");
|
||||||
|
|
||||||
|
|||||||
@@ -286,7 +286,8 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = {
|
|||||||
|| testenv.has(apiiface, "hidden")) {
|
|| testenv.has(apiiface, "hidden")) {
|
||||||
fail("self-contained", "api export leaked unrelated or private declarations");
|
fail("self-contained", "api export leaked unrelated or private declarations");
|
||||||
};
|
};
|
||||||
let expectedunit: str = strings.concat("//ww:module-reset\n", mainsrc, "\n");
|
let expectedunit: str = strings.concat("//ww:module-reset main\n",
|
||||||
|
mainsrc, "\n");
|
||||||
if (!testenv.same(expectedunit, testenv.readfile(strings.concat(cwork,
|
if (!testenv.same(expectedunit, testenv.readfile(strings.concat(cwork,
|
||||||
"__root.unit.ww"))) || !testenv.same(expectedunit,
|
"__root.unit.ww"))) || !testenv.same(expectedunit,
|
||||||
testenv.readfile(strings.concat(wwork, "__root.unit.ww")))) {
|
testenv.readfile(strings.concat(wwork, "__root.unit.ww")))) {
|
||||||
@@ -405,7 +406,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let unit: str = testenv.readfile(strings.concat(scratch,
|
let unit: str = testenv.readfile(strings.concat(scratch,
|
||||||
"__root.unit.ww"));
|
"__root.unit.ww"));
|
||||||
let rootbody: str = testenv.readfile(strings.concat(main, "/main.ww"));
|
let rootbody: str = testenv.readfile(strings.concat(main, "/main.ww"));
|
||||||
let wantroot: str = strings.concat("//ww:module-reset\n", rootbody,
|
let wantroot: str = strings.concat("//ww:module-reset main\n", rootbody,
|
||||||
"\n");
|
"\n");
|
||||||
if (!testenv.same(unit, wantroot) || testenv.has(unit,
|
if (!testenv.same(unit, wantroot) || testenv.has(unit,
|
||||||
"//ww:module ")) {
|
"//ww:module ")) {
|
||||||
@@ -530,6 +531,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let referenceunit: str = "";
|
let referenceunit: str = "";
|
||||||
let referencewwi: str = "";
|
let referencewwi: str = "";
|
||||||
let referencearchive: str = "";
|
let referencearchive: str = "";
|
||||||
|
let referencerootwwi: str = "";
|
||||||
|
let referencerootarchive: str = "";
|
||||||
let referencebin: str = "";
|
let referencebin: str = "";
|
||||||
let referencecompiler: str = "";
|
let referencecompiler: str = "";
|
||||||
let referenceassembler: str = "";
|
let referenceassembler: str = "";
|
||||||
@@ -567,7 +570,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"__root.unit.ww"));
|
"__root.unit.ww"));
|
||||||
let depunit: str = testenv.readfile(strings.concat(work,
|
let depunit: str = testenv.readfile(strings.concat(work,
|
||||||
"dep.unit.ww"));
|
"dep.unit.ww"));
|
||||||
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|
if (!testenv.has(rootunit, "//ww:module-reset main\npackage main;")
|
||||||
|| testenv.has(rootunit, "//ww:module ")
|
|| testenv.has(rootunit, "//ww:module ")
|
||||||
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|
||||||
|| testenv.has(depunit, "//ww:module ")) {
|
|| testenv.has(depunit, "//ww:module ")) {
|
||||||
@@ -578,8 +581,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
|| !testenv.exists(strings.concat(work, "dep.wwi"))
|
|| !testenv.exists(strings.concat(work, "dep.wwi"))
|
||||||
|| !testenv.exists(strings.concat(work, "dep.a"))
|
|| !testenv.exists(strings.concat(work, "dep.a"))
|
||||||
|| !testenv.exists(strings.concat(work, "__root.o"))
|
|| !testenv.exists(strings.concat(work, "__root.o"))
|
||||||
|| testenv.exists(strings.concat(work, "__root.wwi"))
|
|| !testenv.exists(strings.concat(work, "__root.wwi"))
|
||||||
|| testenv.exists(strings.concat(work, "__root.a"))) {
|
|| !testenv.exists(strings.concat(work, "__root.a"))) {
|
||||||
fail("library-roots", "package artifacts do not match root ownership");
|
fail("library-roots", "package artifacts do not match root ownership");
|
||||||
};
|
};
|
||||||
let ctrace: str = testenv.readfile(compilertrace);
|
let ctrace: str = testenv.readfile(compilertrace);
|
||||||
@@ -603,6 +606,10 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"BEGIN<-c><--import><leaf><", work, "leaf.wwi><-I><", work,
|
"BEGIN<-c><--import><leaf><", work, "leaf.wwi><-I><", work,
|
||||||
"dep.wwi><-o><", work,
|
"dep.wwi><-o><", work,
|
||||||
"dep.s><", work, "dep.unit.ww>"))
|
"dep.s><", work, "dep.unit.ww>"))
|
||||||
|
|| !testenv.has(ctrace, strings.concat(
|
||||||
|
"BEGIN<--entry><-c><--import><dep><", work,
|
||||||
|
"dep.wwi><-I><", work, "__root.wwi><-o><", work,
|
||||||
|
"__root.s><", work, "__root.unit.ww>"))
|
||||||
|| testenv.occurrences(atrace, "\n") != 3
|
|| testenv.occurrences(atrace, "\n") != 3
|
||||||
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
|
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
|
||||||
"dep.o><", work, "dep.s>"))) {
|
"dep.o><", work, "dep.s>"))) {
|
||||||
@@ -610,7 +617,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
};
|
};
|
||||||
if (testenv.occurrences(ltrace, "\n") != 1
|
if (testenv.occurrences(ltrace, "\n") != 1
|
||||||
|| !testenv.has(ltrace, strings.concat("BEGIN<-o><", bin, "><",
|
|| !testenv.has(ltrace, strings.concat("BEGIN<-o><", bin, "><",
|
||||||
work, "__root.o>"))
|
work, "__root.a>"))
|
||||||
|| testenv.pos(ltrace, strings.concat("<", work, "dep.a>")) < 0
|
|| testenv.pos(ltrace, strings.concat("<", work, "dep.a>")) < 0
|
||||||
|| testenv.pos(ltrace, strings.concat("<", work, "leaf.a>"))
|
|| testenv.pos(ltrace, strings.concat("<", work, "leaf.a>"))
|
||||||
< testenv.pos(ltrace, strings.concat("<", work, "dep.a>"))
|
< testenv.pos(ltrace, strings.concat("<", work, "dep.a>"))
|
||||||
@@ -643,6 +650,10 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"dep.wwi")));
|
"dep.wwi")));
|
||||||
referencearchive = strings.dup(testenv.readfile(strings.concat(work,
|
referencearchive = strings.dup(testenv.readfile(strings.concat(work,
|
||||||
"dep.a")));
|
"dep.a")));
|
||||||
|
referencerootwwi = strings.dup(testenv.readfile(strings.concat(work,
|
||||||
|
"__root.wwi")));
|
||||||
|
referencerootarchive = strings.dup(testenv.readfile(strings.concat(work,
|
||||||
|
"__root.a")));
|
||||||
referencebin = strings.dup(testenv.readfile(bin));
|
referencebin = strings.dup(testenv.readfile(bin));
|
||||||
referencecompiler = strings.dup(ctrace);
|
referencecompiler = strings.dup(ctrace);
|
||||||
referenceassembler = strings.dup(atrace);
|
referenceassembler = strings.dup(atrace);
|
||||||
@@ -653,6 +664,10 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
work, "dep.wwi")))
|
work, "dep.wwi")))
|
||||||
|| !testenv.same(referencearchive, testenv.readfile(strings.concat(
|
|| !testenv.same(referencearchive, testenv.readfile(strings.concat(
|
||||||
work, "dep.a")))
|
work, "dep.a")))
|
||||||
|
|| !testenv.same(referencerootwwi,
|
||||||
|
testenv.readfile(strings.concat(work, "__root.wwi")))
|
||||||
|
|| !testenv.same(referencerootarchive,
|
||||||
|
testenv.readfile(strings.concat(work, "__root.a")))
|
||||||
|| !testenv.same(referencebin, testenv.readfile(bin))
|
|| !testenv.same(referencebin, testenv.readfile(bin))
|
||||||
|| !testenv.same(referencecompiler, ctrace)
|
|| !testenv.same(referencecompiler, ctrace)
|
||||||
|| !testenv.same(referenceassembler, atrace)
|
|| !testenv.same(referenceassembler, atrace)
|
||||||
@@ -723,7 +738,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
runav) != 42) {
|
runav) != 42) {
|
||||||
fail("library-roots", "empty override did not use default roots");
|
fail("library-roots", "empty override did not use default roots");
|
||||||
};
|
};
|
||||||
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|
if (!testenv.has(rootunit, "//ww:module-reset main\npackage main;")
|
||||||
|| testenv.has(rootunit, "//ww:module ")
|
|| testenv.has(rootunit, "//ww:module ")
|
||||||
|| !testenv.exists(strings.concat(emptywork, "types.wwi"))
|
|| !testenv.exists(strings.concat(emptywork, "types.wwi"))
|
||||||
|| !testenv.exists(strings.concat(emptywork, "types.a"))
|
|| !testenv.exists(strings.concat(emptywork, "types.a"))
|
||||||
@@ -870,7 +885,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let depunitpath: str = strings.concat(work, "/dep.unit.ww");
|
let depunitpath: str = strings.concat(work, "/dep.unit.ww");
|
||||||
let rootunit: str = testenv.readfile(rootunitpath);
|
let rootunit: str = testenv.readfile(rootunitpath);
|
||||||
let depunit: str = testenv.readfile(depunitpath);
|
let depunit: str = testenv.readfile(depunitpath);
|
||||||
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|
if (!testenv.has(rootunit, "//ww:module-reset main\npackage main;")
|
||||||
|| testenv.has(rootunit, "//ww:module ")
|
|| testenv.has(rootunit, "//ww:module ")
|
||||||
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|
||||||
|| testenv.has(depunit, "//ww:module ")) {
|
|| testenv.has(depunit, "//ww:module ")) {
|
||||||
@@ -880,8 +895,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
|| !testenv.exists(strings.concat(work, "/leaf.a"))
|
|| !testenv.exists(strings.concat(work, "/leaf.a"))
|
||||||
|| !testenv.exists(strings.concat(work, "/dep.wwi"))
|
|| !testenv.exists(strings.concat(work, "/dep.wwi"))
|
||||||
|| !testenv.exists(strings.concat(work, "/dep.a"))
|
|| !testenv.exists(strings.concat(work, "/dep.a"))
|
||||||
|| testenv.exists(strings.concat(work, "/__root.wwi"))
|
|| !testenv.exists(strings.concat(work, "/__root.wwi"))
|
||||||
|| testenv.exists(strings.concat(work, "/__root.a"))
|
|| !testenv.exists(strings.concat(work, "/__root.a"))
|
||||||
|| !testenv.same(testenv.readfile(strings.concat(work,
|
|| !testenv.same(testenv.readfile(strings.concat(work,
|
||||||
"/.wwtool.ww")), testenv.readfile(copied[si]))
|
"/.wwtool.ww")), testenv.readfile(copied[si]))
|
||||||
|| !testenv.same(testenv.readfile(strings.concat(work,
|
|| !testenv.same(testenv.readfile(strings.concat(work,
|
||||||
@@ -890,7 +905,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"/.wwtool.w6a")), testenv.readfile(assembler))
|
"/.wwtool.w6a")), testenv.readfile(assembler))
|
||||||
|| !testenv.same(testenv.readfile(strings.concat(work,
|
|| !testenv.same(testenv.readfile(strings.concat(work,
|
||||||
"/.wwtool.stamp")),
|
"/.wwtool.stamp")),
|
||||||
"ww workdir fmt 6 mode build asm 0\n")) {
|
"ww workdir fmt 7 mode build asm 0\n")) {
|
||||||
fail("driver-identity", "persistent artifacts or identities are incomplete");
|
fail("driver-identity", "persistent artifacts or identities are incomplete");
|
||||||
};
|
};
|
||||||
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
|
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
|
||||||
@@ -905,7 +920,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"/dep.wwi.new><-o><", work,
|
"/dep.wwi.new><-o><", work,
|
||||||
"/dep.s.new><", work, "/dep.unit.new>"))
|
"/dep.s.new><", work, "/dep.unit.new>"))
|
||||||
|| !testenv.has(coldcompiler, strings.concat(
|
|| !testenv.has(coldcompiler, strings.concat(
|
||||||
"BEGIN<-c><--import><dep><", work, "/dep.wwi><-o><", work,
|
"BEGIN<--entry><-c><--import><dep><", work,
|
||||||
|
"/dep.wwi><-I><", work, "/__root.wwi.new><-o><", work,
|
||||||
"/__root.s.new><", work,
|
"/__root.s.new><", work,
|
||||||
"/__root.unit.new>"))
|
"/__root.unit.new>"))
|
||||||
|| testenv.occurrences(coldassembler, "\n") != 3
|
|| testenv.occurrences(coldassembler, "\n") != 3
|
||||||
@@ -916,7 +932,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
};
|
};
|
||||||
if (testenv.occurrences(coldlinker, "\n") != 1
|
if (testenv.occurrences(coldlinker, "\n") != 1
|
||||||
|| !testenv.has(coldlinker, strings.concat("BEGIN<-o><", bin,
|
|| !testenv.has(coldlinker, strings.concat("BEGIN<-o><", bin,
|
||||||
"><", work, "/__root.o>"))
|
"><", work, "/__root.a>"))
|
||||||
|| testenv.pos(coldlinker, strings.concat("<", work,
|
|| testenv.pos(coldlinker, strings.concat("<", work,
|
||||||
"/dep.a>")) < 0
|
"/dep.a>")) < 0
|
||||||
|| testenv.pos(coldlinker, strings.concat("<", work,
|
|| testenv.pos(coldlinker, strings.concat("<", work,
|
||||||
|
|||||||
@@ -8,19 +8,16 @@ package sepbuild_test;
|
|||||||
//
|
//
|
||||||
// sepbuild (#46 commit-3) — build_one_sep END-TO-END on the real lib
|
// sepbuild (#46 commit-3) — build_one_sep END-TO-END on the real lib
|
||||||
// chain root -> os -> {rt,time} (transitive-closure discovery + topo):
|
// chain root -> os -> {rt,time} (transitive-closure discovery + topo):
|
||||||
// build+run exit 7 both stages; {time,rt,os}.wwi + __root.s
|
// build+run exit 7 both stages; {time,rt,os,__root}.wwi/.a
|
||||||
// materialize (#69: the root is compiled without -I, so no
|
// materialize; per-package .s/.wwi/.a/.unit.ww and the final binary
|
||||||
// __root.wwi); per-package .s/.wwi/.unit.ww and the final binary
|
|
||||||
// byte-id cs vs ww; every .unit.ww is the package's own sorted source
|
// byte-id cs vs ww; every .unit.ww is the package's own sorted source
|
||||||
// set; `ww run` routes through the same sole sep path (exit 7 both
|
// set; `ww run` routes through the same sole sep path (exit 7 both
|
||||||
// stages).
|
// stages).
|
||||||
//
|
//
|
||||||
// seproot (#69 BUG-1) — a ROOT whose `export fn use(a: *t)` names an
|
// seproot — a ROOT whose `export fn use(a: *t)` reaches an unexported
|
||||||
// unexported local `type t` builds (exit 37 both stages) because the
|
// local `type t` builds and emits a deterministic self-contained .wwi/.a.
|
||||||
// root is compiled WITHOUT the -I .wwi-producer flag: __root.wwi must
|
// The private type is carried as compiler export data without `export`, and
|
||||||
// NOT exist; replaying the driver's own __root.unit.ww plus c.wwi
|
// an importing source still cannot qualify `main.t`.
|
||||||
// through w6c/w6c_ww with -I must REJECT (the isolated bug) while -c
|
|
||||||
// -o alone must accept; __root.s carries the exported fn.
|
|
||||||
//
|
//
|
||||||
// sepstructdef (#70 BUG-2) — a dep exporting aggregate-init defs
|
// sepstructdef (#70 BUG-2) — a dep exporting aggregate-init defs
|
||||||
// (struct-lit + array-lit) sep-builds and links (exit 20 both
|
// (struct-lit + array-lit) sep-builds and links (exit 20 both
|
||||||
@@ -91,29 +88,25 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
|
|||||||
s += 1;
|
s += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// discovery/topo: the transitive package set materialized. #69: the
|
// discovery/topo: every reachable package action materialized.
|
||||||
// root emits no .wwi (compiled without -I); its .s stands in.
|
|
||||||
let pkgs: []str = ["time", "rt", "os", "__root"];
|
let pkgs: []str = ["time", "rt", "os", "__root"];
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < pkgs.len) {
|
for (i < pkgs.len) {
|
||||||
let suffix: str = ".wwi";
|
|
||||||
if (testenv.same(pkgs[i], "__root")) { suffix = ".s"; };
|
|
||||||
if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/",
|
if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/",
|
||||||
pkgs[i], suffix))) {
|
pkgs[i], ".wwi")) || !testenv.exists(strings.concat(td,
|
||||||
fail("sepbuild", strings.concat(pkgs[i], suffix,
|
"/prog.cs.sepwork/", pkgs[i], ".a"))) {
|
||||||
|
fail("sepbuild", strings.concat(pkgs[i], ".wwi/.a",
|
||||||
" missing (discovery/topo)"));
|
" missing (discovery/topo)"));
|
||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// cs==ww (rule 10): per-package artifacts + the final binary
|
// cs==ww (rule 10): per-package artifacts + the final binary
|
||||||
let sufs: []str = [".s", ".wwi", ".unit.ww"];
|
let sufs: []str = [".s", ".wwi", ".a", ".unit.ww"];
|
||||||
let p: i32 = 0;
|
let p: i32 = 0;
|
||||||
for (p < pkgs.len) {
|
for (p < pkgs.len) {
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < sufs.len) {
|
for (k < sufs.len) {
|
||||||
if (testenv.same(pkgs[p], "__root")
|
|
||||||
&& testenv.same(sufs[k], ".wwi")) { k += 1; continue; };
|
|
||||||
samefile("sepbuild", strings.concat(pkgs[p], sufs[k]),
|
samefile("sepbuild", strings.concat(pkgs[p], sufs[k]),
|
||||||
strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]),
|
strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]),
|
||||||
strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k]));
|
strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k]));
|
||||||
@@ -171,15 +164,13 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
|
|||||||
s += 1;
|
s += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// cs==ww; the root's .wwi is intentionally absent (asserted below)
|
// cs==ww for the complete package artifacts, including the root archive.
|
||||||
let pkgs: []str = ["c", "__root"];
|
let pkgs: []str = ["c", "__root"];
|
||||||
let sufs: []str = [".s", ".wwi", ".unit.ww"];
|
let sufs: []str = [".s", ".wwi", ".a", ".unit.ww"];
|
||||||
let p: i32 = 0;
|
let p: i32 = 0;
|
||||||
for (p < pkgs.len) {
|
for (p < pkgs.len) {
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < sufs.len) {
|
for (k < sufs.len) {
|
||||||
if (testenv.same(pkgs[p], "__root")
|
|
||||||
&& testenv.same(sufs[k], ".wwi")) { k += 1; continue; };
|
|
||||||
samefile("seproot", strings.concat(pkgs[p], sufs[k]),
|
samefile("seproot", strings.concat(pkgs[p], sufs[k]),
|
||||||
strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]),
|
strings.concat(td, "/prog.cs.sepwork/", pkgs[p], sufs[k]),
|
||||||
strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k]));
|
strings.concat(td, "/prog.ww.sepwork/", pkgs[p], sufs[k]));
|
||||||
@@ -190,38 +181,51 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
|
|||||||
samefile("seproot", "the final binary",
|
samefile("seproot", "the final binary",
|
||||||
strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww"));
|
strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww"));
|
||||||
|
|
||||||
// the fix: the root is compiled WITHOUT -I, so no __root.wwi
|
// The reachable private nominal is compiler data, not a public source name.
|
||||||
let s2: i32 = 0;
|
let s2: i32 = 0;
|
||||||
for (s2 < 2) {
|
for (s2 < 2) {
|
||||||
if (testenv.exists(strings.concat(td, "/prog.", tags[s2],
|
let rootiface: str = strings.concat(td, "/prog.", tags[s2],
|
||||||
".sepwork/__root.wwi"))) {
|
".sepwork/__root.wwi");
|
||||||
|
let ifacebytes: str = testenv.readfile(rootiface);
|
||||||
|
if (!testenv.has(ifacebytes, "type t = struct { v: i32 }")
|
||||||
|
|| testenv.has(ifacebytes, "export type t")
|
||||||
|
|| !testenv.has(ifacebytes, "export fn use(a: *t) i32;")) {
|
||||||
fail("seproot", strings.concat(drvs[s2],
|
fail("seproot", strings.concat(drvs[s2],
|
||||||
" produced __root.wwi (-I still passed for the root)"));
|
" did not carry a private reachable type as compiler data"));
|
||||||
};
|
};
|
||||||
s2 += 1;
|
s2 += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// replay the pre-fix invocation on the driver's own __root.unit.ww:
|
// Replay the package compile with -I: both compilers accept and emit the
|
||||||
// with -I the export-check FIRES (the isolated bug); without it the
|
// same self-contained export. A source importer cannot name its private t.
|
||||||
// post-fix invocation accepts. Both compilers.
|
|
||||||
let unit: str = strings.concat(td, "/prog.cs.sepwork/__root.unit.ww");
|
let unit: str = strings.concat(td, "/prog.cs.sepwork/__root.unit.ww");
|
||||||
let ciface: str = strings.concat(td, "/prog.cs.sepwork/c.wwi");
|
let ciface: str = strings.concat(td, "/prog.cs.sepwork/c.wwi");
|
||||||
|
let consumer: str = strings.concat(td, "/consumer.ww");
|
||||||
|
testenv.writefile(consumer, strings.concat(
|
||||||
|
"package consumer;\n",
|
||||||
|
"import main;\n",
|
||||||
|
"fn forbidden(v: *main.t) void = {};\n"));
|
||||||
let comps: []str = ["w6c", "w6c_ww"];
|
let comps: []str = ["w6c", "w6c_ww"];
|
||||||
let c: i32 = 0;
|
let c: i32 = 0;
|
||||||
for (c < 2) {
|
for (c < 2) {
|
||||||
let wwi: str = strings.concat(td, "/nv.", comps[c], ".wwi");
|
let wwi: str = strings.concat(td, "/nv.", comps[c], ".wwi");
|
||||||
let asmf: str = strings.concat(td, "/nv.", comps[c], ".s");
|
let asmf: str = strings.concat(td, "/nv.", comps[c], ".s");
|
||||||
let rav: []str = [testenv.driver(comps[c]), "-c", "--import", "c",
|
let rav: []str = [testenv.driver(comps[c]), "--entry", "-c",
|
||||||
ciface, "-I", wwi, "-o", asmf, unit];
|
"--import", "c", ciface, "-I", wwi, "-o", asmf, unit];
|
||||||
if (runcode(td, strings.concat("nvI_", comps[c]), rav) == 0) {
|
if (runcode(td, strings.concat("reexport_", comps[c]), rav) != 0) {
|
||||||
fail("seproot", strings.concat(comps[c], " -c -I accepted the ",
|
fail("seproot", strings.concat(comps[c],
|
||||||
"root export-over-unexported-type (vacuous gate)"));
|
" rejected the self-contained root export"));
|
||||||
};
|
};
|
||||||
let aav: []str = [testenv.driver(comps[c]), "-c", "--import", "c",
|
let rejectav: []str = [testenv.driver(comps[c]), "-c", "--import",
|
||||||
ciface, "-o", asmf, unit];
|
"main", wwi, "-o", asmf, consumer];
|
||||||
if (runcode(td, strings.concat("nvO_", comps[c]), aav) != 0) {
|
let reject: testenv.commandout;
|
||||||
fail("seproot", strings.concat(comps[c], " -c -o (no -I) ",
|
testenv.runcommand(td, td, strings.concat("private_", comps[c]),
|
||||||
"rejected the root unit (post-fix invocation)"));
|
rejectav, tmo(), &reject);
|
||||||
|
if (reject.termination != exec.termination.EXIT || reject.code == 0
|
||||||
|
|| !testenv.has(reject.stderr,
|
||||||
|
"package 'main' has no exported declaration 't'")) {
|
||||||
|
fail("seproot", strings.concat(comps[c],
|
||||||
|
" exposed the compiler-private type to source importers"));
|
||||||
};
|
};
|
||||||
c += 1;
|
c += 1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ fn cmpsepwork(label: str, csdir: str, wwdir: str) void = {
|
|||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < names.len) {
|
for (i < names.len) {
|
||||||
if (strings.hassuffix(names[i], ".s")
|
if (strings.hassuffix(names[i], ".s")
|
||||||
|| strings.hassuffix(names[i], ".wwi")) {
|
|| strings.hassuffix(names[i], ".wwi")
|
||||||
|
|| strings.hassuffix(names[i], ".a")) {
|
||||||
seen += 1;
|
seen += 1;
|
||||||
if (!testenv.same(
|
if (!testenv.same(
|
||||||
testenv.readfile(strings.concat(csdir, "/", names[i])),
|
testenv.readfile(strings.concat(csdir, "/", names[i])),
|
||||||
@@ -81,7 +82,7 @@ fn cmpsepwork(label: str, csdir: str, wwdir: str) void = {
|
|||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
// an existing-but-empty sepwork would pass the loop vacuously
|
// an existing-but-empty sepwork would pass the loop vacuously
|
||||||
if (seen == 0) { fail(label, "no .s/.wwi in cs sepwork"); };
|
if (seen == 0) { fail(label, "no package artifacts in cs sepwork"); };
|
||||||
};
|
};
|
||||||
|
|
||||||
@test fn coloimport() void = {
|
@test fn coloimport() void = {
|
||||||
@@ -210,11 +211,11 @@ fn depmainrow(label: str, entry: str, want: i32, deps: str,
|
|||||||
l += 1;
|
l += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// the root emits no .wwi post-#69, so its suffix set omits .wwi
|
// Both the dependency and raw explicit root emit complete package artifacts.
|
||||||
let parts: []str = ["aa.s", "aa.wwi", "aa.unit.ww", "__root.s",
|
let parts: []str = ["aa.s", "aa.wwi", "aa.a", "aa.unit.ww",
|
||||||
"__root.unit.ww"];
|
"__root.s", "__root.wwi", "__root.a", "__root.unit.ww"];
|
||||||
|
|
||||||
// cs==ww (rule 10) per layout over the fixed 5-part table
|
// cs==ww (rule 10) per layout over the complete package-artifact table
|
||||||
let l2: i32 = 0;
|
let l2: i32 = 0;
|
||||||
for (l2 < 2) {
|
for (l2 < 2) {
|
||||||
let p: i32 = 0;
|
let p: i32 = 0;
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ package seplink_test;
|
|||||||
// retired native carriers test/wcc/989_separchive_run.c and
|
// retired native carriers test/wcc/989_separchive_run.c and
|
||||||
// 989_sepcycle_dup.c; every assertion preserved.
|
// 989_sepcycle_dup.c; every assertion preserved.
|
||||||
//
|
//
|
||||||
// archive (#46 commit-5a) — `ww build` wraps each DEP package's .o in
|
// archive — `ww build` wraps every package action's .o in the existing
|
||||||
// a deterministic single-member .a and links the ROOT as a positional
|
// deterministic single-member .a and links the root archive first:
|
||||||
// .o (force-loaded): build+run exit 7 both stages; __root.a absent,
|
// build+run exit 7 both stages; __root.a + helper.a present; both archives
|
||||||
// __root.o + helper.a present; cs helper.a == ww helper.a (rule 10,
|
// are byte-identical across stages; 3 cold cstage rebuilds emit
|
||||||
// the .a byte-id substrate); 3 cold cstage rebuilds emit
|
// byte-identical archives (zeroed mtime/uid/gid, fixed mode/member —
|
||||||
// byte-identical helper.a (zeroed mtime/uid/gid, fixed mode/member —
|
|
||||||
// a floating byte would poison the content cache key).
|
// a floating byte would poison the content cache key).
|
||||||
//
|
//
|
||||||
// archivedup (#31 PASS 3) — two dep packages force the same link
|
// archivedup (#31 PASS 3) — two dep packages force the same link
|
||||||
@@ -94,22 +93,20 @@ fn runcode(dir: str, name: str, argv: []str) i32 = {
|
|||||||
s += 1;
|
s += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// layout: root stays a positional force-loaded .o, deps become .a
|
// layout: root and dependency are both package archives.
|
||||||
if (testenv.exists(strings.concat(td, "/prog.cs.sepwork/__root.a"))) {
|
if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/__root.a"))
|
||||||
fail("archive", "root wrapped in .a (should stay positional .o)");
|
|| !testenv.exists(strings.concat(td, "/prog.cs.sepwork/helper.a"))) {
|
||||||
};
|
fail("archive", "missing root or dependency archive");
|
||||||
if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/__root.o"))) {
|
|
||||||
fail("archive", "missing root .o");
|
|
||||||
};
|
|
||||||
if (!testenv.exists(strings.concat(td, "/prog.cs.sepwork/helper.a"))) {
|
|
||||||
fail("archive", "missing dep helper.a");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// rule 10: the .a byte-id substrate
|
// rule 10: the complete .a byte-id substrate
|
||||||
if (!testenv.same(
|
if (!testenv.same(
|
||||||
testenv.readfile(strings.concat(td, "/prog.cs.sepwork/helper.a")),
|
testenv.readfile(strings.concat(td, "/prog.cs.sepwork/helper.a")),
|
||||||
testenv.readfile(strings.concat(td, "/prog.ww.sepwork/helper.a")))) {
|
testenv.readfile(strings.concat(td, "/prog.ww.sepwork/helper.a")))
|
||||||
fail("archive", "cs helper.a != ww helper.a (rule 10 .a byte-id)");
|
|| !testenv.same(
|
||||||
|
testenv.readfile(strings.concat(td, "/prog.cs.sepwork/__root.a")),
|
||||||
|
testenv.readfile(strings.concat(td, "/prog.ww.sepwork/__root.a")))) {
|
||||||
|
fail("archive", "cs package archives != ww package archives");
|
||||||
};
|
};
|
||||||
|
|
||||||
// determinism: 3 cold cstage rebuilds -> byte-identical .a
|
// determinism: 3 cold cstage rebuilds -> byte-identical .a
|
||||||
@@ -132,9 +129,18 @@ fn runcode(dir: str, name: str, argv: []str) i32 = {
|
|||||||
let a2: str = testenv.readfile(strings.concat(det2,
|
let a2: str = testenv.readfile(strings.concat(det2,
|
||||||
".sepwork/helper.a"));
|
".sepwork/helper.a"));
|
||||||
if (!testenv.same(a0, a1) || !testenv.same(a1, a2)) {
|
if (!testenv.same(a0, a1) || !testenv.same(a1, a2)) {
|
||||||
fail("archive", strings.concat(".a not deterministic across 3 ",
|
fail("archive", strings.concat("dependency .a not deterministic across 3 ",
|
||||||
"builds (floating bytes poison the cache key)"));
|
"builds (floating bytes poison the cache key)"));
|
||||||
};
|
};
|
||||||
|
let r0: str = testenv.readfile(strings.concat(det0,
|
||||||
|
".sepwork/__root.a"));
|
||||||
|
let r1: str = testenv.readfile(strings.concat(det1,
|
||||||
|
".sepwork/__root.a"));
|
||||||
|
let r2: str = testenv.readfile(strings.concat(det2,
|
||||||
|
".sepwork/__root.a"));
|
||||||
|
if (!testenv.same(r0, r1) || !testenv.same(r1, r2)) {
|
||||||
|
fail("archive", "root .a not deterministic across 3 builds");
|
||||||
|
};
|
||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ slurp(const char *path, char **outbuf, size_t *outlen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* #93 sep layout: the flip stops emitting a monolithic <tool>/main.o;
|
/* #93 sep layout: the flip stops emitting a monolithic <tool>/main.o;
|
||||||
* the linkable unit is now the per-package .o + reverse-topo .a set the
|
* the linkable unit is now the root .a + reverse-topo .a set the
|
||||||
* sep driver assembles (a raw `w6l <root>.o *.a libwwrt.a` from the test
|
* sep driver assembles (a raw `w6l <root>.a *.a libwwrt.a` from the test
|
||||||
* side fails — `undefined reference` — because it can't reproduce the
|
* side fails — `undefined reference` — because it can't reproduce the
|
||||||
* driver's topo order). Drive each real directory package through the
|
* driver's topo order). Drive each real directory package through the
|
||||||
* full sep build twice; both compile directly and differ only in the
|
* full sep build twice; both compile directly and differ only in the
|
||||||
@@ -139,7 +139,7 @@ main(void)
|
|||||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||||
|
|
||||||
/* Real bootstrap-style links: each selfhost tool's full sep build
|
/* Real bootstrap-style links: each selfhost tool's full sep build
|
||||||
* (root .o + reverse-topo dep .a set + libwwrt.a). Both builds compile
|
* (root .a + reverse-topo dep .a set + libwwrt.a). Both builds compile
|
||||||
* directly and differ only in the selected linker. (wwdump is excluded —
|
* directly and differ only in the selected linker. (wwdump is excluded —
|
||||||
* it imports the compiler-internal cmd packages syntax/check/cgen, which don't resolve
|
* it imports the compiler-internal cmd packages syntax/check/cgen, which don't resolve
|
||||||
* under the lib-path sep dep scan; w6a/w6l are self-contained
|
* under the lib-path sep dep scan; w6a/w6l are self-contained
|
||||||
@@ -157,6 +157,6 @@ main(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("w6l_ww: byte-identical to C w6l on %d selfhost tool links "
|
printf("w6l_ww: byte-identical to C w6l on %d selfhost tool links "
|
||||||
"(sep root .o + reverse-topo .a set + libwwrt.a)\n", n);
|
"(sep root .a + reverse-topo .a set + libwwrt.a)\n", n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user