kit

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

run.c (9943B)


      1 /*
      2  * Top-level orchestration: install default macros/rules, import command-line,
      3  * MAKEFLAGS, and environment macros, read the makefiles, build the child
      4  * environment (with the outgoing MAKEFLAGS so recursive make keeps its flags),
      5  * then bring the requested targets up to date. This is pdpmake main() minus the
      6  * CLI/getopt machinery (now in driver/cmd/make.c). Part of the src/api/make.c
      7  * amalgamation.
      8  */
      9 #include "make.h"
     10 
     11 static char* mk_slice_dup(MakeCtx* mc, KitSlice s) {
     12   char* t = mk_alloc(mc, s.len + 1);
     13   if (s.len) memcpy(t, s.s, s.len);
     14   t[s.len] = '\0';
     15   return t;
     16 }
     17 
     18 /* Look up NAME in the ambient environment; return its value or NULL. */
     19 static const char* mk_getenv(MakeCtx* mc, const char* name) {
     20   size_t nlen = strlen(name);
     21   const char* const* e;
     22   if (!mc->ambient) return NULL;
     23   for (e = mc->ambient; *e; ++e)
     24     if (strncmp(*e, name, nlen) == 0 && (*e)[nlen] == '=') return *e + nlen + 1;
     25   return NULL;
     26 }
     27 
     28 /*
     29  * If the option flag for a special target isn't set, mark its prerequisites;
     30  * if the target had no prerequisites, set the global option flag.
     31  */
     32 static void mk_mark_special(MakeCtx* mc, const char* special, uint32_t oflag,
     33                             uint16_t nflag) {
     34   struct name* np;
     35   struct rule* rp;
     36   struct depend* dp;
     37   int marked = FALSE;
     38 
     39   if (!(mc->opts & oflag) && (np = mk_findname(mc, special))) {
     40     for (rp = np->n_rule; rp; rp = rp->r_next) {
     41       for (dp = rp->r_dep; dp; dp = dp->d_next) {
     42         dp->d_name->n_flag |= nflag;
     43         marked = TRUE;
     44       }
     45     }
     46     if (!marked) mc->opts |= oflag;
     47   }
     48 }
     49 
     50 /* Import NAME=VALUE entries from the environment as level-3 macros. */
     51 static void mk_import_env(MakeCtx* mc) {
     52   const char* const* e;
     53 
     54   if (!mc->ambient) return;
     55   for (e = mc->ambient; *e; ++e) {
     56     const char* eq = strchr(*e, '=');
     57     char* name;
     58     if (!eq || eq == *e) continue;
     59     name = mk_strndup(mc, *e, (size_t)(eq - *e));
     60     /* Exceptions for particular environment values (see pdpmake). */
     61     if (strcmp(name, "MAKEFLAGS") == 0 || strcmp(name, "SHELL") == 0) continue;
     62     if (strcmp(name, "CURDIR") == 0 && !useenv && !POSIX_2017) continue;
     63     mk_setmacro(mc, name, eq + 1, 3 | M_ENVIRON);
     64   }
     65 }
     66 
     67 /*
     68  * Parse the incoming MAKEFLAGS environment variable: whitespace-separated
     69  * tokens are either option letters (merged into mc->opts) or NAME=VALUE macro
     70  * definitions (level 2). This is how a recursive `make` inherits the flags and
     71  * macros of its parent. (Escaped blanks in values are not handled in v1.)
     72  */
     73 static void mk_makeflags_in(MakeCtx* mc) {
     74   const char* mf = mk_getenv(mc, "MAKEFLAGS");
     75   char* dup;
     76   char* q;
     77   char* tok;
     78 
     79   if (!mf || !*mf) return;
     80   dup = mk_strdup(mc, mf);
     81   q = dup;
     82   while ((tok = mk_gettok(&q)) != NULL) {
     83     char* eq = strchr(tok, '=');
     84     if (eq && eq != tok) {
     85       *eq = '\0';
     86       mk_setmacro(mc, tok, eq + 1, 2);
     87     } else {
     88       const char* p = tok;
     89       if (*p == '-') ++p;
     90       for (; *p; ++p) {
     91         switch (*p) {
     92           case 'e': mc->opts |= OPT_e; break;
     93           case 'i': mc->opts |= OPT_i; break;
     94           case 'k': mc->opts |= OPT_k; break;
     95           case 'n': mc->opts |= OPT_n; break;
     96           case 'q': mc->opts |= OPT_q; break;
     97           case 'r': mc->opts |= OPT_r; break;
     98           case 's': mc->opts |= OPT_s; break;
     99           case 't': mc->opts |= OPT_t; break;
    100           default: break; /* ignore unknown (e.g. -j and its digits) */
    101         }
    102       }
    103     }
    104   }
    105 }
    106 
    107 /* Backslash-escape blanks and backslashes for embedding in MAKEFLAGS. */
    108 static char* mk_escape_value(MakeCtx* mc, const char* val) {
    109   size_t n = 0;
    110   size_t i;
    111   size_t j = 0;
    112   char* out;
    113   for (i = 0; val[i]; ++i)
    114     n += (val[i] == '\\' || val[i] == ' ' || val[i] == '\t') ? 2 : 1;
    115   out = mk_alloc(mc, n + 1);
    116   for (i = 0; val[i]; ++i) {
    117     if (val[i] == '\\' || val[i] == ' ' || val[i] == '\t') out[j++] = '\\';
    118     out[j++] = val[i];
    119   }
    120   out[j] = '\0';
    121   return out;
    122 }
    123 
    124 /*
    125  * Build the child environment vector used to launch recipes: the ambient
    126  * environment (minus MAKEFLAGS), the outgoing MAKEFLAGS (option flags plus
    127  * level-1/2 macros), and the command-line (level-1) macros exported as
    128  * individual variables. Stored in mc->env.
    129  */
    130 static void mk_build_child_env(MakeCtx* mc) {
    131   static const struct {
    132     uint32_t bit;
    133     const char* flag;
    134   } fl[] = {{OPT_e, "-e"}, {OPT_i, "-i"}, {OPT_k, "-k"}, {OPT_n, "-n"},
    135            {OPT_q, "-q"}, {OPT_r, "-r"}, {OPT_s, "-s"}, {OPT_t, "-t"}};
    136   char* mf = NULL;
    137   int i;
    138   size_t k;
    139   struct macro* mp;
    140   size_t n_ambient = 0;
    141   size_t n_export = 0;
    142   size_t count = 0;
    143   const char* const* e;
    144   KitExecKV* env;
    145 
    146   for (k = 0; k < sizeof fl / sizeof fl[0]; ++k)
    147     if (mc->opts & fl[k].bit) mf = mk_appendword(mc, mf, fl[k].flag);
    148   for (i = 0; i < HTABSIZE; ++i)
    149     for (mp = mc->macrohead[i]; mp; mp = mp->m_next)
    150       if ((mp->m_level == 1 || mp->m_level == 2) &&
    151           strcmp(mp->m_name, "MAKEFLAGS") != 0)
    152         mf = mk_appendword(
    153             mc, mf,
    154             mk_concat3(mc, mp->m_name, "=", mk_escape_value(mc, mp->m_val)));
    155   if (!mf) mf = mk_strdup(mc, "");
    156   /* Also expose it as the MAKEFLAGS macro so $(MAKEFLAGS) expands. */
    157   mk_setmacro(mc, "MAKEFLAGS", mf, 0);
    158 
    159   if (mc->ambient)
    160     for (e = mc->ambient; *e; ++e)
    161       if (strncmp(*e, "MAKEFLAGS=", 10) != 0) n_ambient++;
    162   for (i = 0; i < HTABSIZE; ++i)
    163     for (mp = mc->macrohead[i]; mp; mp = mp->m_next)
    164       if (mp->m_level == 1 && strcmp(mp->m_name, "SHELL") != 0 &&
    165           strcmp(mp->m_name, "MAKEFLAGS") != 0)
    166         n_export++;
    167 
    168   env = mk_alloc(mc, (n_ambient + n_export + 1) * sizeof *env);
    169   if (mc->ambient)
    170     for (e = mc->ambient; *e; ++e) {
    171       const char* eq;
    172       if (strncmp(*e, "MAKEFLAGS=", 10) == 0) continue;
    173       eq = strchr(*e, '=');
    174       if (!eq) continue;
    175       env[count].key.s = *e;
    176       env[count].key.len = (size_t)(eq - *e);
    177       env[count].value = kit_slice_cstr(eq + 1);
    178       count++;
    179     }
    180   env[count].key = kit_slice_cstr("MAKEFLAGS");
    181   env[count].value = kit_slice_cstr(mf);
    182   count++;
    183   for (i = 0; i < HTABSIZE; ++i)
    184     for (mp = mc->macrohead[i]; mp; mp = mp->m_next)
    185       if (mp->m_level == 1 && strcmp(mp->m_name, "SHELL") != 0 &&
    186           strcmp(mp->m_name, "MAKEFLAGS") != 0) {
    187         env[count].key = kit_slice_cstr(mp->m_name);
    188         env[count].value = kit_slice_cstr(mp->m_val);
    189         count++;
    190       }
    191   mc->env = env;
    192   mc->nenv = count;
    193 }
    194 
    195 /* Read one makefile source into the graph (name is for diagnostics only). */
    196 static void mk_read_source(MakeCtx* mc, const char* name, MakeSource* src) {
    197   mc->makefile = name;
    198   mk_input(mc, src, 0);
    199   mc->makefile = NULL;
    200 }
    201 
    202 /* Read a makefile by path (resolved against root) through file_io. */
    203 static int mk_read_path(MakeCtx* mc, const char* path, int required) {
    204   const KitFileIO* io = mc->ctx->file_io;
    205   KitFileData fd;
    206   MakeSource src;
    207 
    208   fd.data = NULL;
    209   fd.size = 0;
    210   fd.token = NULL;
    211   if (!io || io->read_all(io->user, mk_path(mc, path), &fd) != KIT_OK) {
    212     if (required) mk_error(mc, "can't open %s", path);
    213     return 0;
    214   }
    215   src.data = (const char*)fd.data;
    216   src.len = fd.size;
    217   src.pos = 0;
    218   mk_read_source(mc, path, &src);
    219   if (io->release) io->release(io->user, &fd);
    220   return 1;
    221 }
    222 
    223 static int mk_run(MakeCtx* mc) {
    224   const KitMakeOptions* o = mc->mkopts;
    225   MakeSource builtin = {NULL, 0, 0};
    226   struct macro* shell_mp;
    227   size_t i;
    228   int estat;
    229   int found_target;
    230 
    231   mc->myname = "make";
    232   mk_setmacro(mc, "$", "$", 0 | M_VALID);
    233 
    234   /* Macro definitions from the command line (highest precedence, level 1). */
    235   for (i = 0; i < o->nmacros; ++i) {
    236     char* name = mk_slice_dup(mc, o->macros[i].name);
    237     char* val = mk_slice_dup(mc, o->macros[i].value);
    238     mk_setmacro(mc, name, val, 1);
    239   }
    240 
    241   /* MAKEFLAGS from the environment: option flags + macros (level 2). */
    242   mk_makeflags_in(mc);
    243 
    244   /* Macro definitions from the environment (level 3). */
    245   mk_import_env(mc);
    246 
    247   /* Built-in rules. */
    248   mk_input(mc, &builtin, 0);
    249 
    250   /* SHELL / MAKE / CURDIR (level 4; a makefile can still override SHELL). */
    251   mk_setmacro(mc, "SHELL", mc->shell ? mc->shell : "/bin/sh", 4);
    252   mk_setmacro(mc, "MAKE", "make", 4);
    253   if (mc->root && !POSIX_2017) mk_setmacro(mc, "CURDIR", mc->root, 4);
    254 
    255   /* User makefiles (paths resolved against root; no chdir). */
    256   if (o->nmakefiles == 0) {
    257     const char* names[3];
    258     int nn = 0;
    259     int opened = 0;
    260     int k;
    261     if (!mc->posix) names[nn++] = "PDPmakefile";
    262     names[nn++] = "makefile";
    263     names[nn++] = "Makefile";
    264     for (k = 0; k < nn && !opened; ++k) opened = mk_read_path(mc, names[k], 0);
    265     if (!opened) mk_error(mc, "no makefile found");
    266   } else {
    267     for (i = 0; i < o->nmakefiles; ++i) {
    268       const char* fn = o->makefiles[i];
    269       if (strcmp(fn, "-") == 0) {
    270         MakeSource src;
    271         src.data = (const char*)o->stdin_makefile;
    272         src.len = o->stdin_makefile_len;
    273         src.pos = 0;
    274         mk_read_source(mc, "stdin", &src);
    275       } else {
    276         mk_read_path(mc, fn, TRUE);
    277       }
    278     }
    279   }
    280 
    281   /* Honor a makefile-provided SHELL for recipe execution. */
    282   shell_mp = mk_getmp(mc, "SHELL");
    283   if (shell_mp && shell_mp->m_val[0]) mc->shell = shell_mp->m_val;
    284 
    285   if (print) mk_print_details(mc);
    286 
    287   mk_mark_special(mc, ".SILENT", OPT_s, N_SILENT);
    288   mk_mark_special(mc, ".IGNORE", OPT_i, N_IGNORE);
    289   mk_mark_special(mc, ".PRECIOUS", OPT_precious, N_PRECIOUS);
    290   if (!POSIX_2017) mk_mark_special(mc, ".PHONY", OPT_phony, N_PHONY);
    291 
    292   /* Assemble the recipe environment now that all macros/flags are known. */
    293   mk_build_child_env(mc);
    294 
    295   /* Build the requested targets (or the default goal). */
    296   estat = 0;
    297   found_target = FALSE;
    298   for (i = 0; i < o->ntargets; ++i) {
    299     found_target = TRUE;
    300     estat |= mk_make(mc, mk_newname(mc, o->targets[i]), 0);
    301   }
    302   if (!found_target) {
    303     if (!mc->firstname) mk_error(mc, "no targets defined");
    304     estat = mk_make(mc, mc->firstname, 0);
    305   }
    306 
    307   return estat & MAKE_FAILURE;
    308 }