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 }