kit

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

rules.c (6937B)


      1 /*
      2  * Control of the implicit suffix rules
      3  */
      4 #include "make.h"
      5 
      6 /*
      7  * Return a pointer to the suffix of a name (which may be the
      8  * terminating NUL if there's no suffix).
      9  */
     10 static char *
     11 mk_suffix(const char *name)
     12 {
     13 	char *p = strrchr(name, '.');
     14 	return p ? p : (char *)name + strlen(name);
     15 }
     16 
     17 /*
     18  * Find a name structure whose name is formed by concatenating two
     19  * strings.  If 'create' is TRUE the name is created if necessary.
     20  */
     21 static struct name *
     22 mk_namecat(MakeCtx* mc, const char *s, const char *t, int create)
     23 {
     24 	char *p;
     25 	struct name *np;
     26 
     27 	p = mk_concat3(mc, s, t, "");
     28 	np = create ? mk_newname(mc, p) : mk_findname(mc, p);
     29 	return np;
     30 }
     31 
     32 /*
     33  * Search for an inference rule to convert some suffix ('psuff')
     34  * to the target suffix 'tsuff'.  The basename of the prerequisite
     35  * is 'base'.
     36  */
     37 static struct name *
     38 mk_dyndep0(MakeCtx* mc, char *base, const char *tsuff, struct rule *infrule)
     39 {
     40 	char *psuff;
     41 	struct name *xp;		// Suffixes
     42 	struct name *sp;		// Suffix rule
     43 	struct rule *rp;
     44 	struct depend *dp;
     45 	IF_NOT_FEATURE_MAKE_EXTENSIONS(const) bool chain = FALSE;
     46 
     47 	xp = mk_newname(mc, ".SUFFIXES");
     48 #if ENABLE_FEATURE_MAKE_EXTENSIONS
     49  retry:
     50 #endif
     51 	for (rp = xp->n_rule; rp; rp = rp->r_next) {
     52 		for (dp = rp->r_dep; dp; dp = dp->d_next) {
     53 			// Generate new suffix rule to try
     54 			psuff = dp->d_name->n_name;
     55 			sp = mk_namecat(mc, psuff, tsuff, FALSE);
     56 			if (sp && sp->n_rule) {
     57 				struct name *ip;
     58 				int got_ip;
     59 
     60 #if ENABLE_FEATURE_MAKE_EXTENSIONS
     61 				// Has rule already been used in this chain?
     62 				if ((sp->n_flag & N_MARK))
     63 					continue;
     64 #endif
     65 				// Generate a name for an implicit prerequisite
     66 				ip = mk_namecat(mc, base, psuff, TRUE);
     67 				if ((ip->n_flag & N_DOING))
     68 					continue;
     69 
     70 				if (!ip->n_tim.tv_sec)
     71 					mk_modtime(mc, ip);
     72 
     73 				if (!chain) {
     74 					got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET);
     75 				}
     76 #if ENABLE_FEATURE_MAKE_EXTENSIONS
     77 				else {
     78 					sp->n_flag |= N_MARK;
     79 					got_ip = mk_dyndep(mc, ip, NULL, NULL) != NULL;
     80 					sp->n_flag &= ~N_MARK;
     81 				}
     82 #endif
     83 
     84 				if (got_ip) {
     85 					// Prerequisite exists or we know how to make it
     86 					if (infrule) {
     87 						infrule->r_dep = mk_newdep(mc, ip, NULL);
     88 						infrule->r_cmd = sp->n_rule->r_cmd;
     89 					}
     90 					return ip;
     91 				}
     92 			}
     93 		}
     94 	}
     95 #if ENABLE_FEATURE_MAKE_EXTENSIONS
     96 	// If we didn't find an existing file or an explicit rule try
     97 	// again, this time looking for a chained inference rule.
     98 	if (!mc->posix && !chain) {
     99 		chain = TRUE;
    100 		goto retry;
    101 	}
    102 #endif
    103 	return NULL;
    104 }
    105 
    106 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    107 /*
    108  * If 'name' ends with 'suffix' return an allocated string containing
    109  * the name with the suffix removed, else return NULL.
    110  */
    111 static char *
    112 mk_has_suffix(MakeCtx* mc, const char *name, const char *suffix)
    113 {
    114 	ptrdiff_t delta = strlen(name) - strlen(suffix);
    115 	char *base = NULL;
    116 
    117 	if (delta > 0 && strcmp(name + delta, suffix) == 0) {
    118 		base = mk_strdup(mc, name);
    119 		base[delta] = '\0';
    120 	}
    121 
    122 	return base;
    123 }
    124 #endif
    125 
    126 /*
    127  * Dynamic dependency.  This routine applies the suffix rules
    128  * to try and find a source and a set of rules for a missing
    129  * target.  NULL is returned on failure.  On success the name of
    130  * the implicit prerequisite is returned and the rule used is
    131  * placed in the infrule structure provided by the caller.
    132  */
    133 static struct name *
    134 mk_dyndep(MakeCtx* mc, struct name *np, struct rule *infrule, const char **ptsuff)
    135 {
    136 	const char *tsuff;
    137 	char *base, *name, *member;
    138 	struct name *pp = NULL;	// Implicit prerequisite
    139 
    140 	member = NULL;
    141 	name = mk_splitlib(mc, np->n_name, &member);
    142 
    143 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    144 	// POSIX only allows inference rules with one or two periods.
    145 	// As an extension this restriction is lifted, but not for
    146 	// targets of the form lib.a(member.o).
    147 	if (!mc->posix && member == NULL) {
    148 		struct name *xp = mk_newname(mc, ".SUFFIXES");
    149 		int found_suffix = FALSE;
    150 
    151 		for (struct rule *rp = xp->n_rule; rp; rp = rp->r_next) {
    152 			for (struct depend *dp = rp->r_dep; dp; dp = dp->d_next) {
    153 				tsuff = dp->d_name->n_name;
    154 				base = mk_has_suffix(mc, name, tsuff);
    155 				if (base) {
    156 					found_suffix = TRUE;
    157 					pp = mk_dyndep0(mc, base, tsuff, infrule);
    158 					if (pp) {
    159 						goto done;
    160 					}
    161 				}
    162 			}
    163 		}
    164 
    165 		if (!found_suffix) {
    166 			// The name didn't have a known suffix. Try single-suffix rule.
    167 			tsuff = "";
    168 			pp = mk_dyndep0(mc, name, tsuff, infrule);
    169 			if (pp) {
    170  done:
    171 				if (ptsuff) {
    172 					*ptsuff = tsuff;
    173 				}
    174 			}
    175 		}
    176 	} else
    177 #endif
    178 	{
    179 		tsuff = mk_strdup(mc, mk_suffix(name));
    180 		base = member ? member : name;
    181 		*mk_suffix(base) = '\0';
    182 
    183 		pp = mk_dyndep0(mc, base, tsuff, infrule);
    184 	}
    185 
    186 	return pp;
    187 }
    188 
    189 #define RULES \
    190 	".c.o:\n" \
    191 	"	$(CC) $(CFLAGS) -c $<\n" \
    192 	".y.o:\n" \
    193 	"	$(YACC) $(YFLAGS) $<\n" \
    194 	"	$(CC) $(CFLAGS) -c y.tab.c\n" \
    195 	"	rm -f y.tab.c\n" \
    196 	"	mv y.tab.o $@\n" \
    197 	".y.c:\n" \
    198 	"	$(YACC) $(YFLAGS) $<\n" \
    199 	"	mv y.tab.c $@\n" \
    200 	".l.o:\n" \
    201 	"	$(LEX) $(LFLAGS) $<\n" \
    202 	"	$(CC) $(CFLAGS) -c lex.yy.c\n" \
    203 	"	rm -f lex.yy.c\n" \
    204 	"	mv lex.yy.o $@\n" \
    205 	".l.c:\n" \
    206 	"	$(LEX) $(LFLAGS) $<\n" \
    207 	"	mv lex.yy.c $@\n" \
    208 	".c.a:\n" \
    209 	"	$(CC) -c $(CFLAGS) $<\n" \
    210 	"	$(AR) $(ARFLAGS) $@ $*.o\n" \
    211 	"	rm -f $*.o\n" \
    212 	".c:\n" \
    213 	"	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<\n" \
    214 	".sh:\n" \
    215 	"	cp $< $@\n" \
    216 	"	chmod a+x $@\n"
    217 
    218 #define RULES_2017 \
    219 	".SUFFIXES:.o .c .y .l .a .sh .f\n" \
    220 	".f.o:\n" \
    221 	"	$(FC) $(FFLAGS) -c $<\n" \
    222 	".f.a:\n" \
    223 	"	$(FC) -c $(FFLAGS) $<\n" \
    224 	"	$(AR) $(ARFLAGS) $@ $*.o\n" \
    225 	"	rm -f $*.o\n" \
    226 	".f:\n" \
    227 	"	$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n"
    228 
    229 #define RULES_2024 \
    230 	".SUFFIXES:.o .c .y .l .a .sh\n"
    231 
    232 #define MACROS \
    233 	"CFLAGS=-O1\n" \
    234 	"YACC=yacc\n" \
    235 	"YFLAGS=\n" \
    236 	"LEX=lex\n" \
    237 	"LFLAGS=\n" \
    238 	"AR=ar\n" \
    239 	"ARFLAGS=-rv\n" \
    240 	"LDFLAGS=\n"
    241 
    242 #define MACROS_2017 \
    243 	"CC=c99\n" \
    244 	"FC=fort77\n" \
    245 	"FFLAGS=-O1\n" \
    246 
    247 #define MACROS_2024 \
    248 	"CC=c17\n"
    249 
    250 #define MACROS_EXT \
    251 	"CC=cc\n"
    252 
    253 /*
    254  * Read the built-in rules using a fake fgets-like interface.
    255  */
    256 static char *
    257 mk_getrules(MakeCtx* mc, char *s, int size)
    258 {
    259 	char *r = s;
    260 
    261 	if (mc->rulepos == NULL || *mc->rulepos == '\0') {
    262 		if (mc->rule_idx == 0) {
    263 			mc->rulepos = MACROS;
    264 			mc->rule_idx++;
    265 		} else if (mc->rule_idx == 1) {
    266 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    267 			if (POSIX_2017)
    268 				mc->rulepos = MACROS_2017;
    269 			else if (mc->posix)
    270 				mc->rulepos = MACROS_2024;
    271 			else
    272 				mc->rulepos = MACROS_EXT;
    273 #elif ENABLE_FEATURE_MAKE_POSIX_2024
    274 			mc->rulepos = MACROS_2024;
    275 #else
    276 			mc->rulepos = MACROS_2017;
    277 #endif
    278 			mc->rule_idx++;
    279 		} else if (!norules) {
    280 			if (mc->rule_idx == 2) {
    281 #if ENABLE_FEATURE_MAKE_EXTENSIONS
    282 				mc->rulepos = POSIX_2017 ? RULES_2017 : RULES_2024;
    283 #elif ENABLE_FEATURE_MAKE_POSIX_2024
    284 				mc->rulepos = RULES_2024;
    285 #else
    286 				mc->rulepos = RULES_2017;
    287 #endif
    288 				mc->rule_idx++;
    289 			} else if (mc->rule_idx == 3) {
    290 				mc->rulepos = RULES;
    291 				mc->rule_idx++;
    292 			}
    293 		}
    294 	}
    295 
    296 	if (*mc->rulepos == '\0')
    297 		return NULL;
    298 
    299 	while (--size) {
    300 		if ((*r++ = *mc->rulepos++) == '\n')
    301 			break;
    302 	}
    303 	*r = '\0';
    304 	return s;
    305 }