ww: separate package identity from declared name
This commit is contained in:
320
cmd/ww/main.c
320
cmd/ww/main.c
@@ -717,6 +717,9 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
|
||||
struct sepbind {
|
||||
char kind;
|
||||
char *name;
|
||||
char *source;
|
||||
int line;
|
||||
int col;
|
||||
int dep; /* stable canonical action index; -1 for inline */
|
||||
};
|
||||
|
||||
@@ -753,6 +756,7 @@ struct seppkg {
|
||||
int root; /* requested usage; never package-action identity */
|
||||
int link_entry; /* package supplies the executable's bare main */
|
||||
int generated_main; /* compiler-owned generated test-main package */
|
||||
int generated_target; /* target variant used by generated test main */
|
||||
int failed; /* discovery/compile failure reaches this action */
|
||||
int test_support; /* compiler-generated -T support package */
|
||||
int loaded; /* directory membership/name loaded exactly once */
|
||||
@@ -1094,18 +1098,20 @@ sep_root_is_command(const struct seppkg *p)
|
||||
return strcmp(p->name, "main") == 0;
|
||||
}
|
||||
|
||||
static int sep_external_production_edge(const struct sepgraph *, int, int);
|
||||
static int sep_external_name_matches_production(const struct sepgraph *,
|
||||
int, int);
|
||||
|
||||
static int
|
||||
sep_forbidden_command_import(const struct sepgraph *g, int importer, int dep)
|
||||
{
|
||||
const struct seppkg *from = &g->pkg[importer];
|
||||
const struct seppkg *to = &g->pkg[dep];
|
||||
if (strcmp(to->name, "main") != 0 || to->role != SEP_ROLE_NORMAL)
|
||||
return 0;
|
||||
/* An external test's exact import of its colocated command production is
|
||||
* test-variant wiring, not a general source-importable command edge. */
|
||||
return !(from->variant == SEP_VARIANT_EXTERNAL
|
||||
&& sep_command_declared_name(from)
|
||||
&& strcmp(from->canon, to->canon) == 0);
|
||||
return !(sep_external_production_edge(g, importer, dep)
|
||||
&& sep_external_name_matches_production(g, importer, dep));
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1550,7 +1556,10 @@ sep_pkg_free_fields(struct seppkg *p)
|
||||
{
|
||||
for (int j = 0; j < p->nsources; j++) free(p->sources[j]);
|
||||
free(p->sources);
|
||||
for (int j = 0; j < p->bindings.n; j++) free(p->bindings.v[j].name);
|
||||
for (int j = 0; j < p->bindings.n; j++) {
|
||||
free(p->bindings.v[j].name);
|
||||
free(p->bindings.v[j].source);
|
||||
}
|
||||
free(p->bindings.v);
|
||||
free(p->context_state);
|
||||
free(p->deps);
|
||||
@@ -2071,28 +2080,46 @@ use_node_cmp(const void *a, const void *b)
|
||||
const char *yp = y->usepath ? y->usepath : y->str;
|
||||
int r = strcmp(xp, yp);
|
||||
if (r != 0) return r;
|
||||
r = strcmp(x->pos.file ? x->pos.file : "",
|
||||
y->pos.file ? y->pos.file : "");
|
||||
if (r != 0) return r;
|
||||
if (x->pos.line != y->pos.line) return x->pos.line - y->pos.line;
|
||||
return x->pos.col - y->pos.col;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_external_production_name(const struct seppkg *pkg, const char *path,
|
||||
int leaf_only)
|
||||
sep_external_production_name(const struct seppkg *pkg, const char *name)
|
||||
{
|
||||
if (pkg->variant != SEP_VARIANT_EXTERNAL
|
||||
|| pkg->test_package == NULL || pkg->test_package[0] == '\0')
|
||||
return 0;
|
||||
const char *name = path;
|
||||
if (leaf_only) {
|
||||
const char *dot = strrchr(path, '.');
|
||||
if (dot != NULL) name = dot + 1;
|
||||
}
|
||||
size_t n = strlen(name);
|
||||
size_t tn = strlen(pkg->test_package);
|
||||
return tn == n + 5 && strncmp(pkg->test_package, name, n) == 0
|
||||
&& strcmp(pkg->test_package + n, "_test") == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_external_production_edge(const struct sepgraph *g, int importer, int dep)
|
||||
{
|
||||
const struct seppkg *from = &g->pkg[importer];
|
||||
const struct seppkg *to = &g->pkg[dep];
|
||||
return from->variant == SEP_VARIANT_EXTERNAL
|
||||
&& to->variant == SEP_VARIANT_PRODUCTION
|
||||
&& to->role == SEP_ROLE_NORMAL
|
||||
&& strcmp(from->canon, to->canon) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_external_name_matches_production(const struct sepgraph *g, int importer,
|
||||
int dep)
|
||||
{
|
||||
const struct seppkg *from = &g->pkg[importer];
|
||||
const struct seppkg *to = &g->pkg[dep];
|
||||
return from->name != NULL && to->name != NULL
|
||||
&& sep_external_production_name(from, to->name);
|
||||
}
|
||||
|
||||
static char *sep_local_import_base(const struct seppkg *);
|
||||
|
||||
/* Canonical source bindings make a shared action independent of the request
|
||||
@@ -2101,20 +2128,21 @@ static char *sep_local_import_base(const struct seppkg *);
|
||||
* route/root legality deliberately does not enter action identity. */
|
||||
static int
|
||||
sep_binding_add(struct sepbindset *bindings, char kind, const char *name,
|
||||
int dep)
|
||||
int dep, Pos pos)
|
||||
{
|
||||
for (int i = 0; i < bindings->n; i++)
|
||||
if (bindings->v[i].kind == kind
|
||||
&& bindings->v[i].dep == dep
|
||||
&& strcmp(bindings->v[i].name, name) == 0)
|
||||
return 0;
|
||||
if (bindings->n == INT_MAX) return sep_fail_size();
|
||||
if (sep_reserve((void **)&bindings->v, &bindings->cap,
|
||||
bindings->n + 1, sizeof *bindings->v) < 0)
|
||||
return -1;
|
||||
char *copy = strdup(name);
|
||||
if (copy == NULL) return sep_fail_nomem();
|
||||
bindings->v[bindings->n++] = (struct sepbind){ kind, copy, dep };
|
||||
char *source = strdup(pos.file ? pos.file : "");
|
||||
if (source == NULL) {
|
||||
free(copy);
|
||||
return sep_fail_nomem();
|
||||
}
|
||||
bindings->v[bindings->n++] = (struct sepbind){
|
||||
kind, copy, source, pos.line, pos.col, dep };
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2126,13 +2154,83 @@ sep_binding_cmp(const void *a, const void *b)
|
||||
if (r != 0) return r;
|
||||
if (x->kind != y->kind) return (unsigned char)x->kind
|
||||
- (unsigned char)y->kind;
|
||||
return x->dep < y->dep ? -1 : x->dep > y->dep;
|
||||
if (x->dep != y->dep) return x->dep < y->dep ? -1 : 1;
|
||||
r = strcmp(x->source, y->source);
|
||||
if (r != 0) return r;
|
||||
if (x->line != y->line) return x->line - y->line;
|
||||
return x->col - y->col;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_binding_semantic_same(const struct sepbind *a, const struct sepbind *b)
|
||||
{
|
||||
return a->kind == b->kind && a->dep == b->dep
|
||||
&& strcmp(a->name, b->name) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_bindsets_semantically_same(const struct sepbindset *a,
|
||||
const struct sepbindset *b)
|
||||
{
|
||||
int ai = 0, bi = 0;
|
||||
while (ai < a->n && bi < b->n) {
|
||||
if (!sep_binding_semantic_same(&a->v[ai], &b->v[bi])) return 0;
|
||||
struct sepbind *av = &a->v[ai];
|
||||
struct sepbind *bv = &b->v[bi];
|
||||
do ai++; while (ai < a->n
|
||||
&& sep_binding_semantic_same(av, &a->v[ai]));
|
||||
do bi++; while (bi < b->n
|
||||
&& sep_binding_semantic_same(bv, &b->v[bi]));
|
||||
}
|
||||
return ai == a->n && bi == b->n;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_validate_bindings(const struct sepgraph *g,
|
||||
const struct sepbindset *bindings)
|
||||
{
|
||||
const char *name = NULL;
|
||||
int dep = -1;
|
||||
for (int i = 0; i < bindings->n; i++) {
|
||||
const struct sepbind *b = &bindings->v[i];
|
||||
if (b->kind != 'D') continue;
|
||||
if (name != NULL && strcmp(name, b->name) == 0 && dep != b->dep) {
|
||||
Pos pos = { b->source, b->line, b->col };
|
||||
errorf(pos, "package path %s resolves to both %s and %s",
|
||||
b->name, g->pkg[dep].path, g->pkg[b->dep].path);
|
||||
return -1;
|
||||
}
|
||||
name = b->name;
|
||||
dep = b->dep;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_binding_needs_map(const struct sepgraph *g, const struct sepbind *b)
|
||||
{
|
||||
return b->kind == 'D' && b->dep >= 0 && b->dep < g->n
|
||||
&& strcmp(b->name, g->pkg[b->dep].path) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_binding_first_map(const struct sepgraph *g,
|
||||
const struct sepbindset *bindings, int i)
|
||||
{
|
||||
if (!sep_binding_needs_map(g, &bindings->v[i])) return 0;
|
||||
for (int j = i - 1; j >= 0
|
||||
&& strcmp(bindings->v[j].name, bindings->v[i].name) == 0; j--)
|
||||
if (sep_binding_needs_map(g, &bindings->v[j])) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
sep_bindset_free(struct sepbindset *bindings)
|
||||
{
|
||||
for (int i = 0; i < bindings->n; i++) free(bindings->v[i].name);
|
||||
for (int i = 0; i < bindings->n; i++) {
|
||||
free(bindings->v[i].name);
|
||||
free(bindings->v[i].source);
|
||||
}
|
||||
free(bindings->v);
|
||||
bindings->v = NULL;
|
||||
bindings->n = bindings->cap = 0;
|
||||
@@ -2403,12 +2501,9 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file,
|
||||
if (nuse > 1) qsort(uses, (size_t)nuse, sizeof *uses, use_node_cmp);
|
||||
|
||||
int rc = 0;
|
||||
const char *previous = NULL;
|
||||
for (int i = 0; i < nuse && rc == 0; i++) {
|
||||
Node *u = uses[i];
|
||||
const char *name = u->usepath ? u->usepath : u->str;
|
||||
if (previous && strcmp(previous, name) == 0) continue;
|
||||
previous = name;
|
||||
if (reserved_import_path(name)) {
|
||||
errorf(u->pos, "package path %s is reserved", name);
|
||||
rc = -1;
|
||||
@@ -2442,9 +2537,8 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file,
|
||||
g->context[context].route);
|
||||
int literal_self = route_suffix != NULL
|
||||
? strcmp(path_form, route_suffix) == 0
|
||||
&& sep_external_production_name(&g->pkg[pi], name, 1)
|
||||
: strchr(name, '.') == NULL
|
||||
&& sep_external_production_name(&g->pkg[pi], name, 0);
|
||||
&& sep_external_production_name(&g->pkg[pi], name);
|
||||
if (literal_self) {
|
||||
if (g->pkg[pi].import_base != NULL)
|
||||
resolved.identity = strdup(g->pkg[pi].import_base);
|
||||
@@ -2471,18 +2565,17 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file,
|
||||
break;
|
||||
}
|
||||
if (!located) {
|
||||
const char *dot = strrchr(name, '.');
|
||||
const char *leaf = dot ? dot + 1 : name;
|
||||
int inline_package = 0;
|
||||
if (!g->pkg[pi].is_dir)
|
||||
for (Node *package = imports->body; package;
|
||||
package = package->next)
|
||||
if (strcmp(package->module, leaf) == 0) {
|
||||
if (strcmp(package->module, name) == 0) {
|
||||
inline_package = 1;
|
||||
break;
|
||||
}
|
||||
if (inline_package) {
|
||||
if (sep_binding_add(bindings, 'I', name, -1) < 0)
|
||||
if (sep_binding_add(bindings, 'I', name, -1,
|
||||
u->pos) < 0)
|
||||
rc = -1;
|
||||
continue;
|
||||
}
|
||||
@@ -2506,10 +2599,7 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file,
|
||||
break;
|
||||
}
|
||||
int self = strcmp(canon, g->pkg[pi].canon) == 0;
|
||||
if (self
|
||||
&& (sep_external_production_name(&g->pkg[pi], name, 1)
|
||||
|| (g->pkg[pi].variant == SEP_VARIANT_EXTERNAL
|
||||
&& sep_command_declared_name(&g->pkg[pi]))))
|
||||
if (self && g->pkg[pi].variant == SEP_VARIANT_EXTERNAL)
|
||||
external_production = 1;
|
||||
if (self && !external_production) {
|
||||
const char *owner = g->pkg[pi].path[0]
|
||||
@@ -2574,7 +2664,7 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file,
|
||||
int child_context = sep_child_context_for(g, context,
|
||||
resolved.entry, resolved.source_root);
|
||||
if (child_context < 0
|
||||
|| sep_binding_add(bindings, 'D', name, di) < 0
|
||||
|| sep_binding_add(bindings, 'D', name, di, u->pos) < 0
|
||||
|| sep_add_dep(g, pi, di) < 0
|
||||
|| sep_children_add(children, di, child_context) < 0) {
|
||||
free(canon);
|
||||
@@ -2688,6 +2778,7 @@ sep_add_generated_main(struct sepgraph *g, struct sepproduct *product,
|
||||
p->root = 1;
|
||||
p->link_entry = 1;
|
||||
p->generated_main = 1;
|
||||
p->generated_target = variant;
|
||||
p->loaded = 1;
|
||||
p->emit_context = product->context;
|
||||
if (sep_set_context_state(p, product->context, 2) < 0
|
||||
@@ -2754,18 +2845,6 @@ sep_prepare_pkg_context(struct sepgraph *g, int pi, int context,
|
||||
for (int i = 0; i < g->pkg[pi].nsources && rc == 0; i++)
|
||||
rc = sep_scan_file(g, pi, g->pkg[pi].sources[i],
|
||||
context, &fv, &bindings, children, 1);
|
||||
if (rc == 0 && g->pkg[pi].path[0] != '\0'
|
||||
&& !g->pkg[pi].test_support) {
|
||||
const char *dot = strrchr(g->pkg[pi].path, '.');
|
||||
const char *leaf = dot ? dot + 1 : g->pkg[pi].path;
|
||||
if (strcmp(g->pkg[pi].name, leaf) != 0
|
||||
&& !sep_command_declared_name(&g->pkg[pi])) {
|
||||
fprintf(stderr,
|
||||
"ww: package %s does not match import path %s\n",
|
||||
g->pkg[pi].name, g->pkg[pi].path);
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
} else if (rc == 0) {
|
||||
rc = sep_scan_file(g, pi, g->pkg[pi].entry, context,
|
||||
&fv, &bindings, children, 0);
|
||||
@@ -2774,6 +2853,7 @@ sep_prepare_pkg_context(struct sepgraph *g, int pi, int context,
|
||||
if (bindings.n > 1)
|
||||
qsort(bindings.v, (size_t)bindings.n,
|
||||
sizeof *bindings.v, sep_binding_cmp);
|
||||
if (rc == 0 && sep_validate_bindings(g, &bindings) < 0) rc = -1;
|
||||
if (rc == 0 && g->pkg[pi].emit_context < 0) {
|
||||
g->pkg[pi].bindings = bindings;
|
||||
bindings.v = NULL;
|
||||
@@ -2781,12 +2861,7 @@ sep_prepare_pkg_context(struct sepgraph *g, int pi, int context,
|
||||
g->pkg[pi].emit_context = context;
|
||||
} else if (rc == 0) {
|
||||
struct sepbindset *want = &g->pkg[pi].bindings;
|
||||
if (want->n != bindings.n) rc = -1;
|
||||
for (int i = 0; i < want->n && rc == 0; i++)
|
||||
if (want->v[i].kind != bindings.v[i].kind
|
||||
|| want->v[i].dep != bindings.v[i].dep
|
||||
|| strcmp(want->v[i].name, bindings.v[i].name) != 0)
|
||||
rc = -1;
|
||||
if (!sep_bindsets_semantically_same(want, &bindings)) rc = -1;
|
||||
if (rc < 0) {
|
||||
const char *first =
|
||||
g->context[g->pkg[pi].emit_context].root;
|
||||
@@ -2875,6 +2950,14 @@ sep_load_pkg(struct sepgraph *g, int pi, int context)
|
||||
if (f->pending_dep >= 0) {
|
||||
int dep = f->pending_dep;
|
||||
f->pending_dep = -1;
|
||||
if (dep != f->pkg
|
||||
&& sep_external_production_edge(g, f->pkg, dep)
|
||||
&& !sep_external_name_matches_production(g, f->pkg, dep)) {
|
||||
fprintf(stderr,
|
||||
"ww: external test package %s does not match production package %s\n",
|
||||
g->pkg[f->pkg].name, g->pkg[dep].name);
|
||||
goto failed;
|
||||
}
|
||||
if (dep != f->pkg
|
||||
&& sep_forbidden_command_import(g, f->pkg, dep)) {
|
||||
fprintf(stderr,
|
||||
@@ -3055,54 +3138,27 @@ sep_reverse_import_base(const struct sepgraph *g, const struct seppkg *pkg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
sep_ordinary_declared_name(const struct seppkg *p)
|
||||
{
|
||||
if (p->name == NULL || p->name[0] == '\0') return NULL;
|
||||
size_t n = strlen(p->name);
|
||||
if (p->variant == SEP_VARIANT_EXTERNAL) {
|
||||
if (n <= 5 || strcmp(p->name + n - 5, "_test") != 0) {
|
||||
fprintf(stderr,
|
||||
"ww: package-test selector does not name an external package\n");
|
||||
return NULL;
|
||||
}
|
||||
n -= 5;
|
||||
}
|
||||
char *out = malloc(n + 1);
|
||||
if (out == NULL) {
|
||||
sep_fail_nomem();
|
||||
return NULL;
|
||||
}
|
||||
memcpy(out, p->name, n);
|
||||
out[n] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
/* The reserved local namespace is reversible, so filesystem identity never
|
||||
* depends on a hash, request order, output name, or another selected package. */
|
||||
* depends on a hash, request order, output name, declared package name, or
|
||||
* another selected package. */
|
||||
static char *
|
||||
sep_local_import_base(const struct seppkg *p)
|
||||
{
|
||||
char *leaf = sep_ordinary_declared_name(p);
|
||||
if (leaf == NULL) return NULL;
|
||||
size_t prefix = strlen(SEP_LOCAL_IMPORT_PREFIX);
|
||||
size_t canon_len = strlen(p->canon), leaf_len = strlen(leaf);
|
||||
if (leaf_len > (size_t)-1 - prefix - 4
|
||||
|| canon_len > ((size_t)-1 - prefix - 4 - leaf_len) / 4) {
|
||||
size_t canon_len = strlen(p->canon);
|
||||
if (canon_len > ((size_t)-1 - prefix - 3) / 4) {
|
||||
sep_fail_size();
|
||||
free(leaf);
|
||||
return NULL;
|
||||
}
|
||||
size_t outsz = prefix + 3 + 4 * canon_len + leaf_len + 1;
|
||||
size_t outsz = prefix + 2 + 4 * canon_len + 1;
|
||||
char *out = malloc(outsz);
|
||||
if (out == NULL) {
|
||||
sep_fail_nomem();
|
||||
free(leaf);
|
||||
return NULL;
|
||||
}
|
||||
size_t off = 0;
|
||||
int n = snprintf(out, outsz, "%s.p", SEP_LOCAL_IMPORT_PREFIX);
|
||||
if (n < 0 || (size_t)n >= outsz) { free(leaf); free(out); return NULL; }
|
||||
if (n < 0 || (size_t)n >= outsz) { free(out); return NULL; }
|
||||
off = (size_t)n;
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
for (const unsigned char *s = (const unsigned char *)p->canon;
|
||||
@@ -3110,25 +3166,21 @@ sep_local_import_base(const struct seppkg *p)
|
||||
unsigned char c = *s;
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9')) {
|
||||
if (off + 1 >= outsz) { free(leaf); free(out); return NULL; }
|
||||
if (off + 1 >= outsz) { free(out); return NULL; }
|
||||
out[off++] = (char)c;
|
||||
} else if (c == '_' || c == '/') {
|
||||
if (off + 2 >= outsz) { free(leaf); free(out); return NULL; }
|
||||
if (off + 2 >= outsz) { free(out); return NULL; }
|
||||
out[off++] = '_';
|
||||
out[off++] = c == '_' ? 'u' : 's';
|
||||
} else {
|
||||
if (off + 4 >= outsz) { free(leaf); free(out); return NULL; }
|
||||
if (off + 4 >= outsz) { free(out); return NULL; }
|
||||
out[off++] = '_';
|
||||
out[off++] = 'x';
|
||||
out[off++] = hex[c >> 4];
|
||||
out[off++] = hex[c & 15];
|
||||
}
|
||||
}
|
||||
size_t ln = leaf_len;
|
||||
if (off + 1 + ln + 1 > outsz) { free(leaf); free(out); return NULL; }
|
||||
out[off++] = '.';
|
||||
memcpy(out + off, leaf, ln + 1);
|
||||
free(leaf);
|
||||
out[off] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -3193,17 +3245,6 @@ sep_finalize_directory_identities(struct sepgraph *g)
|
||||
struct seppkg *p = &g->pkg[pi];
|
||||
if (!p->is_dir || p->generated_main || p->failed || !p->loaded)
|
||||
continue;
|
||||
const char *dot = strrchr(p->path, '.');
|
||||
const char *leaf = dot ? dot + 1 : p->path;
|
||||
int support_alias = p->role == SEP_ROLE_TEST_SUPPORT
|
||||
&& strcmp(p->path, SEP_TEST_SUPPORT_MODULE) == 0
|
||||
&& strcmp(p->name, "test") == 0;
|
||||
if (!support_alias && strcmp(p->name, leaf) != 0
|
||||
&& !sep_command_declared_name(p)) {
|
||||
fprintf(stderr, "ww: package %s does not match import path %s\n",
|
||||
p->name, p->path);
|
||||
return -1;
|
||||
}
|
||||
free(p->artifact);
|
||||
p->artifact = NULL;
|
||||
if (p->variant == SEP_VARIANT_SAME_TEST)
|
||||
@@ -3418,9 +3459,7 @@ sep_compose_unit(struct sepgraph *g, int pi, const char *unitf)
|
||||
* retarget cannot reuse stale assembly even when export bytes are equal. */
|
||||
for (int i = 0; i < g->pkg[pi].bindings.n && bodyrc == 0; i++) {
|
||||
struct sepbind *b = &g->pkg[pi].bindings.v[i];
|
||||
if (b->kind != 'D' || b->dep < 0 || b->dep >= g->n
|
||||
|| strcmp(b->name, g->pkg[b->dep].path) == 0)
|
||||
continue;
|
||||
if (!sep_binding_first_map(g, &g->pkg[pi].bindings, i)) continue;
|
||||
if (fprintf(u, "//ww:import-map %s %s ",
|
||||
b->name, g->pkg[b->dep].path) < 0
|
||||
|| sep_emit_hex(u, g->pkg[b->dep].canon) < 0
|
||||
@@ -3624,7 +3663,7 @@ static void
|
||||
workdir_stamp_text(char *buf, size_t bufsz, int is_test, int emit_asm)
|
||||
{
|
||||
snprintf(buf, bufsz, "ww workdir fmt %d mode %s asm %d\n",
|
||||
is_test ? 12 : 13, is_test ? "test" : "build", emit_asm);
|
||||
is_test ? 13 : 14, is_test ? "test" : "build", emit_asm);
|
||||
}
|
||||
|
||||
/* A stale global builder identity invalidates every committed unit voucher in
|
||||
@@ -3658,6 +3697,20 @@ invalidate_workdir_units(const char *scratch)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
sep_discard_action_staging(int warm, const char *unit, const char *wwi,
|
||||
const char *assembly, const char *object, const char *archive)
|
||||
{
|
||||
if (!warm) return 0;
|
||||
const char *paths[] = { unit, wwi, assembly, object, archive };
|
||||
for (size_t i = 0; i < sizeof paths / sizeof paths[0]; i++) {
|
||||
if (unlink(paths[i]) == 0 || errno == ENOENT) continue;
|
||||
fprintf(stderr, "ww: cannot remove staged package artifacts\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sep_created_dirs {
|
||||
char path[PATH_MAX];
|
||||
unsigned short offset[(PATH_MAX + 1) / 2];
|
||||
@@ -4200,7 +4253,15 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
const char *cs = warm ? asmnew : asmf;
|
||||
const char *co = warm ? objnew : obj;
|
||||
const char *ca = warm ? anew : apath;
|
||||
if (sep_discard_action_staging(warm, unitnew, wwinew, asmnew,
|
||||
objnew, anew) < 0) {
|
||||
g->pkg[pi].failed = 1;
|
||||
any_failed = 1;
|
||||
continue;
|
||||
}
|
||||
if (sep_compose_unit(g, pi, cu) < 0) {
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
g->pkg[pi].failed = 1;
|
||||
any_failed = 1;
|
||||
continue;
|
||||
@@ -4225,26 +4286,30 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
}
|
||||
int nmaps = 0;
|
||||
for (int k = 0; k < g->pkg[pi].bindings.n; k++) {
|
||||
struct sepbind *b = &g->pkg[pi].bindings.v[k];
|
||||
if (b->kind == 'D' && b->dep >= 0 && b->dep < g->n
|
||||
&& strcmp(b->name, g->pkg[b->dep].path) != 0) {
|
||||
if (nmaps == INT_MAX) {
|
||||
sep_fail_size();
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
nmaps++;
|
||||
if (!sep_binding_first_map(g, &g->pkg[pi].bindings, k))
|
||||
continue;
|
||||
if (nmaps == INT_MAX) {
|
||||
sep_fail_size();
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
nmaps++;
|
||||
}
|
||||
size_t cargvcap = 12;
|
||||
size_t cargvcap = 14;
|
||||
if ((size_t)g->pkg[pi].ndeps > ((size_t)-1 - cargvcap) / 3) {
|
||||
fprintf(stderr, "ww: package graph is too large\n");
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
cargvcap += 3 * (size_t)g->pkg[pi].ndeps;
|
||||
if ((size_t)nmaps > ((size_t)-1 - cargvcap) / 3) {
|
||||
fprintf(stderr, "ww: package graph is too large\n");
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
@@ -4257,6 +4322,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
if (cargv == NULL || (g->pkg[pi].ndeps > 0
|
||||
&& importfiles == NULL)) {
|
||||
fprintf(stderr, "ww: out of memory\n");
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
free(importfiles);
|
||||
free(cargv);
|
||||
free(order);
|
||||
@@ -4270,6 +4337,10 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
cargv[cpos++] = "--entry";
|
||||
cargv[cpos++] = "--test-support-module";
|
||||
cargv[cpos++] = (char *)test_support_module;
|
||||
if (g->pkg[pi].generated_main) {
|
||||
cargv[cpos++] = "--test-target-package";
|
||||
cargv[cpos++] = g->pkg[g->pkg[pi].generated_target].path;
|
||||
}
|
||||
} else {
|
||||
if (g->pkg[pi].variant == SEP_VARIANT_SAME_TEST
|
||||
|| g->pkg[pi].variant == SEP_VARIANT_EXTERNAL)
|
||||
@@ -4294,8 +4365,7 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
}
|
||||
for (int k = 0; k < g->pkg[pi].bindings.n; k++) {
|
||||
struct sepbind *b = &g->pkg[pi].bindings.v[k];
|
||||
if (b->kind != 'D' || b->dep < 0 || b->dep >= g->n
|
||||
|| strcmp(b->name, g->pkg[b->dep].path) == 0)
|
||||
if (!sep_binding_first_map(g, &g->pkg[pi].bindings, k))
|
||||
continue;
|
||||
cargv[cpos++] = "--import-map";
|
||||
cargv[cpos++] = b->name;
|
||||
@@ -4315,6 +4385,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||
g->pkg[pi].failed = 1;
|
||||
any_failed = 1;
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
continue;
|
||||
}
|
||||
g->pkg[pi].export_changed = !warm
|
||||
@@ -4327,6 +4399,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||
g->pkg[pi].failed = 1;
|
||||
any_failed = 1;
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -4338,6 +4412,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||
g->pkg[pi].failed = 1;
|
||||
any_failed = 1;
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -4353,6 +4429,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
g->pkg[pi].path[0] ? g->pkg[pi].path : "(root)");
|
||||
g->pkg[pi].failed = 1;
|
||||
any_failed = 1;
|
||||
(void)sep_discard_action_staging(warm, unitnew, wwinew,
|
||||
asmnew, objnew, anew);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user