commit 59a6db8
shrub
·
2026-04-08 17:31:17 +0000 UTC
parent 757e0ed
feat: handle $< $^ $+ 127
2 files changed,
+61,
-50
+0,
-35
1@@ -1,35 +0,0 @@
2-build all: phony shin
3-
4-rule r1
5- command = clang -static -o $out $in
6-
7-build shin: r1 cli/main.o src/parse.o src/eval.o src/graph.o backends/ninja.o src/util.o src/functions.o
8-
9-rule r2
10- command = clang -O2 -Wall -Wextra -pedantic -Isrc -Ibackends -c -o $out $in
11-
12-build cli/main.o: r2 cli/main.c
13-
14-build src/parse.o: r2 src/parse.c
15-
16-build src/eval.o: r2 src/eval.c
17-
18-build src/graph.o: r2 src/graph.c
19-
20-build backends/ninja.o: r2 backends/ninja.c
21-
22-build src/util.o: r2 src/util.c
23-
24-build src/functions.o: r2 src/functions.c
25-
26-rule r3
27- command = clang-format -i cli/main.c src/parse.c src/eval.c src/graph.c backends/ninja.c src/util.c src/functions.c src/shinobi.h src/internal.h backends/ninja.h
28-
29-build fmt: r3
30-
31-rule r4
32- command = rm -f shin cli/main.o src/parse.o src/eval.o src/graph.o backends/ninja.o src/util.o src/functions.o
33-
34-build clean: r4
35-
36-default all
+61,
-15
1@@ -148,7 +148,32 @@ applystem(const char *s, const char *stem)
2 }
3
4 static char *
5-expandauto(const char *s, const struct Target *t)
6+joinprereqs(const struct Target *t)
7+{
8+ size_t k;
9+ char *joined, *next;
10+
11+ joined = xstrdup("");
12+ for (k = 0; k < t->prereqs.n; k++) {
13+ next = joined[0] ? cat3(joined, " ", t->prereqs.v[k]) : xstrdup(t->prereqs.v[k]);
14+ free(joined);
15+ joined = next;
16+ }
17+ return joined;
18+}
19+
20+/*
21+ * expand gnu make automatic variables
22+ * $@ target
23+ * $< first prereq
24+ * $^ all prereqs
25+ * $+ all prereqs
26+ * $? all prereqs, let ninja decide
27+ * $* stem
28+ * $$ literal $
29+ */
30+static char *
31+expandauto(const char *s, const struct Target *t, const char *stem)
32 {
33 size_t i, n, cap, len;
34 char *out;
35@@ -159,36 +184,46 @@ expandauto(const char *s, const struct Target *t)
36 out = xmalloc(cap);
37 for (i = 0; i < n; i++) {
38 if (s[i] == '$' && i + 1 < n) {
39- char *val = 0;
40- int mustfree = 0;
41+ const char *val;
42+ int mustfree;
43
44+ val = 0;
45+ mustfree = 0;
46+
47+ if (s[i + 1] == '$') {
48+ if (len + 3 > cap) {
49+ cap = len + 3 + (n - i);
50+ out = xrealloc(out, cap);
51+ }
52+ out[len++] = '$';
53+ out[len++] = '$';
54+ i++;
55+ continue;
56+ }
57 if (s[i + 1] == '@') {
58 val = t->name;
59 } else if (s[i + 1] == '<') {
60 if (t->prereqs.n > 0)
61 val = t->prereqs.v[0];
62- } else if (s[i + 1] == '^') {
63- size_t k;
64- char *joined = xstrdup("");
65- for (k = 0; k < t->prereqs.n; k++) {
66- char *next = joined[0] ? cat3(joined, " ", t->prereqs.v[k]) : xstrdup(t->prereqs.v[k]);
67- free(joined);
68- joined = next;
69- }
70- val = joined;
71+ else
72+ val = "";
73+ } else if (s[i + 1] == '^' || s[i + 1] == '+' || s[i + 1] == '?') {
74+ val = joinprereqs(t);
75 mustfree = 1;
76+ } else if (s[i + 1] == '*') {
77+ val = stem ? stem : "";
78 }
79
80 if (val) {
81 size_t vlen = strlen(val);
82 if (len + vlen + 1 > cap) {
83- cap = len + vlen + n - i + 1;
84+ cap = len + vlen + (n - i) + 1;
85 out = xrealloc(out, cap);
86 }
87 memcpy(out + len, val, vlen);
88 len += vlen;
89 if (mustfree)
90- free(val);
91+ free((char *)val);
92 i++;
93 continue;
94 }
95@@ -220,7 +255,7 @@ instantiate(struct Target *t, struct Pattern *p, const char *stem)
96 }
97 for (i = 0; i < p->recipes.n; i++) {
98 char *s = applystem(p->recipes.v[i], stem);
99- char *exp = expandauto(s, t);
100+ char *exp = expandauto(s, t, stem);
101 free(s);
102 t->recipes.v = xrealloc(t->recipes.v, (t->recipes.n + 1) * sizeof(t->recipes.v[0]));
103 t->recipes.v[t->recipes.n++] = exp;
104@@ -269,6 +304,17 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
105 start = current_n;
106 }
107
108+ for (i = 0; i < graph->n; i++) {
109+ struct Target *t = &graph->v[i];
110+ size_t k;
111+
112+ for (k = 0; k < t->recipes.n; k++) {
113+ char *exp = expandauto(t->recipes.v[k], t, 0);
114+ free(t->recipes.v[k]);
115+ t->recipes.v[k] = exp;
116+ }
117+ }
118+
119 for (i = 0; i < gs.npats; i++) {
120 free(gs.pats[i].target);
121 freestrs(&gs.pats[i].prereqs);