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