version 1.71, 2007/09/18 08:31:15 |
version 1.72, 2007/09/18 09:15:04 |
|
|
* if the target had no implicit sources. |
* if the target had no implicit sources. |
*/ |
*/ |
|
|
/* The suffix specifications are *really weird* |
|
* Here is how it works: |
|
* - each time you encounter a .SUFFIX: .s1 .s2 .s3 |
|
* you add the suffixes to the list of known suffixes, keeping it ordered. |
|
* - when you see a |
|
* .s1.s2: |
|
* line, you match it against the known suffixes at this point, and it |
|
* is tagged as a transform rule. |
|
* - when you encounter a .SUFFIX: |
|
* you reset the list of suffixes to empty, but you keep all the transforms |
|
* around. |
|
* - at the end of all Makefiles, you match recognized transforms against |
|
* suffixes existing at this point. |
|
* |
|
* The description of SusV3 is really sketchy, but this is how make works, |
|
* gmake works that way as well. |
|
* |
|
* The only difference is that gmake keeps its transform rules on the main |
|
* target list, so if you define two suffixes and a transform, then resets |
|
* the suffix and define a normal rule with the same name, you'll override |
|
* the transform. |
|
*/ |
|
#include <ctype.h> |
#include <ctype.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
|
#include "make.h" |
#include "make.h" |
#include "stats.h" |
#include "stats.h" |
|
|
static struct ohash suffixes; /* hash of suffixes */ |
/* XXX the suffixes hash is stored using a specific hash function, suitable |
size_t maxLen; /* optimization: remember longest suffix */ |
* for looking up suffixes in reverse. |
static LIST srclist; /* Lst of sources */ |
*/ |
|
static struct ohash suffixes; |
|
|
|
/* We remember the longest suffix, so we don't need to look beyond that. */ |
|
size_t maxLen; |
|
static LIST srclist; |
|
|
|
/* Transforms (.c.o) are stored in another hash, independently from suffixes. |
|
* When make sees a target, it checks whether it's currently parsable as a |
|
* transform (according to the active suffixes). If yes, it's stored as a |
|
* new transform. |
|
* |
|
* XXX |
|
* But transforms DO NOT have a canonical decomposition as a set of suffixes, |
|
* and will be used as necessary later, when looking up implicit rules for |
|
* actual targets. |
|
* |
|
* For instance, a transform .a.b.c can be parsed as .a -> .b.c if suffixes |
|
* .a and .b.c are active, and then LATER, reused as .a.b -> .c if suffixes |
|
* .a.b and .c are active. |
|
*/ |
static struct ohash transforms; |
static struct ohash transforms; |
|
|
static int sNum = 0; /* Counter for assigning suffix numbers */ |
/* conflicts between suffixes are solved by suffix declaration order. */ |
|
static int order = 0; |
|
|
/* |
/* |
* Structure describing an individual suffix. |
* Structure describing an individual suffix. |
*/ |
*/ |
typedef struct Suff_ { |
typedef struct Suff_ { |
size_t nameLen; /* Length of the suffix */ |
size_t nameLen; /* optimisation: strlen(name) */ |
short flags; /* Type of suffix */ |
short flags; |
#define SUFF_INCLUDE 0x01 /* One which is #include'd */ |
#define SUFF_INCLUDE 0x01 /* suffix marked with .INCLUDES keyword */ |
#define SUFF_LIBRARY 0x02 /* One which contains a library */ |
#define SUFF_LIBRARY 0x02 /* suffix marked with .LIBS keyword */ |
#define SUFF_NULL 0x04 /* The empty suffix */ |
#define SUFF_NULL 0x04 /* The empty suffix (normally '', */ |
#define SUFF_EXISTS 0x08 /* So that we don't have to destroy them */ |
/* but see .EMPTY keyword) */ |
|
#define SUFF_ACTIVE 0x08 /* We never destroy suffixes and rules, */ |
|
/* we just deactivate them. */ |
#define SUFF_PATH 0x10 /* False suffix: actually, the path keyword */ |
#define SUFF_PATH 0x10 /* False suffix: actually, the path keyword */ |
LIST searchPath; /* The path along which files of this suffix |
LIST searchPath; /* The path along which files of this suffix |
* may be found */ |
* may be found */ |
int sNum; /* The suffix number */ |
int order; /* order of declaration for conflict |
LIST parents; /* Suffixes we have a transformation to */ |
* resolution. */ |
LIST children; /* Suffixes we have a transformation from */ |
LIST parents; /* List of Suff we have a transformation to */ |
char name[1]; /* The suffix itself */ |
LIST children; /* List of Suff we have a transformation from */ |
|
char name[1]; |
} Suff; |
} Suff; |
|
|
static struct ohash_info suff_info = { |
static struct ohash_info suff_info = { |
offsetof(struct Suff_, name), NULL, hash_alloc, hash_free, element_alloc |
offsetof(struct Suff_, name), NULL, |
|
hash_alloc, hash_free, element_alloc |
}; |
}; |
|
|
/* |
/* |
|
|
static void PrintAddr(void *); |
static void PrintAddr(void *); |
#endif |
#endif |
|
|
/* we usually look at suffixes `backwards', which makes it necessary for |
/* hash functions for the suffixes hash */ |
* us to have a specific hash function that proceeds backwards. |
/* add one char to the hash */ |
*/ |
|
|
|
|
|
static void |
static void |
reverse_hash_add_char(uint32_t *pk, const char *s) |
reverse_hash_add_char(uint32_t *pk, const char *s) |
{ |
{ |
*pk = ((*pk << 2) | (*pk >> 30)) ^ *s; |
*pk = ((*pk << 2) | (*pk >> 30)) ^ *s; |
} |
} |
|
|
|
/* build a full hash from end to start */ |
static uint32_t |
static uint32_t |
reverse_hashi(const char *s, const char **e) |
reverse_hashi(const char *s, const char **e) |
{ |
{ |
|
|
|
|
for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { |
s2 = (Suff *)Lst_Datum(ln); |
s2 = (Suff *)Lst_Datum(ln); |
if (s2->sNum >= s->sNum) |
if (s2->order >= s->order) |
break; |
break; |
} |
} |
|
|
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("inserting %s(%d)...", s->name, s->sNum); |
printf("inserting %s(%d)...", s->name, s->order); |
if (ln == NULL) { |
if (ln == NULL) { |
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("at end of list\n"); |
printf("at end of list\n"); |
Lst_AtEnd(l, s); |
Lst_AtEnd(l, s); |
} else if (s2->sNum != s->sNum) { |
} else if (s2->order != s->order) { |
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("before %s(%d)\n", s2->name, s2->sNum); |
printf("before %s(%d)\n", s2->name, s2->order); |
Lst_Insert(l, ln, s); |
Lst_Insert(l, ln, s); |
} else if (DEBUG(SUFF)) { |
} else if (DEBUG(SUFF)) { |
printf("already there\n"); |
printf("already there\n"); |
|
|
|
|
for (s = ohash_first(&suffixes, &i); s != NULL; |
for (s = ohash_first(&suffixes, &i); s != NULL; |
s = ohash_next(&suffixes, &i)) |
s = ohash_next(&suffixes, &i)) |
s->flags &= ~SUFF_EXISTS; |
s->flags &= ~SUFF_ACTIVE; |
|
|
sNum = 0; |
order = 0; |
maxLen = 0; |
maxLen = 0; |
suffNull = emptySuff; |
suffNull = emptySuff; |
} |
} |
|
|
/* no double suffix in there */ |
/* no double suffix in there */ |
if (p - str <= (ptrdiff_t)maxLen) { |
if (p - str <= (ptrdiff_t)maxLen) { |
target = ohash_find(&suffixes, slot); |
target = ohash_find(&suffixes, slot); |
if (target != NULL && (target->flags & SUFF_EXISTS)) { |
if (target != NULL && (target->flags & SUFF_ACTIVE)) { |
src = find_suffi(str, p); |
src = find_suffi(str, p); |
if (src != NULL && |
if (src != NULL && |
(src->flags & (SUFF_EXISTS | SUFF_PATH))) { |
(src->flags & (SUFF_ACTIVE | SUFF_PATH))) { |
/* XXX even if we find a set of suffixes, we |
/* XXX even if we find a set of suffixes, we |
* have to keep going to find the best one, |
* have to keep going to find the best one, |
* namely, the one whose src appears first in |
* namely, the one whose src appears first in |
* .SUFFIXES |
* .SUFFIXES |
*/ |
*/ |
if (best_src == NULL || |
if (best_src == NULL || |
src->sNum < best_src->sNum) { |
src->order < best_src->order) { |
best_src = src; |
best_src = src; |
best_target = target; |
best_target = target; |
} |
} |
|
|
* we find one. */ |
* we find one. */ |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
src = ohash_find(&suffixes, slot); |
src = ohash_find(&suffixes, slot); |
if (src != NULL && (src->flags & (SUFF_EXISTS | SUFF_PATH))) { |
if (src != NULL && (src->flags & (SUFF_ACTIVE | SUFF_PATH))) { |
best_src = src; |
best_src = src; |
best_target = suffNull; |
best_target = suffNull; |
} |
} |
|
|
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
suff = ohash_find(&suffixes, slot); |
suff = ohash_find(&suffixes, slot); |
if (suff != NULL) |
if (suff != NULL) |
if (best == NULL || suff->sNum < best->sNum) |
if (best == NULL || suff->order < best->order) |
best = suff; |
best = suff; |
if (e - p >= (ptrdiff_t)maxLen) |
if (e - p >= (ptrdiff_t)maxLen) |
break; |
break; |
|
|
static void |
static void |
make_suffix_known(Suff *s) |
make_suffix_known(Suff *s) |
{ |
{ |
if ((s->flags & SUFF_EXISTS) == 0) { |
if ((s->flags & SUFF_ACTIVE) == 0) { |
s->sNum = sNum++; |
s->order = order++; |
s->flags |= SUFF_EXISTS; |
s->flags |= SUFF_ACTIVE; |
if (s->nameLen > maxLen) |
if (s->nameLen > maxLen) |
maxLen = s->nameLen; |
maxLen = s->nameLen; |
} |
} |
|
|
while (p != s) { |
while (p != s) { |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
suff = ohash_find(&suffixes, slot); |
suff = ohash_find(&suffixes, slot); |
if (suff != NULL && (suff->flags & SUFF_EXISTS)) |
if (suff != NULL && (suff->flags & SUFF_ACTIVE)) |
record_possible_suffix(suff, gn, e, srcs, targs); |
record_possible_suffix(suff, gn, e, srcs, targs); |
if (e - p >= (ptrdiff_t)maxLen) |
if (e - p >= (ptrdiff_t)maxLen) |
break; |
break; |
|
|
make_suffix_known(emptySuff); |
make_suffix_known(emptySuff); |
Dir_Concat(&emptySuff->searchPath, defaultPath); |
Dir_Concat(&emptySuff->searchPath, defaultPath); |
ohash_init(&suffixes, 4, &suff_info); |
ohash_init(&suffixes, 4, &suff_info); |
sNum = 0; |
order = 0; |
clear_suffixes(); |
clear_suffixes(); |
special_path_hack(); |
special_path_hack(); |
|
|