kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

build.c (12761B)


      1 /*
      2  * The build engine: bring a target up to date by running its recipe through
      3  * the injected shell. Ported from pdpmake make.c. Recipe execution goes through
      4  * host->exec (pdpmake used system()), touch through host->touch, and
      5  * failed-target removal through host->remove_file. Part of the src/api/make.c
      6  * amalgamation.
      7  *
      8  * host->exec reports the child result in *exit_status: >= 0 is the exit code,
      9  * < 0 is the negated terminating signal number; the call itself returns 0 when
     10  * the child ran and was reaped, non-zero when the shell could not be spawned.
     11  */
     12 #include "make.h"
     13 
     14 static void mk_remove_target(MakeCtx* mc) {
     15   if (!dryrun && !print && !precious && mc->target &&
     16       !(mc->target->n_flag & (N_PRECIOUS | N_PHONY)) &&
     17       mc->host->remove_file(mc->host->user, mk_path(mc, mc->target->n_name)) ==
     18           0) {
     19     mk_diagnostic(mc, "'%s' removed", mc->target->n_name);
     20   }
     21 }
     22 
     23 /*
     24  * Update the modification time of a file to now (create it if absent).
     25  */
     26 static void mk_do_touch(MakeCtx* mc, struct name* np) {
     27   if (dryrun || !silent) mk_outf(mc, "touch %s\n", np->n_name);
     28 
     29   if (!dryrun) {
     30     if (mc->host->touch(mc->host->user, mk_path(mc, np->n_name)) != 0)
     31       mk_warning(mc, "touch %s failed", np->n_name);
     32   }
     33 }
     34 
     35 /*
     36  * Do commands to make a target.
     37  */
     38 static int mk_docmds(MakeCtx* mc, struct name* np, struct cmd* cp) {
     39   int estat = 0;
     40   char* q;
     41   char* command;
     42 
     43   for (; cp; cp = cp->c_next) {
     44     uint32_t ssilent, signore, sdomake;
     45 
     46     /* Location of command in makefile (for error messages). */
     47     mc->curr_cmd = cp;
     48     mc->opts &= ~OPT_make; /* We want to know if $(MAKE) is expanded. */
     49     q = command = mk_expand_macros(mc, cp->c_cmd, FALSE);
     50     ssilent = silent || (np->n_flag & N_SILENT) || dotouch;
     51     signore = ignore || (np->n_flag & N_IGNORE);
     52     sdomake = (!dryrun || doinclude || domake) && !dotouch;
     53     for (;;) {
     54       if (*q == '@') /* specific silent */
     55         ssilent = TRUE + 1;
     56       else if (*q == '-') /* specific ignore */
     57         signore = TRUE;
     58       else if (*q == '+') /* specific domake */
     59         sdomake = TRUE + 1;
     60       else
     61         break;
     62       do {
     63         q++;
     64       } while (isblank((unsigned char)*q));
     65     }
     66 
     67     if (sdomake > TRUE) {
     68       /* '+' must not override '@' or .SILENT */
     69       if (ssilent != TRUE + 1 && !(np->n_flag & N_SILENT)) ssilent = FALSE;
     70     } else if (!sdomake)
     71       ssilent = dotouch;
     72 
     73     if (!ssilent && *q != '\0') { /* Ignore empty commands. */
     74       mk_out(mc, q);
     75       mk_outc(mc, '\n');
     76     }
     77 
     78     if (quest && sdomake != TRUE + 1) {
     79       /* MAKE_FAILURE means rebuild is needed. */
     80       estat |= MAKE_FAILURE | MAKE_DIDSOMETHING;
     81       continue;
     82     }
     83 
     84     if (sdomake && *q != '\0') { /* Ignore empty commands. */
     85       int status = 0;
     86       int spawned;
     87       char* cmd = (!signore && mc->posix) ? mk_concat3(mc, "set -e;", q, "") : q;
     88       const KitExec* ex = mc->host->exec;
     89       KitExecProc* proc = NULL;
     90       KitSlice av[3];
     91       KitExecOpts eo;
     92 
     93       av[0] = kit_slice_cstr(mc->shell);
     94       av[1] = KIT_SLICE_LIT("-c");
     95       av[2] = kit_slice_cstr(cmd);
     96       memset(&eo, 0, sizeof eo);
     97       eo.argv = av;
     98       eo.argc = 3;
     99       eo.env = mc->env;
    100       eo.nenv = mc->nenv;
    101       eo.cwd = mc->root ? kit_slice_cstr(mc->root) : KIT_SLICE_NULL;
    102       eo.search_path = 1;
    103       mc->target = np;
    104       spawned = ex->spawn(ex->user, &eo, &proc);
    105       if (spawned == 0) spawned = ex->wait(ex->user, proc, &status, NULL, NULL);
    106       /* If this command was being run to create/refresh an include file,
    107        * errors are ignored and a failure status returned. */
    108       if (spawned != 0) {
    109         if (!doinclude)
    110           mk_error(mc, "couldn't execute '%s'", q);
    111         else
    112           mk_warning(mc, "failed to build '%s'", np->n_name);
    113       } else if (status != 0 && !signore) {
    114         int signaled = status < 0;
    115         int err_value = signaled ? -status : status;
    116         const char* err_type = signaled ? "signal" : "exit";
    117 
    118         if (!mc->posix && signaled) mk_remove_target(mc);
    119         if (doinclude) {
    120           mk_warning(mc, "failed to build '%s'", np->n_name);
    121         } else {
    122           if (!quest || err_value == 127)
    123             mk_diagnostic(mc, "failed to build '%s' %s %d", np->n_name, err_type,
    124                           err_value);
    125           if (errcont) {
    126             estat |= MAKE_FAILURE;
    127             mc->target = NULL;
    128             break;
    129           }
    130           mk_exit(mc, 2);
    131         }
    132       }
    133       mc->target = NULL;
    134     }
    135     if (sdomake || dryrun) estat = MAKE_DIDSOMETHING;
    136   }
    137 
    138   if (dotouch && !(np->n_flag & N_PHONY) && !(estat & MAKE_DIDSOMETHING)) {
    139     mk_do_touch(mc, np);
    140     estat = MAKE_DIDSOMETHING;
    141   }
    142 
    143   mc->curr_cmd = NULL;
    144   return estat;
    145 }
    146 
    147 /*
    148  * Remove the suffix from a name, either the one in 'tsuff' or, if NULL, one of
    149  * the known suffixes.
    150  */
    151 static char* mk_remove_suffix(MakeCtx* mc, const char* name, const char* tsuff) {
    152   char* base = NULL;
    153 
    154   if (tsuff != NULL) {
    155     base = mk_has_suffix(mc, name, tsuff);
    156   } else {
    157     struct name* xp = mk_newname(mc, ".SUFFIXES");
    158     for (struct rule* rp = xp->n_rule; rp; rp = rp->r_next) {
    159       for (struct depend* dp = rp->r_dep; dp; dp = dp->d_next) {
    160         base = mk_has_suffix(mc, name, dp->d_name->n_name);
    161         if (base) return base;
    162       }
    163     }
    164   }
    165   return base;
    166 }
    167 
    168 static int mk_make1(MakeCtx* mc, struct name* np, struct cmd* cp, char* oodate,
    169                     char* allsrc, char* dedup, struct name* implicit,
    170                     const char* tsuff) {
    171   char* name;
    172   char* member = NULL;
    173   char* base = NULL;
    174   char* prereq = NULL;
    175 
    176   name = mk_splitlib(mc, np->n_name, &member);
    177   mk_setmacro(mc, "?", oodate, 0 | M_VALID);
    178   if (!POSIX_2017) {
    179     mk_setmacro(mc, "+", allsrc, 0 | M_VALID);
    180     mk_setmacro(mc, "^", dedup, 0 | M_VALID);
    181   }
    182   mk_setmacro(mc, "%", member, 0 | M_VALID);
    183   mk_setmacro(mc, "@", name, 0 | M_VALID);
    184   if (implicit || !mc->posix) {
    185     char* s;
    186 
    187     /* As an extension, if we're not dealing with an implicit prerequisite set
    188      * $< to the first out-of-date prerequisite. */
    189     if (implicit == NULL) {
    190       if (oodate) {
    191         s = strchr(oodate, ' ');
    192         if (s) *s = '\0';
    193         prereq = oodate;
    194       }
    195     } else
    196       prereq = implicit->n_name;
    197 
    198     if (!mc->posix && member == NULL) {
    199       /* Remove a suffix (not necessarily period-led) from a target, but not for
    200        * lib.a(member.o) targets. */
    201       base = mk_remove_suffix(mc, name, tsuff);
    202       if (base) {
    203         name = base;
    204       }
    205     } else {
    206       base = member ? member : name;
    207       s = mk_suffix(base);
    208       /* If not implicit and the target ends with a known suffix, set $* to the
    209        * stem, else to an empty string. */
    210       if (implicit == NULL && !mk_is_suffix(mc, s))
    211         base = NULL;
    212       else
    213         *s = '\0';
    214     }
    215   }
    216   mk_setmacro(mc, "<", prereq, 0 | M_VALID);
    217   mk_setmacro(mc, "*", base, 0 | M_VALID);
    218 
    219   return mk_docmds(mc, np, cp);
    220 }
    221 
    222 /*
    223  * Determine if the mtime of target t is <= that of prerequisite p. If tv_nsec
    224  * of either is 0 assume 1-second resolution and compare only tv_sec.
    225  */
    226 static int mk_timespec_le(const struct mk_timespec* t,
    227                           const struct mk_timespec* p) {
    228   if (t->tv_nsec == 0 || p->tv_nsec == 0)
    229     return t->tv_sec <= p->tv_sec;
    230   else if (t->tv_sec < p->tv_sec)
    231     return TRUE;
    232   else if (t->tv_sec == p->tv_sec)
    233     return t->tv_nsec <= p->tv_nsec;
    234   return FALSE;
    235 }
    236 
    237 static const struct mk_timespec* mk_timespec_max(const struct mk_timespec* t,
    238                                                  const struct mk_timespec* p) {
    239   return mk_timespec_le(t, p) ? p : t;
    240 }
    241 
    242 /*
    243  * Recursive routine to make a target.
    244  */
    245 static int mk_make(MakeCtx* mc, struct name* np, int level) {
    246   struct depend* dp;
    247   struct rule* rp;
    248   struct name* impdep = NULL; /* implicit prerequisite */
    249   struct rule infrule;
    250   struct cmd* sc_cmd = NULL; /* commands for single-colon rule */
    251   char* oodate = NULL;
    252   char* allsrc = NULL;
    253   char* dedup = NULL;
    254   const char* tsuff = NULL;
    255   struct mk_timespec dtim = {1, 0};
    256   int estat = 0;
    257 
    258   if (np->n_flag & N_DONE) return 0;
    259   if (np->n_flag & N_DOING) mk_error(mc, "circular dependency for %s",
    260                                      np->n_name);
    261   np->n_flag |= N_DOING;
    262 
    263   if (!np->n_tim.tv_sec) mk_modtime(mc, np); /* Get modtime of this file. */
    264 
    265   if (!(np->n_flag & N_DOUBLE)) {
    266     /* Find the commands for a single-colon rule, using an inference or .DEFAULT
    267      * rule if needed (but, as an extension, not for phony targets). */
    268     sc_cmd = mk_getcmd(np);
    269     if (!sc_cmd && (mc->posix || !(np->n_flag & N_PHONY))) {
    270       impdep = mk_dyndep(mc, np, &infrule, &tsuff);
    271       if (impdep) {
    272         sc_cmd = infrule.r_cmd;
    273         mk_addrule(mc, np, infrule.r_dep, NULL, FALSE);
    274       }
    275     }
    276 
    277     /* As a last resort check for a default rule. */
    278     if (!(np->n_flag & N_TARGET) && np->n_tim.tv_sec == 0) {
    279       if (mc->posix || !(np->n_flag & N_PHONY))
    280         sc_cmd = mk_getcmd(mk_findname(mc, ".DEFAULT"));
    281       if (!sc_cmd) {
    282         if (doinclude) return 1;
    283         mk_error(mc, "don't know how to make %s", np->n_name);
    284       }
    285       impdep = np;
    286     }
    287   } else {
    288     /* If any double-colon rule has no commands we need an inference rule. */
    289     for (rp = np->n_rule; rp; rp = rp->r_next) {
    290       if (!rp->r_cmd) {
    291         /* Phony targets don't need an inference rule. */
    292         if (!mc->posix && (np->n_flag & N_PHONY)) continue;
    293         impdep = mk_dyndep(mc, np, &infrule, &tsuff);
    294         if (!impdep) {
    295           if (doinclude) return 1;
    296           mk_error(mc, "don't know how to make %s", np->n_name);
    297         }
    298         break;
    299       }
    300     }
    301   }
    302 
    303   /* Reset flag to detect duplicate prerequisites. */
    304   if (!(np->n_flag & N_DOUBLE)) {
    305     for (rp = np->n_rule; rp; rp = rp->r_next)
    306       for (dp = rp->r_dep; dp; dp = dp->d_next) dp->d_name->n_flag &= ~N_MARK;
    307   }
    308 
    309   for (rp = np->n_rule; rp; rp = rp->r_next) {
    310     struct name* locdep = NULL;
    311 
    312     /* Each double-colon rule is handled separately. */
    313     if ((np->n_flag & N_DOUBLE)) {
    314       /* If the rule has no commands use the inference rule (unless there isn't
    315        * one, as allowed for phony targets). */
    316       if (!rp->r_cmd) {
    317         if (impdep) {
    318           locdep = impdep;
    319           infrule.r_dep->d_next = rp->r_dep;
    320           rp->r_dep = infrule.r_dep;
    321           rp->r_cmd = infrule.r_cmd;
    322         }
    323       }
    324       /* A rule with no prerequisites is executed unconditionally. */
    325       if (!rp->r_dep) dtim = np->n_tim;
    326       /* Reset flag to detect duplicate prerequisites. */
    327       for (dp = rp->r_dep; dp; dp = dp->d_next) dp->d_name->n_flag &= ~N_MARK;
    328     }
    329     for (dp = rp->r_dep; dp; dp = dp->d_next) {
    330       /* Make prerequisite. */
    331       estat |= mk_make(mc, dp->d_name, level + 1);
    332 
    333       /* Make strings of out-of-date prerequisites ($?), all prerequisites ($+)
    334        * and deduplicated prerequisites ($^). */
    335       if (mk_timespec_le(&np->n_tim, &dp->d_name->n_tim)) {
    336         if (mc->posix || !(dp->d_name->n_flag & N_MARK))
    337           oodate = mk_appendword(mc, oodate, dp->d_name->n_name);
    338       }
    339       allsrc = mk_appendword(mc, allsrc, dp->d_name->n_name);
    340       if (!(dp->d_name->n_flag & N_MARK))
    341         dedup = mk_appendword(mc, dedup, dp->d_name->n_name);
    342       dp->d_name->n_flag |= N_MARK;
    343       dtim = *mk_timespec_max(&dtim, &dp->d_name->n_tim);
    344     }
    345     if ((np->n_flag & N_DOUBLE)) {
    346       if (((np->n_flag & N_PHONY) || mk_timespec_le(&np->n_tim, &dtim))) {
    347         if (!(estat & MAKE_FAILURE)) {
    348           estat |= mk_make1(mc, np, rp->r_cmd, oodate, allsrc, dedup, locdep,
    349                             tsuff);
    350           dtim = (struct mk_timespec){1, 0};
    351         }
    352         oodate = NULL;
    353       }
    354       allsrc = dedup = NULL;
    355       if (locdep) {
    356         rp->r_dep = rp->r_dep->d_next;
    357         rp->r_cmd = NULL;
    358       }
    359     }
    360   }
    361 
    362   np->n_flag |= N_DONE;
    363   np->n_flag &= ~N_DOING;
    364 
    365   if (!(np->n_flag & N_DOUBLE) &&
    366       ((np->n_flag & N_PHONY) || (mk_timespec_le(&np->n_tim, &dtim)))) {
    367     if (!(estat & MAKE_FAILURE)) {
    368       if (sc_cmd)
    369         estat |= mk_make1(mc, np, sc_cmd, oodate, allsrc, dedup, impdep, tsuff);
    370       else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING))
    371         mk_warning(mc, "nothing to be done for %s", np->n_name);
    372     } else if (!doinclude && !quest) {
    373       mk_diagnostic(mc, "'%s' not built due to errors", np->n_name);
    374     }
    375   }
    376 
    377   if (estat & MAKE_DIDSOMETHING) {
    378     mk_modtime(mc, np);
    379     if (!np->n_tim.tv_sec) {
    380       np->n_tim.tv_sec = mc->ctx->now > 0 ? mc->ctx->now : ((int64_t)1 << 40);
    381       np->n_tim.tv_nsec = 0;
    382     }
    383   } else if (!quest && level == 0 && !mk_timespec_le(&np->n_tim, &dtim))
    384     mk_outf(mc, "%s: '%s' is up to date\n", mc->myname, np->n_name);
    385 
    386   return estat;
    387 }