commit 90228d3
shrub
·
2026-04-08 10:37:48 +0000 UTC
parent c353699
dont emit a rule for every target and emit default and phony rules
1 files changed,
+168,
-7
+168,
-7
1@@ -7,17 +7,145 @@
2
3 /* ninja backend */
4
5+struct Rule {
6+ char *cmd;
7+ int id;
8+};
9+
10 static void
11-emitrule(FILE *fp, const struct Target *t, int id)
12+emitrule(FILE *fp, const char *cmd, int id)
13+{
14+ fprintf(fp, "rule r%d\n", id);
15+ fprintf(fp, " command = %s\n\n", cmd);
16+}
17+
18+static char *
19+joinprereqs(const struct Target *t)
20 {
21 size_t i;
22+ char *s;
23
24- fprintf(fp, "rule r%d\n", id);
25- fprintf(fp, " command =");
26+ s = xstrdup("");
27+ for (i = 0; i < t->prereqs.n; i++) {
28+ char *next;
29+
30+ next = s[0] ? cat3(s, " ", t->prereqs.v[i]) : xstrdup(t->prereqs.v[i]);
31+ free(s);
32+ s = next;
33+ }
34+ return s;
35+}
36+
37+static char *
38+joinrecipes(const struct Target *t)
39+{
40+ size_t i;
41+ char *s;
42+
43+ s = xstrdup("");
44 for (i = 0; i < t->recipes.n; i++) {
45- fprintf(fp, "%s %s", i == 0 ? "" : " &&", t->recipes.v[i]);
46+ char *next;
47+
48+ next = s[0] ? cat3(s, " && ", t->recipes.v[i]) : xstrdup(t->recipes.v[i]);
49+ free(s);
50+ s = next;
51+ }
52+ return s;
53+}
54+
55+static char *
56+replaceall(const char *s, const char *from, const char *to)
57+{
58+ size_t nfrom, nto, ns, count, i, j;
59+ char *out;
60+ const char *p;
61+
62+ if (!from || !from[0])
63+ return xstrdup(s);
64+ nfrom = strlen(from);
65+ nto = strlen(to);
66+ ns = strlen(s);
67+ count = 0;
68+ for (p = s; (p = strstr(p, from)) != 0; p += nfrom)
69+ count++;
70+ out = xmalloc(ns + count * (nto - nfrom) + 1);
71+ for (i = 0, j = 0; i < ns;) {
72+ if (i + nfrom <= ns && memcmp(s + i, from, nfrom) == 0) {
73+ memcpy(out + j, to, nto);
74+ j += nto;
75+ i += nfrom;
76+ continue;
77+ }
78+ out[j++] = s[i++];
79 }
80- fprintf(fp, "\n\n");
81+ out[j] = 0;
82+ return out;
83+}
84+
85+static char *
86+rulecmd(const struct Target *t)
87+{
88+ char *cmd, *deps, *tmp;
89+
90+ cmd = joinrecipes(t);
91+ if (!cmd[0])
92+ return cmd;
93+ tmp = replaceall(cmd, t->name, "$out");
94+ free(cmd);
95+ cmd = tmp;
96+ deps = joinprereqs(t);
97+ if (deps[0]) {
98+ tmp = replaceall(cmd, deps, "$in");
99+ free(cmd);
100+ cmd = tmp;
101+ if (t->prereqs.n == 1) {
102+ tmp = replaceall(cmd, t->prereqs.v[0], "$in");
103+ free(cmd);
104+ cmd = tmp;
105+ }
106+ }
107+ free(deps);
108+ return cmd;
109+}
110+
111+static int
112+findrule(struct Rule *rules, size_t n, const char *cmd)
113+{
114+ size_t i;
115+
116+ for (i = 0; i < n; i++) {
117+ if (strcmp(rules[i].cmd, cmd) == 0)
118+ return rules[i].id;
119+ }
120+ return 0;
121+}
122+
123+static const struct Target *
124+findtarget(const struct Graph *graph, const char *name)
125+{
126+ size_t i;
127+
128+ for (i = 0; i < graph->n; i++) {
129+ if (strcmp(graph->v[i].name, name) == 0)
130+ return &graph->v[i];
131+ }
132+ return 0;
133+}
134+
135+static const char *
136+defaulttarget(const struct Graph *graph)
137+{
138+ size_t i;
139+
140+ if (findtarget(graph, "all"))
141+ return "all";
142+ for (i = 0; i < graph->n; i++) {
143+ if (strcmp(graph->v[i].name, "clean") == 0 || strcmp(graph->v[i].name, "fmt") == 0)
144+ continue;
145+ if (graph->v[i].recipes.n > 0 || graph->v[i].prereqs.n > 0 || graph->v[i].order_only.n > 0)
146+ return graph->v[i].name;
147+ }
148+ return 0;
149 }
150
151 int
152@@ -26,16 +154,44 @@ genninja(const struct Graph *graph, const char *path)
153 FILE *fp;
154 size_t i, j;
155 int ruleid;
156+ struct Rule *rules;
157+ size_t nrules;
158
159 fp = fopen(path, "w");
160 if (!fp)
161 return -1;
162
163 ruleid = 0;
164+ rules = 0;
165+ nrules = 0;
166 for (i = 0; i < graph->n; i++) {
167 if (graph->v[i].recipes.n > 0) {
168- emitrule(fp, &graph->v[i], ++ruleid);
169- fprintf(fp, "build %s: r%d", graph->v[i].name, ruleid);
170+ char *cmd;
171+ int id;
172+
173+ cmd = rulecmd(&graph->v[i]);
174+ id = findrule(rules, nrules, cmd);
175+ if (!id) {
176+ id = ++ruleid;
177+ emitrule(fp, cmd, id);
178+ rules = xrealloc(rules, (nrules + 1) * sizeof(rules[0]));
179+ rules[nrules].cmd = cmd;
180+ rules[nrules].id = id;
181+ nrules++;
182+ } else {
183+ free(cmd);
184+ }
185+ fprintf(fp, "build %s: r%d", graph->v[i].name, id);
186+ for (j = 0; j < graph->v[i].prereqs.n; j++)
187+ fprintf(fp, " %s", graph->v[i].prereqs.v[j]);
188+ if (graph->v[i].order_only.n) {
189+ fprintf(fp, " ||");
190+ for (j = 0; j < graph->v[i].order_only.n; j++)
191+ fprintf(fp, " %s", graph->v[i].order_only.v[j]);
192+ }
193+ fprintf(fp, "\n\n");
194+ } else if (graph->v[i].prereqs.n > 0 || graph->v[i].order_only.n > 0) {
195+ fprintf(fp, "build %s: phony", graph->v[i].name);
196 for (j = 0; j < graph->v[i].prereqs.n; j++)
197 fprintf(fp, " %s", graph->v[i].prereqs.v[j]);
198 if (graph->v[i].order_only.n) {
199@@ -46,7 +202,12 @@ genninja(const struct Graph *graph, const char *path)
200 fprintf(fp, "\n\n");
201 }
202 }
203+ if (defaulttarget(graph))
204+ fprintf(fp, "default %s\n", defaulttarget(graph));
205
206 fclose(fp);
207+ for (i = 0; i < nrules; i++)
208+ free(rules[i].cmd);
209+ free(rules);
210 return 0;
211 }