kit

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

target.c (7960B)


      1 /*
      2  * Process name, rule, command and prerequisite structures. Ported from pdpmake
      3  * target.c. Part of the src/api/make.c amalgamation.
      4  */
      5 #include "make.h"
      6 
      7 /*
      8  * Add a prerequisite to the end of the supplied list.
      9  * Return the new head pointer for that list.
     10  */
     11 static struct depend* mk_newdep(MakeCtx* mc, struct name* np,
     12                                 struct depend* dphead) {
     13   struct depend* dpnew;
     14   struct depend* dp;
     15 
     16   dpnew = mk_alloc(mc, sizeof(struct depend));
     17   dpnew->d_next = NULL;
     18   dpnew->d_name = np;
     19   dpnew->d_refcnt = 0;
     20 
     21   if (dphead == NULL)
     22     return dpnew;
     23 
     24   for (dp = dphead; dp->d_next; dp = dp->d_next)
     25     ;
     26 
     27   dp->d_next = dpnew;
     28 
     29   return dphead;
     30 }
     31 
     32 /*
     33  * Add a command to the end of the supplied list of commands.
     34  * Return the new head pointer for that list.
     35  */
     36 static struct cmd* mk_newcmd(MakeCtx* mc, char* str, struct cmd* cphead) {
     37   struct cmd* cpnew;
     38   struct cmd* cp;
     39 
     40   while (isspace(*str))
     41     str++;
     42 
     43   cpnew = mk_alloc(mc, sizeof(struct cmd));
     44   cpnew->c_next = NULL;
     45   cpnew->c_cmd = mk_strdup(mc, str);
     46   cpnew->c_refcnt = 0;
     47   cpnew->c_makefile = mk_strdup(mc, mc->makefile);
     48   cpnew->c_dispno = mc->dispno;
     49 
     50   if (cphead == NULL)
     51     return cpnew;
     52 
     53   for (cp = cphead; cp->c_next; cp = cp->c_next)
     54     ;
     55 
     56   cp->c_next = cpnew;
     57 
     58   return cphead;
     59 }
     60 
     61 static struct name* mk_findname(MakeCtx* mc, const char* name) {
     62   struct name* np;
     63 
     64   for (np = mc->namehead[mk_getbucket(name)]; np; np = np->n_next) {
     65     if (strcmp(name, np->n_name) == 0)
     66       return np;
     67   }
     68   return NULL;
     69 }
     70 
     71 static int mk_check_name(MakeCtx* mc, const char* name) {
     72   const char* s;
     73 
     74 #if ENABLE_FEATURE_MAKE_EXTENSIONS
     75   if (!mc->posix) {
     76     for (s = name; *s; ++s) {
     77       if (*s == '=')
     78         return FALSE;
     79     }
     80     return TRUE;
     81   }
     82 #endif
     83 
     84   for (s = name; *s; ++s) {
     85     if ((
     86 #if ENABLE_FEATURE_MAKE_EXTENSIONS
     87             (mc->pragma & P_TARGET_NAME) ||
     88 #endif
     89 #if ENABLE_FEATURE_MAKE_POSIX_2024
     90             !POSIX_2017
     91 #else
     92             FALSE
     93 #endif
     94             )
     95             ? !(isfname(*s) || *s == '/')
     96             : !ispname(*s))
     97       return FALSE;
     98   }
     99   return TRUE;
    100 }
    101 
    102 static int mk_is_valid_target(MakeCtx* mc, const char* name) {
    103   char* archive;
    104   char* member = NULL;
    105   int ret;
    106 
    107   /* Names of the form 'lib(member)' are referred to as 'expressions'
    108    * in POSIX and are subjected to special treatment.  The 'lib'
    109    * and 'member' elements must each be a valid target name. */
    110   archive = mk_splitlib(mc, name, &member);
    111   ret = mk_check_name(mc, archive) &&
    112         (member == NULL || mk_check_name(mc, member));
    113 
    114   return ret;
    115 }
    116 
    117 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    118 static int mk_potentially_valid_target(MakeCtx* mc, const char* name) {
    119   int ret = FALSE;
    120 
    121   if (!(mc->pragma & P_TARGET_NAME)) {
    122     mc->pragma |= P_TARGET_NAME;
    123     ret = mk_is_valid_target(mc, name);
    124     mc->pragma &= ~P_TARGET_NAME;
    125   }
    126   return ret;
    127 }
    128 #endif
    129 
    130 /*
    131  * Intern a name.  Return a pointer to the name struct
    132  */
    133 static struct name* mk_newname(MakeCtx* mc, const char* name) {
    134   struct name* np = mk_findname(mc, name);
    135 
    136   if (np == NULL) {
    137     unsigned int bucket;
    138 
    139     if (!mk_is_valid_target(mc, name))
    140 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    141       mk_error(mc, "invalid target name '%s'%s", name,
    142                mk_potentially_valid_target(mc, name)
    143                    ? ": allow with pragma target_name"
    144                    : "");
    145 #else
    146       mk_error(mc, "invalid target name '%s'", name);
    147 #endif
    148 
    149     bucket = mk_getbucket(name);
    150     np = mk_alloc(mc, sizeof(struct name));
    151     np->n_next = mc->namehead[bucket];
    152     mc->namehead[bucket] = np;
    153     np->n_name = mk_strdup(mc, name);
    154     np->n_rule = NULL;
    155     np->n_tim = (struct mk_timespec){0, 0};
    156     np->n_flag = 0;
    157   }
    158   return np;
    159 }
    160 
    161 /*
    162  * Return the commands on the first rule that has them or NULL.
    163  */
    164 static struct cmd* mk_getcmd(struct name* np) {
    165   struct rule* rp;
    166 
    167   if (np == NULL)
    168     return NULL;
    169 
    170   for (rp = np->n_rule; rp; rp = rp->r_next)
    171     if (rp->r_cmd)
    172       return rp->r_cmd;
    173   return NULL;
    174 }
    175 
    176 static void mk_freerules(struct rule* rp) { (void)rp; }
    177 
    178 static void* mk_inc_ref(MakeCtx* mc, void* vp) {
    179   if (vp) {
    180     struct depend* dp = vp;
    181     if (dp->d_refcnt == INT_MAX)
    182       mk_error(mc, "out of memory");
    183     dp->d_refcnt++;
    184   }
    185   return vp;
    186 }
    187 
    188 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    189 // Order must match constants in make.h
    190 // POSIX levels must be last and in increasing order
    191 static const char* p_name[] = {
    192     "macro_name",
    193     "target_name",
    194     "command_comment",
    195     "empty_suffix",
    196     "posix_2017",
    197     "posix_2024",
    198     "posix_202x"
    199 };
    200 
    201 static void mk_set_pragma(MakeCtx* mc, const char* name) {
    202   int i;
    203 
    204   // posix_202x is an alias for posix_2024
    205   for (i = 0; i < (int)(sizeof(p_name) / sizeof(p_name[0])); ++i) {
    206     if (strcmp(name, p_name[i]) == 0) {
    207 #if !ENABLE_FEATURE_MAKE_POSIX_2024
    208       if (i == BIT_POSIX_2024 || i == BIT_POSIX_202X) {
    209         break;
    210       }
    211 #endif
    212       if (i >= BIT_POSIX_2017) {
    213         // POSIX level is stored in a separate variable.
    214         // No bits in 'pragma' are used.
    215         if (mc->posix_level == DEFAULT_POSIX_LEVEL) {
    216           mc->posix_level = i - BIT_POSIX_2017;
    217           if (mc->posix_level > STD_POSIX_2024)
    218             mc->posix_level = STD_POSIX_2024;
    219         } else if (mc->posix_level != i - BIT_POSIX_2017)
    220           mk_warning(mc, "unable to change POSIX level");
    221       } else {
    222         mc->pragma |= 1 << i;
    223       }
    224       return;
    225     }
    226   }
    227   mk_warning(mc, "invalid pragma '%s'", name);
    228 }
    229 #endif
    230 
    231 /*
    232  * Add a new rule to a target.  This checks to see if commands already
    233  * exist for the target.  If flag is TRUE the target can have multiple
    234  * rules with commands (double-colon rules).
    235  *
    236  * i)  If the name is a special target and there are no prerequisites
    237  *     or commands to be added remove all prerequisites and commands.
    238  *     This is necessary when clearing a built-in inference rule.
    239  * ii) If name is a special target and has commands, replace them.
    240  *     This is for redefining commands for an inference rule.
    241  */
    242 static void mk_addrule(MakeCtx* mc, struct name* np, struct depend* dp,
    243                        struct cmd* cp, int flag) {
    244   struct rule* rp;
    245   struct rule** rpp;
    246   struct cmd* old_cp;
    247 
    248 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    249   // Can't mix single-colon and double-colon rules
    250   if (!mc->posix && (np->n_flag & N_TARGET)) {
    251     if (!(np->n_flag & N_DOUBLE) != !flag)  // like xor
    252       mk_error(mc, "inconsistent rules for target %s", np->n_name);
    253   }
    254 #endif
    255 
    256   // Clear out prerequisites and commands
    257   if ((np->n_flag & N_SPECIAL) && !dp && !cp) {
    258 #if ENABLE_FEATURE_MAKE_POSIX_2024
    259     if (strcmp(np->n_name, ".PHONY") == 0)
    260       return;
    261 #endif
    262     mk_freerules(np->n_rule);
    263     np->n_rule = NULL;
    264     return;
    265   }
    266 
    267   if (cp && !(np->n_flag & N_DOUBLE) && (old_cp = mk_getcmd(np))) {
    268     // Handle the inference rule redefinition case
    269     // .DEFAULT rule can also be redefined (as an extension).
    270     if ((np->n_flag & N_INFERENCE)
    271 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    272         && !(mc->posix && (np->n_flag & N_SPECIAL))
    273 #endif
    274     ) {
    275       mk_freerules(np->n_rule);
    276       np->n_rule = NULL;
    277     } else {
    278       // We're adding commands to a single colon rule which
    279       // already has some.  Clear the old ones first.
    280       mk_warning(mc, "overriding rule for target %s", np->n_name);
    281       mc->curr_cmd = old_cp;
    282       mk_warning(mc, "previous rule for target %s", np->n_name);
    283       mc->curr_cmd = NULL;
    284 
    285       for (rp = np->n_rule; rp; rp = rp->r_next) {
    286         rp->r_cmd = NULL;
    287       }
    288     }
    289   }
    290 
    291   rpp = &np->n_rule;
    292   while (*rpp)
    293     rpp = &(*rpp)->r_next;
    294 
    295   *rpp = rp = mk_alloc(mc, sizeof(struct rule));
    296   rp->r_next = NULL;
    297   rp->r_dep = mk_inc_ref(mc, dp);
    298   rp->r_cmd = mk_inc_ref(mc, cp);
    299 
    300   np->n_flag |= N_TARGET;
    301   if (flag)
    302     np->n_flag |= N_DOUBLE;
    303 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    304   if (strcmp(np->n_name, ".PRAGMA") == 0) {
    305     for (; dp; dp = dp->d_next) {
    306       mk_set_pragma(mc, dp->d_name->n_name);
    307     }
    308   }
    309 #endif
    310 }