commit 816afea
shrub
·
2026-04-09 10:56:55 +0000 UTC
parent 60073bc
simplify ninja backend (no rule dedup) and add suffix handling
2 files changed,
+100,
-65
+1,
-64
1@@ -19,23 +19,6 @@ emitrule(FILE *fp, const char *cmd, int id)
2 fprintf(fp, " command = %s\n\n", cmd);
3 }
4
5-static char *
6-joinprereqs(const struct Target *t)
7-{
8- size_t i;
9- char *s;
10-
11- s = xstrdup("");
12- for (i = 0; i < t->prereqs.n; i++) {
13- char *next;
14-
15- next = s[0] ? cat3(s, " ", t->prereqs.v[i]) : xstrdup(t->prereqs.v[i]);
16- free(s);
17- s = next;
18- }
19- return s;
20-}
21-
22 static char *
23 joinrecipes(const struct Target *t)
24 {
25@@ -53,58 +36,12 @@ joinrecipes(const struct Target *t)
26 return s;
27 }
28
29-static char *
30-replaceall(const char *s, const char *from, const char *to)
31-{
32- size_t nfrom, nto, ns, count, i, j;
33- char *out;
34- const char *p;
35-
36- if (!from || !from[0])
37- return xstrdup(s);
38- nfrom = strlen(from);
39- nto = strlen(to);
40- ns = strlen(s);
41- count = 0;
42- for (p = s; (p = strstr(p, from)) != 0; p += nfrom)
43- count++;
44- out = xmalloc(ns + count * (nto - nfrom) + 1);
45- for (i = 0, j = 0; i < ns;) {
46- if (i + nfrom <= ns && memcmp(s + i, from, nfrom) == 0) {
47- memcpy(out + j, to, nto);
48- j += nto;
49- i += nfrom;
50- continue;
51- }
52- out[j++] = s[i++];
53- }
54- out[j] = 0;
55- return out;
56-}
57-
58 static char *
59 rulecmd(const struct Target *t)
60 {
61- char *cmd, *deps, *tmp;
62+ char *cmd;
63
64 cmd = joinrecipes(t);
65- if (!cmd[0])
66- return cmd;
67- tmp = replaceall(cmd, t->name, "$out");
68- free(cmd);
69- cmd = tmp;
70- deps = joinprereqs(t);
71- if (deps[0]) {
72- tmp = replaceall(cmd, deps, "$in");
73- free(cmd);
74- cmd = tmp;
75- if (t->prereqs.n == 1) {
76- tmp = replaceall(cmd, t->prereqs.v[0], "$in");
77- free(cmd);
78- cmd = tmp;
79- }
80- }
81- free(deps);
82 return cmd;
83 }
84
+99,
-1
1@@ -47,6 +47,12 @@ struct Pattern {
2 struct RecipeList recipes;
3 };
4
5+struct Suffix {
6+ char *from;
7+ char *to;
8+ struct RecipeList recipes;
9+};
10+
11 struct TAssign {
12 struct StrList targets;
13 char *lhs;
14@@ -61,6 +67,8 @@ struct GraphState {
15 size_t nrules;
16 struct Pattern *pats;
17 size_t npats;
18+ struct Suffix *sufs;
19+ size_t nsufs;
20 struct TAssign *tas;
21 size_t ntas;
22 };
23@@ -95,6 +103,19 @@ matchpat(const char *pat, const char *name)
24 return xstrndup(name + pre, n - pre - suf);
25 }
26
27+static int
28+matchsuf(const char *suf, const char *name, char **stem)
29+{
30+ size_t nsuf, nname;
31+
32+ nsuf = strlen(suf);
33+ nname = strlen(name);
34+ if (nname < nsuf || strcmp(name + nname - nsuf, suf) != 0)
35+ return 0;
36+ *stem = xstrndup(name, nname - nsuf);
37+ return 1;
38+}
39+
40 static int
41 targetmatches(const char *pat, const char *name)
42 {
43@@ -131,6 +152,21 @@ applystem(const char *s, const char *stem)
44 return out;
45 }
46
47+static int
48+issuffix(const char *s, char **from, char **to)
49+{
50+ const char *mid;
51+
52+ if (!s || s[0] != '.')
53+ return 0;
54+ mid = strchr(s + 1, '.');
55+ if (!mid || mid == s + 1 || !mid[1] || strchr(mid + 1, '.'))
56+ return 0;
57+ *from = xstrndup(s, (size_t)(mid - s));
58+ *to = xstrdup(mid);
59+ return 1;
60+}
61+
62 static char *
63 joinprereqs(const struct Target *t)
64 {
65@@ -322,6 +358,29 @@ addpattern(struct GraphState *gs, const struct RuleNode *rule)
66 }
67 }
68
69+static void
70+addsuffix(struct GraphState *gs, const struct RuleNode *rule)
71+{
72+ char *from, *to;
73+ struct Suffix *sr;
74+
75+ if (rule->targets.n != 1 || rule->prereqs.n != 0 || rule->order_only.n != 0)
76+ {
77+ addpattern(gs, rule);
78+ return;
79+ }
80+ if (!issuffix(rule->targets.v[0], &from, &to)) {
81+ addpattern(gs, rule);
82+ return;
83+ }
84+ gs->sufs = xrealloc(gs->sufs, (gs->nsufs + 1) * sizeof(gs->sufs[0]));
85+ sr = &gs->sufs[gs->nsufs++];
86+ memset(sr, 0, sizeof(*sr));
87+ sr->from = from;
88+ sr->to = to;
89+ addrecipes(&sr->recipes, &rule->recipes);
90+}
91+
92 static void
93 addtassign(struct GraphState *gs, const struct AssignNode *assign)
94 {
95@@ -367,6 +426,37 @@ instantiate(struct GraphState *gs, struct Target *t, struct Pattern *p, const ch
96 freeenv(&env);
97 }
98
99+static int
100+instantiatesuffix(struct GraphState *gs, struct Target *t)
101+{
102+ size_t i, k;
103+
104+ for (i = 0; i < gs->nsufs; i++) {
105+ char *stem, *src;
106+ struct Env env;
107+
108+ if (!matchsuf(gs->sufs[i].to, t->name, &stem))
109+ continue;
110+ src = cat3(stem, "", gs->sufs[i].from);
111+ t->prereqs.v = xrealloc(t->prereqs.v, (t->prereqs.n + 1) * sizeof(t->prereqs.v[0]));
112+ t->prereqs.v[t->prereqs.n++] = src;
113+ targetenv(gs, &env, t->name);
114+ for (k = 0; k < gs->sufs[i].recipes.n; k++) {
115+ char *vars, *exp;
116+
117+ vars = expandstr(&env, gs->sufs[i].recipes.v[k]);
118+ exp = expandauto(vars, t, stem);
119+ free(vars);
120+ t->recipes.v = xrealloc(t->recipes.v, (t->recipes.n + 1) * sizeof(t->recipes.v[0]));
121+ t->recipes.v[t->recipes.n++] = exp;
122+ }
123+ freeenv(&env);
124+ free(stem);
125+ return 1;
126+ }
127+ return 0;
128+}
129+
130 int
131 buildgraph(const struct Ast *ast, struct Graph *graph)
132 {
133@@ -390,7 +480,7 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
134 }
135
136 for (i = 0; i < gs.nrules; i++)
137- addpattern(&gs, gs.rules[i]);
138+ addsuffix(&gs, gs.rules[i]);
139
140 start = 0;
141 while (start < graph->n) {
142@@ -406,6 +496,8 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
143 break;
144 }
145 }
146+ if (t->recipes.n == 0)
147+ instantiatesuffix(&gs, t);
148 }
149 for (j = 0; j < t->prereqs.n; j++) {
150 if (!findtarget(graph, t->prereqs.v[j])) {
151@@ -438,6 +530,11 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
152 freestrs(&gs.pats[i].order_only);
153 freerecipes(&gs.pats[i].recipes);
154 }
155+ for (i = 0; i < gs.nsufs; i++) {
156+ free(gs.sufs[i].from);
157+ free(gs.sufs[i].to);
158+ freerecipes(&gs.sufs[i].recipes);
159+ }
160 for (i = 0; i < gs.ntas; i++) {
161 freestrs(&gs.tas[i].targets);
162 free(gs.tas[i].lhs);
163@@ -445,6 +542,7 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
164 }
165 free(gs.tas);
166 free(gs.pats);
167+ free(gs.sufs);
168 free(gs.rules);
169 freeenv(&gs.env);
170