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