rules.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
rules.c (9610B)
---
1 #include <signal.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "make.h"
7
8 #define TABSIZ 128
9 #define FORCE 1
10 #define NOFORCE 0
11
12 static Target *htab[TABSIZ], *deftarget;
13
14 void
15 dumprules(void)
16 {
17 int i;
18 Target **pp, **q, *p;
19
20 for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
21 for (p = *pp; p; p = p->next) {
22 if (!p->defined)
23 continue;
24 printf("%s:", p->name);
25 for (q = p->deps; q && *q; ++q)
26 printf(" %s", (*q)->name);
27 putchar('\n');
28 for (i = 0; i < p->nactions; i++)
29 printf("\t%s\n", p->actions[i].line);
30 putchar('\n');
31 }
32 }
33 }
34
35 static Target *
36 lookup(char *name)
37 {
38 Target *tp;
39 int h = hash(name) & TABSIZ-1;
40
41 for (tp = htab[h]; tp && strcmp(tp->name, name); tp = tp->next)
42 ;
43
44 if (tp)
45 return tp;
46
47 tp = emalloc(sizeof(*tp));
48 tp->name = estrdup(name);
49 tp->target = tp->name;
50 tp->req = NULL;
51 tp->ndeps = 0;
52 tp->deps = NULL;
53 tp->actions = NULL;
54 tp->nactions = 0;
55 tp->next = htab[h];
56 tp->defined = 0;
57 htab[h] = tp;
58
59 return tp;
60 }
61
62 static void
63 cleanup(Target *tp)
64 {
65 int precious;
66 Target *p, **q;
67
68 printf("make: signal %d arrived\n", stop);
69
70 precious = 0;
71 p = lookup(".PRECIOUS");
72 for (q = p->deps; q && *q; q++) {
73 if (strcmp((*q)->name, tp->name) == 0) {
74 precious = 1;
75 break;
76 }
77 }
78
79 if (!precious && !nflag && !qflag && !is_dir(tp->name)) {
80 printf("make: trying to remove target %s\n", tp->name);
81 remove(tp->name);
82 }
83
84 signal(stop, SIG_DFL);
85 raise(stop);
86 }
87
88 static int
89 depends(char *target, char *dep)
90 {
91 int i;
92 Target **p, *tp = lookup(target);
93
94 for (p = tp->deps; p && *p; ++p) {
95 if (strcmp((*p)->name, target) == 0)
96 return 1;
97 }
98
99 return 0;
100 }
101
102 static int
103 is_suffix(char *s)
104 {
105 int n;
106
107 if (s[0] != '.')
108 return 0;
109
110 for (n = 0; s = strchr(s, '.'); n++)
111 s++;
112
113 return n == 2;
114 }
115
116 void
117 addtarget(char *target, int ndeps)
118 {
119 Target *tp = lookup(target);
120
121 tp->defined = 1;
122 if (!deftarget && target[0] != '.') {
123 deftarget = tp;
124 return;
125 }
126
127 if (strcmp(target, ".SUFFIXES") == 0 && ndeps == 0) {
128 free(tp->deps);
129 tp->deps = NULL;
130 tp->ndeps = 0;
131 return;
132 }
133
134 if (strcmp(target, ".DEFAULT") == 0) {
135 if (ndeps > 0)
136 error("DEFAULT rule with prerequisites");
137 return;
138 }
139
140 if (strcmp(target, ".SILENT") == 0 && ndeps == 0) {
141 sflag = 1;
142 return;
143 }
144
145 if (strcmp(target, ".IGNORE") == 0 && ndeps == 0) {
146 iflag = 1;
147 return;
148 }
149 }
150
151 void
152 adddep(char *target, char *dep)
153 {
154 int i;
155 size_t siz;
156 Target **p, *tp = lookup(target);
157
158 if (depends(dep, target)) {
159 warning("circular dependency %s <- %s dropped", target, dep);
160 return;
161 }
162
163 for (p = tp->deps; p && *p; ++p) {
164 if (strcmp((*p)->name, dep) == 0)
165 return;
166 }
167
168 tp->ndeps++;
169 siz = (tp->ndeps + 1) * sizeof(Target *);
170 tp->deps = erealloc(tp->deps, siz);
171 tp->deps[tp->ndeps-1] = lookup(dep);
172 tp->deps[tp->ndeps] = NULL;
173
174 debug("adding dependency %s <- %s", target, dep);
175 }
176
177 static void
178 freeaction(struct action *act)
179 {
180 free(act->line);
181 freeloc(&act->loc);
182 }
183
184 void
185 addrule(char *target, struct action *acts, int n)
186 {
187 int i;
188 struct action *v;
189 Target *tp = lookup(target);
190
191 debug("adding actions for target %s", target);
192
193 if (tp->actions) {
194 debug("overring actions of target %s", target);
195 for (i = 0; i < tp->nactions; i++)
196 freeaction(&tp->actions[i]);
197 free(tp->actions);
198 }
199
200 v = emalloc(n * sizeof(*v));
201 for (i = 0; i < n; i++) {
202 v[i].line = estrdup(acts[i].line);
203 v[i].loc.lineno = acts[i].loc.lineno;
204 v[i].loc.fname = estrdup(acts[i].loc.fname);
205 }
206
207 tp->nactions = n;
208 tp->actions = v;
209 }
210
211 static int
212 execline(Target *tp, char *line, int ignore, int silence)
213 {
214 char *s, *t;
215 Target *p, **q;
216 int r, at, plus, minus, l;
217
218 debug("executing '%s'", line);
219
220 at = plus = minus = 0;
221 for (s = line; ; s++) {
222 switch (*s) {
223 case '@':
224 at = 1;
225 break;
226 case '-':
227 minus = 1;
228 break;
229 case '+':
230 plus = 1;
231 break;
232 default:
233 goto out_loop;
234 }
235 }
236
237 out_loop:
238 /* unescape $$ */
239 for (l = strlen(s)+1, t = s; *t; --l, ++t) {
240 if (t[0] == '$' && t[1] == '$') {
241 memmove(t+1, t+2, l-2);
242 l--;
243 }
244 }
245
246 if (tflag && !plus)
247 return 0;
248
249 if (sflag || silence || (qflag && !plus))
250 at = 1;
251 if (nflag)
252 at = 0;
253 if (!at) {
254 puts(s);
255 fflush(stdout);
256 }
257
258 if ((nflag || qflag) && !plus) {
259 if (qflag)
260 exitstatus = 1;
261 return 0;
262 }
263
264 if (minus || iflag || ignore)
265 ignore = 1;
266
267 r = launch(s, ignore);
268 if (ignore)
269 return 0;
270
271 return r;
272 }
273
274 static int
275 touch(char *name, int ignore, int silence)
276 {
277 char *cmd;
278 int r, n;
279
280 n = snprintf(NULL, 0, "touch %s", name) + 1;
281 cmd = emalloc(n);
282 snprintf(cmd, n, "touch %s", name);
283
284 if (!sflag && !silence)
285 puts(cmd);
286
287 r = system(cmd);
288 free(cmd);
289
290 if (ignore || iflag)
291 return 0;
292
293 return r;
294 }
295
296 static int
297 touchdeps(Target *tp, int ignore, int silent)
298 {
299 int r;
300 Target **p;
301
302 if (tp->req) {
303 r = touch(tp->req, silent, ignore);
304 if (r)
305 return r;
306 }
307
308 for (p = tp->deps; p && *p; ++p) {
309 r = touch((*p)->name, silent, ignore);
310 if (r)
311 return r;
312 }
313
314 return 0;
315 }
316
317 static int
318 run(Target *tp)
319 {
320 int r, i, ignore, silent;
321 char *s;
322 Target *p, **q;
323
324 silent = 0;
325 p = lookup(".SILENT");
326 for (q = p->deps; q && *q; ++q) {
327 if (strcmp((*q)->name, tp->name) == 0) {
328 debug("target %s error silent by .SILENT", tp->name);
329 silent = 1;
330 }
331 }
332
333 ignore = 0;
334 p = lookup(".IGNORE");
335 for (q = p->deps; q && *q; ++q) {
336 if (strcmp((*q)->name, tp->name) == 0) {
337 debug("target %s error ignored by .IGNORE", tp->name);
338 ignore = 1;
339 }
340 }
341
342 if (tflag) {
343 r = touchdeps(tp, ignore, silent);
344 if (r)
345 return r;
346 }
347
348 for (i = 0; i < tp->nactions; i++) {
349 struct action *p;
350
351 if (stop)
352 cleanup(tp);
353
354 p = &tp->actions[i];
355 debug("executing action '%s'", p->line);
356 s = expandstring(p->line, tp, &p->loc);
357 r = execline(tp, s, ignore, silent);
358 free(s);
359
360 if (r)
361 return r;
362 }
363
364 if (tflag) {
365 r = touch(tp->target, ignore, silent);
366 if (r)
367 return r;
368 }
369
370 return 0;
371 }
372
373 static int
374 enabled(char *suffix)
375 {
376 Target **p, *tp = lookup(".SUFFIXES");
377
378 for (p = tp->deps; p && *p; ++p) {
379 if (strcmp(suffix, (*p)->name) == 0)
380 return 1;
381 }
382
383 return 0;
384 }
385
386 static Target *
387 inference(Target *tp, int force)
388 {
389 time_t t;
390 int tolen, r;
391 char *to, *from;
392 Target *q, **p, *suffixes;
393 char buf[FILENAME_MAX], fname[FILENAME_MAX];
394
395 debug("searching an inference rule for %s", tp->name);
396
397 to = strrchr(tp->name, '.');
398 if (to && !enabled(to))
399 return NULL;
400 tolen = to ? to - tp->name : strlen(tp->name);
401
402 if (!to)
403 to = "";
404
405 suffixes = lookup(".SUFFIXES");
406 for (p = suffixes->deps; p && *p; ++p) {
407 from = (*p)->name;
408 debug("trying suffix %s", from);
409
410 r = snprintf(buf,
411 sizeof(buf),
412 "%s%s",
413 from, to);
414
415 if (r < 0 || r >= sizeof(buf))
416 error("suffixes too long %s %s", from, to);
417
418 q = lookup(buf);
419 if (!q->actions)
420 continue;
421
422 r = snprintf(fname,
423 sizeof(fname),
424 "%*.*s%s",
425 tolen, tolen, tp->name, from);
426
427 if (r < 0 || r >= sizeof(fname)) {
428 error("prerequisite name too long %s %s",
429 tp->name, from);
430 }
431
432 debug("\tsearching prerequisite %s", fname);
433
434 t = stamp(fname);
435 if (t == -1) {
436 debug("\tprerequisite %s not found", fname);
437 continue;
438 }
439
440 if (!force && t <= tp->stamp) {
441 debug("\tdiscarded because is newer");
442 debug("\t%s: %s", tp->name, ctime(&tp->stamp));
443 debug("\t%s: %s", fname, ctime(&t));
444 continue;
445 }
446
447 free(q->req);
448 q->req = estrdup(fname);
449 q->deps = tp->deps;
450 q->target = tp->name;
451 q->stamp = tp->stamp;
452
453 debug("using inference rule %s with %s", q->name, fname);
454 return q;
455 }
456
457 return NULL;
458 }
459
460 static int
461 update(Target *tp)
462 {
463 Target *p;
464
465 debug("%s needs to be updated", tp->name);
466
467 if (tp->actions) {
468 debug("using target rule to build %s", tp->name);
469 return run(tp);
470 }
471
472 if ((p = inference(tp, FORCE)) != NULL) {
473 debug("using inference rule %s", p->name);
474 return run(p);
475 }
476
477 p = lookup(".DEFAULT");
478 if (p->defined) {
479 debug("using default rule");
480 return run(p);
481 }
482
483 debug("not rule found to update %s", tp->name);
484
485 if (!tp->defined)
486 error("don't know how to make %s", tp->name);
487
488 return 0;
489 }
490
491 static int
492 rebuild(Target *tp, int *buildp)
493 {
494 Target **p, *q;;
495 int r, need, build, err, def;
496
497 debug("checking rebuild of %s", tp->name);
498
499 tp->stamp = stamp(tp->name);
500
501 def = err = need = 0;
502 for (p = tp->deps; p && *p; ++p) {
503 if (stop)
504 cleanup(tp);
505
506 q = *p;
507 debug("checking dependency %s", q->name);
508
509 if (strcmp(q->name, tp->name) == 0 && q->actions)
510 def = 1;
511
512 build = 0;
513 if (rebuild(q, &build) != 0) {
514 err = 1;
515 continue;
516 }
517
518 if (build) {
519 debug("rebuild of %s forces rebuild of %s",
520 q->name, tp->name);
521 need = 1;
522 } else if (q->stamp > tp->stamp) {
523 debug("dependency %s is newer than %s",
524 q->name, tp->name);
525 need = 1;
526 }
527 }
528
529 if (tp->stamp == -1) {
530 need = 1;
531 } else if (!def) {
532 debug("no action found for %s, looking a inference rule",
533 tp->name);
534 if (inference(tp, NOFORCE))
535 need = 1;
536 }
537
538 if (err) {
539 warning("target %s not remade because of errors", tp->name);
540 return 1;
541 } else if (need) {
542 *buildp = 1;
543
544 debug("target %s needs updating", tp->name);
545 r = update(tp);
546 if (r == 0)
547 return 0;
548
549 if (stop)
550 cleanup(tp);
551
552 exitstatus = 1;
553
554 if (!kflag)
555 error("target %s: error %d", tp->name, r);
556 else
557 warning("target %s: error %d", tp->name, r);
558 return r;
559 }
560
561 return 0;
562 }
563
564 int
565 build(char *name)
566 {
567 int build, r;
568
569 if (!name) {
570 if (!deftarget) {
571 printf("make: no target to make\n");
572 return 0;
573 }
574 name = deftarget->name;
575 }
576
577 debug("checking target %s", name);
578
579 build = 0;
580 return rebuild(lookup(name), &build);
581 }