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