commit fd3a8d1
shrub
·
2026-05-05 14:49:17 +0000 UTC
parent d304126
handle [], fix auto var handling in function expansion, dedup $^
2 files changed,
+106,
-8
+50,
-2
1@@ -229,6 +229,28 @@ findclose(const char *s, size_t i, size_t n, char close)
2 static char *expandvarref(struct EvalCtx *ctx, const char *s, size_t n);
3 static char *expandref(struct EvalCtx *ctx, const char *s, size_t n);
4
5+static char *
6+autoprereqsval(const struct StrList *prereqs, char kind)
7+{
8+ if (kind == '+')
9+ return joinstrs(prereqs, " ");
10+
11+ {
12+ size_t i;
13+ struct StrList uniq;
14+ char *joined;
15+
16+ memset(&uniq, 0, sizeof(uniq));
17+ for (i = 0; i < prereqs->n; i++) {
18+ if (!hasword(&uniq, prereqs->v[i]))
19+ addstr(&uniq, prereqs->v[i]);
20+ }
21+ joined = joinstrs(&uniq, " ");
22+ freestrs(&uniq);
23+ return joined;
24+ }
25+}
26+
27 static char *
28 expandname(struct EvalCtx *ctx, const char *s)
29 {
30@@ -264,7 +286,7 @@ expandname(struct EvalCtx *ctx, const char *s)
31 ctx->auto_prereqs) {
32 char *joined;
33
34- joined = joinstrs(ctx->auto_prereqs, " ");
35+ joined = autoprereqsval(ctx->auto_prereqs, s[i + 1]);
36 bufappend(&out, joined);
37 free(joined);
38 i++;
39@@ -555,7 +577,33 @@ expandstr(struct EvalCtx *ctx, const char *s)
40 continue;
41 }
42 if (s[i + 1] != '(' && s[i + 1] != '{') {
43- /* leave automatic variables for expandauto and translateauto */
44+ if (s[i + 1] == '@' && ctx->auto_target) {
45+ bufappend(&out, ctx->auto_target);
46+ i++;
47+ continue;
48+ }
49+ if (s[i + 1] == '<' && ctx->auto_prereqs) {
50+ if (ctx->auto_prereqs->n > 0)
51+ bufappend(&out, ctx->auto_prereqs->v[0]);
52+ i++;
53+ continue;
54+ }
55+ if ((s[i + 1] == '^' || s[i + 1] == '+' || s[i + 1] == '?') &&
56+ ctx->auto_prereqs) {
57+ char *joined;
58+
59+ joined = autoprereqsval(ctx->auto_prereqs, s[i + 1]);
60+ bufappend(&out, joined);
61+ free(joined);
62+ i++;
63+ continue;
64+ }
65+ if (s[i + 1] == '*' && ctx->auto_stem) {
66+ bufappend(&out, ctx->auto_stem);
67+ i++;
68+ continue;
69+ }
70+ /* leave unresolved automatic vars for later translation */
71 if (s[i + 1] == '@' || s[i + 1] == '<' || s[i + 1] == '^' ||
72 s[i + 1] == '+' || s[i + 1] == '?' || s[i + 1] == '*' ||
73 s[i + 1] == '%') {
+56,
-6
1@@ -3,6 +3,7 @@
2 #include "posix.h"
3 #include "gnu/pattern.h"
4
5+#include <glob.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9@@ -107,6 +108,45 @@ targetenv(struct GraphState *gs, struct EvalCtx *ctx, const struct Env *base, co
10 applytassigns(gs, ctx, name);
11 }
12
13+static int
14+hasglobmeta(const char *s)
15+{
16+ size_t i;
17+
18+ for (i = 0; s[i]; i++) {
19+ if (s[i] == '\\' && s[i + 1]) {
20+ i++;
21+ continue;
22+ }
23+ if (s[i] == '*' || s[i] == '?' || s[i] == '[')
24+ return 1;
25+ }
26+ return 0;
27+}
28+
29+static void
30+addglobword(struct StrList *out, const char *s)
31+{
32+ glob_t g;
33+ size_t i;
34+ int rc;
35+
36+ if (!hasglobmeta(s)) {
37+ addstr(out, s);
38+ return;
39+ }
40+
41+ memset(&g, 0, sizeof(g));
42+ rc = glob(s, 0, 0, &g);
43+ if (rc == 0 && g.gl_pathc > 0) {
44+ for (i = 0; i < g.gl_pathc; i++)
45+ addstr(out, g.gl_pathv[i]);
46+ } else {
47+ addstr(out, s);
48+ }
49+ globfree(&g);
50+}
51+
52 /* add an explicit target rule to the graph, and add all
53 * non-pattern prereqs also as placeholder nodes. later
54 * we discorver how to build them if they need to be built */
55@@ -117,8 +157,12 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
56 struct Target *t;
57 struct Env env;
58 struct EvalCtx ctx;
59+ struct StrList prereqs;
60+ struct StrList order_only;
61
62 memset(&ctx, 0, sizeof(ctx));
63+ memset(&prereqs, 0, sizeof(prereqs));
64+ memset(&order_only, 0, sizeof(order_only));
65 ctx.env = &env;
66
67 t = findtarget(gs->graph, name);
68@@ -134,25 +178,29 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
69 }
70 t->defined = 1;
71 t->dcolon = rule->dcolon;
72- addwords(&t->prereqs, &rule->prereqs);
73- addwords(&t->order_only, &rule->order_only);
74+ for (i = 0; i < rule->prereqs.n; i++)
75+ addglobword(&prereqs, rule->prereqs.v[i]);
76+ for (i = 0; i < rule->order_only.n; i++)
77+ addglobword(&order_only, rule->order_only.v[i]);
78+ addwords(&t->prereqs, &prereqs);
79+ addwords(&t->order_only, &order_only);
80 targetenv(gs, &ctx, t->env.n ? &t->env : 0, name);
81 addrecipes(&t->recipes, &rule->recipes);
82 freeenv(&t->env);
83 copyenv(&t->env, &env);
84
85- for (i = 0; i < rule->prereqs.n; i++) {
86+ for (i = 0; i < prereqs.n; i++) {
87 struct Env penv;
88 struct EvalCtx pctx;
89
90- if (strchr(rule->prereqs.v[i], '%'))
91+ if (strchr(prereqs.v[i], '%'))
92 continue;
93- t = findtarget(gs->graph, rule->prereqs.v[i]);
94+ t = findtarget(gs->graph, prereqs.v[i]);
95 if (!t) {
96 gs->graph->v = xrealloc(gs->graph->v, (gs->graph->n + 1) * sizeof(gs->graph->v[0]));
97 t = &gs->graph->v[gs->graph->n++];
98 memset(t, 0, sizeof(*t));
99- t->name = intern(rule->prereqs.v[i]);
100+ t->name = intern(prereqs.v[i]);
101 }
102 memset(&penv, 0, sizeof(penv));
103 memset(&pctx, 0, sizeof(pctx));
104@@ -162,6 +210,8 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
105 copyenv(&t->env, pctx.env);
106 freeenv(&penv);
107 }
108+ freestrs(&prereqs);
109+ freestrs(&order_only);
110 freeenv(&env);
111 }
112 static void