diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2007-09-17 12:42:10 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2007-09-17 12:42:10 +0000 |
commit | 04da241c9a9d1947a02599b69c4d28cad730e2ee (patch) | |
tree | 411a70834205a49e35f9401bcb6a7d91905ebc7a /usr.bin/make | |
parent | 623d7eb586551d91075741d88eb155937894af6b (diff) |
rewrite of the basic suffix/target parsing: use hash for suffixes.
Store special targets in target hash, and use them for the parsing.
Use OP_DUMMY flag to mark targets that don't really exist yet, such
as interrupt and default nodes.
Also, .PATHxxx is special in suffixes.
Small tweaks to compat.c, so that run_commands does more stuff after
the fork() (and thus no need to free things).
Remove distinction between local and global jobs.
Diffstat (limited to 'usr.bin/make')
-rw-r--r-- | usr.bin/make/Makefile | 14 | ||||
-rw-r--r-- | usr.bin/make/compat.c | 355 | ||||
-rw-r--r-- | usr.bin/make/engine.c | 264 | ||||
-rw-r--r-- | usr.bin/make/extern.h | 2 | ||||
-rw-r--r-- | usr.bin/make/gnode.h | 133 | ||||
-rw-r--r-- | usr.bin/make/init.c | 4 | ||||
-rw-r--r-- | usr.bin/make/job.c | 310 | ||||
-rw-r--r-- | usr.bin/make/job.h | 4 | ||||
-rw-r--r-- | usr.bin/make/main.c | 22 | ||||
-rw-r--r-- | usr.bin/make/main.h | 4 | ||||
-rw-r--r-- | usr.bin/make/parse.c | 1292 | ||||
-rw-r--r-- | usr.bin/make/suff.c | 1360 | ||||
-rw-r--r-- | usr.bin/make/suff.h | 19 | ||||
-rw-r--r-- | usr.bin/make/targ.c | 195 | ||||
-rw-r--r-- | usr.bin/make/targ.h | 22 |
15 files changed, 1757 insertions, 2243 deletions
diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile index afc59ae3895..c60937fd0ed 100644 --- a/usr.bin/make/Makefile +++ b/usr.bin/make/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.46 2007/09/16 10:39:07 espie Exp $ +# $OpenBSD: Makefile,v 1.47 2007/09/17 12:42:09 espie Exp $ PROG= make CFLAGS+= -I${.OBJDIR} -I${.CURDIR} @@ -15,9 +15,8 @@ CDEFS+=-DHAS_EXTENDED_GETCWD CFLAGS+=${CDEFS} HOSTCFLAGS+=${CDEFS} -SRCS= arch.c buf.c cmd_exec.c compat.c cond.c dir.c direxpand.c \ - engine.c error.c for.c \ - init.c job.c lowparse.c main.c make.c memory.c parse.c \ +SRCS= arch.c buf.c cmd_exec.c compat.c cond.c dir.c direxpand.c engine.c \ + error.c for.c init.c job.c lowparse.c main.c make.c memory.c parse.c \ parsevar.c str.c stats.c suff.c targ.c timestamp.c \ var.c varmodifiers.c varname.c SRCS+= lstAddNew.c lstAppend.c lstConcat.c lstConcatDestroy.c \ @@ -28,10 +27,9 @@ SRCS+= lstAddNew.c lstAppend.c lstConcat.c lstConcatDestroy.c \ CLEANFILES+=generate hashconsts.h generate.o regress.o check CLEANFILES+=${LIBOBJS} libohash.a -CLEANFILES+= varhashconsts.h condhashconsts.h nodehashconsts.h -CLEANFILES+= generate.o generate +CLEANFILES+= varhashconsts.h condhashconsts.h generate.o generate -beforedepend: varhashconsts.h condhashconsts.h +beforedepend: varhashconsts.h condhashconsts.h nodehashconsts.h # may need tweaking if you add variable synonyms or change the hash function MAGICVARSLOTS=77 MAGICCONDSLOTS=65 @@ -57,8 +55,10 @@ regress: check # kludge for people who forget to make depend var.o: varhashconsts.h cond.o: condhashconsts.h +targ.o parse.o: nodehashconsts.h var.ln: varhashconsts.h cond.ln: condhashconsts.h +targ.ln parse.ln: nodehashconsts.h .if make(install) SUBDIR+= PSD.doc diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c index 29e1cb933f9..b9d7f1a75fa 100644 --- a/usr.bin/make/compat.c +++ b/usr.bin/make/compat.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: compat.c,v 1.59 2007/09/17 09:28:36 espie Exp $ */ +/* $OpenBSD: compat.c,v 1.60 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: compat.c,v 1.14 1996/11/06 17:59:01 christos Exp $ */ /* @@ -66,18 +66,13 @@ #include "lst.h" #include "pathnames.h" -/* The following array is used to make a fast determination of which - * characters are interpreted specially by the shell. If a command - * contains any of these characters, it is executed by the shell, not - * directly by us. */ - -static char meta[256]; - -static GNode *ENDNode; static void CompatInterrupt(int); static int CompatRunCommand(LstNode, void *); static void CompatMake(void *, void *); -static int shellneed(char **); +static int run_gnode(GNode *); +static void setup_meta(void); +static char **recheck_command_for_shell(char **); +static void run_command(const char *, bool); static volatile sig_atomic_t interrupted; @@ -88,56 +83,84 @@ CompatInterrupt(int signo) interrupted = signo; } -/*- - *----------------------------------------------------------------------- - * shellneed -- - * - * Results: - * Returns 1 if a specified set of arguments - * must be executed by the shell, - * 0 if it can be run via execve, and -1 if the command can be - * handled internally - * - * Side Effects: - * May modify the process umask - *----------------------------------------------------------------------- - */ -static int -shellneed(char **av) +/* The following array is used to make a fast determination of which + * characters are interpreted specially by the shell. If a command + * contains any of these characters, it is executed by the shell, not + * directly by us. */ +static char meta[256]; + +static void +setup_meta(void) +{ + char *p; + + for (p = "#=|^(){};&<>*?[]:$`\\\n"; *p != '\0'; p++) + meta[(unsigned char) *p] = 1; + /* The null character serves as a sentinel in the string. */ + meta[0] = 1; +} + +static char ** +recheck_command_for_shell(char **av) { char *runsh[] = { - "alias", "cd", "eval", "exec", "exit", "read", "set", "ulimit", - "unalias", "unset", "wait", - NULL + "alias", "cd", "eval", "exit", "read", "set", "ulimit", + "unalias", "unset", "wait", "umask", NULL }; char **p; - /* FIXME most of these ARE actual no-ops */ + /* optimization: if exec cmd, we avoid the intermediate shell */ + if (strcmp(av[0], "exec") == 0) + av++; + for (p = runsh; *p; p++) if (strcmp(av[0], *p) == 0) - return 1; - - if (strcmp(av[0], "umask") == 0) { - long umi; - char *ep = NULL; - mode_t um; - - if (av[1] != NULL) { - umi = strtol(av[1], &ep, 8); - if (ep == NULL) - return 1; - um = umi; - } - else { - um = umask(0); - printf("%o\n", um); - } - (void)umask(um); - return -1; + return NULL; + + return av; +} + +static void +run_command(const char *cmd, bool errCheck) +{ + const char *p; + char *shargv[4]; + char **todo; + + shargv[0] = _PATH_BSHELL; + + shargv[1] = errCheck ? "-ec" : "-c"; + shargv[2] = (char *)cmd; + shargv[3] = NULL; + + todo = shargv; + + + /* Search for meta characters in the command. If there are no meta + * characters, there's no need to execute a shell to execute the + * command. */ + for (p = cmd; !meta[(unsigned char)*p]; p++) + continue; + if (*p == '\0') { + char *bp; + char **av; + int argc; + /* No meta-characters, so probably no need to exec a shell. + * Break the command into words to form an argument vector + * we can execute. */ + av = brk_string(cmd, &argc, &bp); + av = recheck_command_for_shell(av); + if (av != NULL) + todo = av; } + execvp(todo[0], todo); - return 0; + if (errno == ENOENT) + fprintf(stderr, "%s: not found\n", todo[0]); + else + perror(todo[0]); + _exit(1); } /*- @@ -154,24 +177,19 @@ shellneed(char **av) *----------------------------------------------------------------------- */ static int -CompatRunCommand(LstNode cmdNode,/* Command to execute */ - void *gnp) /* Node from which the command came */ +CompatRunCommand(LstNode cmdNode, /* Command to execute */ + void *gnp) /* Node from which the command came */ { - char *cmdStart; /* Start of expanded command */ - char *cp, *bp = NULL; - bool silent; /* Don't print command */ - bool doExecute; /* Execute the command */ - volatile bool errCheck; /* Check errors */ - int reason; /* Reason for child's death */ - int status; /* Description of child's death */ - pid_t cpid; /* Child actually found */ - pid_t stat; /* Status of fork */ - char **volatile av; /* Argument vector for thing to exec */ - int argc; /* Number of arguments in av or 0 if not - * dynamically allocated */ + char *cmdStart; /* Start of expanded command */ + bool silent; /* Don't print command */ + bool doExecute; /* Execute the command */ + bool errCheck; /* Check errors */ + int reason; /* Reason for child's death */ + int status; /* Description of child's death */ + pid_t cpid; /* Child actually found */ + pid_t stat; /* Status of fork */ char *cmd = (char *)Lst_Datum(cmdNode); GNode *gn = (GNode *)gnp; - static char *shargv[4] = { _PATH_BSHELL }; silent = gn->type & OP_SILENT; errCheck = !(gn->type & OP_IGNORE); @@ -179,11 +197,8 @@ CompatRunCommand(LstNode cmdNode,/* Command to execute */ cmdStart = Var_Subst(cmd, &gn->context, false); - /* brk_string will return an argv with a NULL in av[0], thus causing - * execvp to choke and die horribly. Besides, how can we execute a null - * command? In any case, we warn the user that the command expanded to - * nothing (is this the right thing to do?). */ - + /* How can we execute a null command ? we warn the user that the + * command expanded to nothing (is this the right thing to do?). */ if (*cmdStart == '\0') { free(cmdStart); Error("%s expands to empty string", cmd); @@ -192,14 +207,14 @@ CompatRunCommand(LstNode cmdNode,/* Command to execute */ cmd = cmdStart; Lst_Replace(cmdNode, cmdStart); - if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { - Lst_AtEnd(&ENDNode->commands, cmdStart); + if ((gn->type & OP_SAVE_CMDS) && (gn != end_node)) { + Lst_AtEnd(&end_node->commands, cmdStart); + end_node->type &= ~OP_DUMMY; return 1; } else if (strcmp(cmdStart, "...") == 0) { gn->type |= OP_SAVE_CMDS; return 1; } - for (;; cmd++) { if (*cmd == '@') silent = DEBUG(LOUD) ? false : true; @@ -210,80 +225,29 @@ CompatRunCommand(LstNode cmdNode,/* Command to execute */ else break; } - while (isspace(*cmd)) cmd++; - - /* Search for meta characters in the command. If there are no meta - * characters, there's no need to execute a shell to execute the - * command. */ - for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { - continue; - } - /* Print the command before echoing if we're not supposed to be quiet * for this one. We also print the command if -n given. */ if (!silent || noExecute) { printf("%s\n", cmd); fflush(stdout); } - /* If we're not supposed to execute any commands, this is as far as * we go... */ if (!doExecute) return 1; - if (*cp != '\0') { - /* If *cp isn't the null character, we hit a "meta" character - * and need to pass the command off to the shell. We give the - * shell the -e flag as well as -c if it's supposed to exit - * when it hits an error. */ - - shargv[1] = errCheck ? "-ec" : "-c"; - shargv[2] = cmd; - shargv[3] = NULL; - av = shargv; - argc = 0; - } else { - /* No meta-characters, so probably no need to exec a shell. - * Break the command into words to form an argument vector - * we can execute. */ - av = brk_string(cmd, &argc, &bp); - switch (shellneed(av)) { - case -1: /* handled internally */ - free(bp); - free(av); - return 1; - case 1: - shargv[1] = errCheck ? "-ec" : "-c"; - shargv[2] = cmd; - shargv[3] = NULL; - free(av); - free(bp); - bp = NULL; - av = shargv; - argc = 0; - break; - default: /* nothing needed */ - break; - } - } - /* Fork and execute the single command. If the fork fails, we abort. */ - cpid = fork(); - if (cpid == -1) + switch (cpid = fork()) { + case -1: Fatal("Could not fork"); - if (cpid == 0) { - execvp(av[0], av); - if (errno == ENOENT) - fprintf(stderr, "%s: not found\n", av[0]); - else - perror(av[0]); - _exit(1); - } - if (bp) { - free(av); - free(bp); + /*NOTREACHED*/ + case 0: + run_command(cmd, errCheck); + /*NOTREACHED*/ + default: + break; } free(cmdStart); Lst_Replace(cmdNode, NULL); @@ -305,7 +269,7 @@ CompatRunCommand(LstNode cmdNode,/* Command to execute */ else if (WIFEXITED(reason)) { status = WEXITSTATUS(reason); /* exited */ if (status != 0) - printf("*** Error code %d", status); + printf("*** Error code %d", status); } else { status = WTERMSIG(reason); /* signaled */ printf("*** Signal %d", status); @@ -320,9 +284,9 @@ CompatRunCommand(LstNode cmdNode,/* Command to execute */ * but let others continue. */ printf(" (continuing)\n"); } else { - /* Continue executing commands for this - * target. If we return 0, this will - * happen... */ + /* Continue executing commands for + * this target. If we return 0, + * this will happen... */ printf(" (ignored)\n"); status = 0; } @@ -335,25 +299,33 @@ CompatRunCommand(LstNode cmdNode,/* Command to execute */ /* This is reached only if interrupted */ if (!Targ_Precious(gn)) { - char *file = Varq_Value(TARGET_INDEX, gn); + char *file = Varq_Value(TARGET_INDEX, gn); if (!noExecute && eunlink(file) != -1) Error("*** %s removed\n", file); } if (interrupted == SIGINT) { - GNode *i = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGQUIT, SIG_IGN); interrupted = 0; - if (i != NULL) - Lst_ForEachNodeWhile(&i->commands, CompatRunCommand, i); + run_gnode(interrupt_node); exit(SIGINT); } exit(interrupted); } +static int +run_gnode(GNode *gn) +{ + if (gn != NULL && (gn->type & OP_DUMMY) == 0) { + Lst_ForEachNodeWhile(&gn->commands, CompatRunCommand, gn); + return gn->made; + } else + return NOSUCHNODE; +} + /*- *----------------------------------------------------------------------- * CompatMake -- @@ -379,11 +351,12 @@ CompatMake(void *gnp, /* The node to make */ Make_HandleUse(gn, pgn); } else if (gn->made == UNMADE) { /* First mark ourselves to be made, then apply whatever - * transformations the suffix module thinks are necessary. Once - * that's done, we can descend and make all our children. If - * any of them has an error but the -k flag was given, our - * 'make' field will be set false again. This is our signal to - * not attempt to do anything but abort our parent as well. */ + * transformations the suffix module thinks are necessary. + * Once that's done, we can descend and make all our children. + * If any of them has an error but the -k flag was given, + * our 'make' field will be set false again. This is our + * signal to not attempt to do anything but abort our + * parent as well. */ gn->make = true; gn->made = BEINGMADE; Suff_FindDeps(gn); @@ -401,11 +374,11 @@ CompatMake(void *gnp, /* The node to make */ /* All the children were made ok. Now cmtime contains the * modification time of the newest child, we need to find out - * if we exist and when we were modified last. The criteria for - * datedness are defined by the Make_OODate function. */ + * if we exist and when we were modified last. The criteria + * for datedness are defined by the Make_OODate function. */ if (DEBUG(MAKE)) printf("Examining %s...", gn->name); - if (! Make_OODate(gn)) { + if (!Make_OODate(gn)) { gn->made = UPTODATE; if (DEBUG(MAKE)) printf("up-to-date.\n"); @@ -413,41 +386,40 @@ CompatMake(void *gnp, /* The node to make */ } else if (DEBUG(MAKE)) printf("out-of-date.\n"); - /* If the user is just seeing if something is out-of-date, exit - * now to tell him/her "yes". */ + /* If the user is just seeing if something is out-of-date, + * exit now to tell him/her "yes". */ if (queryFlag) exit(-1); - /* We need to be re-made. We also have to make sure we've got a - * $? variable. To be nice, we also define the $> variable - * using Make_DoAllVar(). */ + /* We need to be re-made. We also have to make sure we've + * got a $? variable. To be nice, we also define the $> + * variable using Make_DoAllVar(). */ Make_DoAllVar(gn); /* Alter our type to tell if errors should be ignored or things * should not be printed so CompatRunCommand knows what to do. - * */ + */ if (Targ_Ignore(gn)) gn->type |= OP_IGNORE; if (Targ_Silent(gn)) gn->type |= OP_SILENT; if (Job_CheckCommands(gn, Fatal)) { - /* Our commands are ok, but we still have to worry - * about the -t flag... */ - if (!touchFlag) - Lst_ForEachNodeWhile(&gn->commands, - CompatRunCommand, gn); - else - Job_Touch(gn, gn->type & OP_SILENT); + /* Our commands are ok, but we still have to worry + * about the -t flag... */ + if (!touchFlag) + run_gnode(gn); + else + Job_Touch(gn, gn->type & OP_SILENT); } else gn->made = ERROR; if (gn->made != ERROR) { /* If the node was made successfully, mark it so, - * update its modification time and timestamp all its - * parents. Note that for .ZEROTIME targets, the - * timestamping isn't done. This is to keep its state - * from affecting that of its parent. */ + * update its modification time and timestamp all + * its parents. + * This is to keep its state from affecting that of + * its parent. */ gn->made = MADE; /* This is what Make does and it's actually a good * thing, as it allows rules like @@ -455,17 +427,13 @@ CompatMake(void *gnp, /* The node to make */ * cmp -s y.tab.h parse.h || cp y.tab.h parse.h * * to function as intended. Unfortunately, thanks to - * the stateless nature of NFS (and the speed of this - * program), there are times when the modification time - * of a file created on a remote machine will not be - * modified before the stat() implied by the Dir_MTime - * occurs, thus leading us to believe that the file is - * unchanged, wreaking havoc with files that depend on - * this one. - * - * I have decided it is better to make too much than to - * make too little, so this stuff is commented out - * unless you're sure it's ok. -- ardeb 1/12/88 + * the stateless nature of NFS (and the speed of + * this program), there are times when the + * modification time of a file created on a remote + * machine will not be modified before the stat() + * implied by the Dir_MTime occurs, thus leading us + * to believe that the file is unchanged, wreaking + * havoc with files that depend on this one. */ if (noExecute || is_out_of_date(Dir_MTime(gn))) gn->mtime = now; @@ -493,8 +461,8 @@ CompatMake(void *gnp, /* The node to make */ exit(1); } } else if (gn->made == ERROR) - /* Already had an error when making this beastie. Tell the - * parent to abort. */ + /* Already had an error when making this beastie. Tell the parent + * to abort. */ pgn->make = false; else { if (Lst_Member(&gn->iParents, pgn) != NULL) { @@ -526,32 +494,21 @@ CompatMake(void *gnp, /* The node to make */ void Compat_Run(Lst targs) /* List of target nodes to re-create */ { - char *cp; /* Pointer to string of shell meta-characters */ - GNode *gn = NULL; /* Current root target */ - int errors; /* Number of targets not remade due to errors */ + GNode *gn = NULL; /* Current root target */ + int errors; /* Number of targets not remade due to errors */ signal(SIGINT, CompatInterrupt); signal(SIGTERM, CompatInterrupt); signal(SIGHUP, CompatInterrupt); signal(SIGQUIT, CompatInterrupt); - for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) - meta[(unsigned char) *cp] = 1; - /* The null character serves as a sentinel in the string. */ - meta[0] = 1; - - ENDNode = Targ_FindNode(".END", TARG_CREATE); + setup_meta(); /* If the user has defined a .BEGIN target, execute the commands * attached to it. */ if (!queryFlag) { - gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); - if (gn != NULL) { - Lst_ForEachNodeWhile(&gn->commands, CompatRunCommand, - gn); - if (gn->made == ERROR) { - printf("\n\nStop.\n"); - exit(1); - } + if (run_gnode(begin_node) == ERROR) { + printf("\n\nStop.\n"); + exit(1); } } @@ -560,9 +517,10 @@ Compat_Run(Lst targs) /* List of target nodes to re-create */ * in one of several states: * UPTODATE gn was already up-to-date * MADE gn was recreated successfully - * ERROR An error occurred while gn was being created + * ERROR An error occurred while gn was being + * created * ABORTED gn was not remade because one of its - * inferiors could not be made due to errors. + * inferiors could not be made due to errors. */ errors = 0; while ((gn = (GNode *)Lst_DeQueue(targs)) != NULL) { @@ -579,6 +537,5 @@ Compat_Run(Lst targs) /* List of target nodes to re-create */ /* If the user has defined a .END target, run its commands. */ if (errors == 0) - Lst_ForEachNodeWhile(&ENDNode->commands, CompatRunCommand, - ENDNode); + run_gnode(end_node); } diff --git a/usr.bin/make/engine.c b/usr.bin/make/engine.c index 960b7b2bc3b..4dba6633604 100644 --- a/usr.bin/make/engine.c +++ b/usr.bin/make/engine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: engine.c,v 1.8 2007/09/17 12:19:11 espie Exp $ */ +/* $OpenBSD: engine.c,v 1.9 2007/09/17 12:42:09 espie Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. * Copyright (c) 1988, 1989 by Adam de Boor @@ -51,35 +51,22 @@ #include "lst.h" #include "timestamp.h" #include "make.h" -#include "main.h" static void MakeTimeStamp(void *, void *); static void MakeAddAllSrc(void *, void *); static int rewrite_time(const char *); -/*- - *----------------------------------------------------------------------- - * Job_CheckCommands -- - * Make sure the given node has all the commands it needs. - * - * Results: - * true if the commands list is/was ok. - * - * Side Effects: - * The node will have commands from the .DEFAULT rule added to it - * if it needs them. - *----------------------------------------------------------------------- - */ bool Job_CheckCommands(GNode *gn, void (*abortProc)(char *, ...)) { if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands) && - (gn->type & OP_LIB) == 0) { + (gn->type & (OP_NODEFAULT | OP_LIB)) == 0) { /* * No commands. Look for .DEFAULT rule from which we might infer * commands */ - if (DEFAULT != NULL && !Lst_IsEmpty(&DEFAULT->commands)) { + if ((DEFAULT->type & OP_DUMMY) == 0 && + !Lst_IsEmpty(&DEFAULT->commands)) { /* * Make only looks for a .DEFAULT if the node was never * the target of an operator, so that's what we do too. @@ -145,24 +132,13 @@ rewrite_time(const char *name) return 0; } -/*- - *----------------------------------------------------------------------- - * Job_Touch -- - * Touch the given target. Called by JobStart when the -t flag was - * given - * - * Side Effects: - * The data modification of the file is changed. In addition, if the - * file did not exist, it is created. - *----------------------------------------------------------------------- - */ void Job_Touch(GNode *gn, bool silent) { if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { /* - * .JOIN, .USE and .OPTIONAL targets are "virtual" - * targets and, as such, shouldn't really be created. + * .JOIN, .USE, and .OPTIONAL targets are "virtual" targets + * and, as such, shouldn't really be created. */ return; } @@ -189,22 +165,11 @@ Job_Touch(GNode *gn, bool silent) "*** couldn't touch %s: %s", file, strerror(errno)); (void)fflush(stdout); - } + } } } } -/*- - *----------------------------------------------------------------------- - * Make_TimeStamp -- - * Set the cmtime field of a parent node based on the mtime stamp in its - * child. - * - * Side Effects: - * The cmtime of the parent node will be changed if the mtime - * field of the child is greater than it. - *----------------------------------------------------------------------- - */ void Make_TimeStamp(GNode *parent, GNode *child) { @@ -212,29 +177,8 @@ Make_TimeStamp(GNode *parent, GNode *child) parent->cmtime = child->mtime; } -/*- - *----------------------------------------------------------------------- - * Make_HandleUse -- - * Function called by Make_Run and SuffApplyTransform on the downward - * pass to handle .USE and transformation nodes. A callback function - * for Lst_ForEach, it implements the .USE and transformation - * functionality by copying the node's commands, type flags - * and children to the parent node. Should be called before the - * children are enqueued to be looked at by MakeAddChild. - * - * A .USE node is much like an explicit transformation rule, except - * its commands are always added to the target node, even if the - * target already has commands. - * - * Side Effects: - * Children and commands may be added to the parent and the parent's - * type may be changed. - * - *----------------------------------------------------------------------- - */ void -Make_HandleUse( - GNode *cgn, /* The .USE node */ +Make_HandleUse(GNode *cgn, /* The .USE node */ GNode *pgn) /* The target of the .USE node */ { GNode *gn; /* A child of the .USE node */ @@ -242,8 +186,8 @@ Make_HandleUse( if (cgn->type & (OP_USE|OP_TRANSFORM)) { if ((cgn->type & OP_USE) || Lst_IsEmpty(&pgn->commands)) { - /* .USE or transformation and target has no commands -- - * append the child's commands to the parent. */ + /* .USE or transformation and target has no commands + * -- append the child's commands to the parent. */ Lst_Concat(&pgn->commands, &cgn->commands); } @@ -264,97 +208,55 @@ Make_HandleUse( * unmade children in the parent... We also remove the child * from the parent's list to accurately reflect the number of * decent children the parent has. This is used by Make_Run to - * decide whether to queue the parent or examine its - * children... + * decide whether to queue the parent or examine its children... */ - if (cgn->type & OP_USE) { + if (cgn->type & OP_USE) pgn->unmade--; - } } } -/*- - *----------------------------------------------------------------------- - * MakeAddAllSrc -- - * Add a child's name to the ALLSRC and OODATE variables of the given - * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only - * if it has not been given the .EXEC, .USE or .INVISIBLE attributes. - * .EXEC and .USE children are very rarely going to be files, so... - * A child is added to the OODATE variable if its modification time is - * later than that of its parent, as defined by Make, except if the - * parent is a .JOIN node. In that case, it is only added to the OODATE - * variable if it was actually made (since .JOIN nodes don't have - * modification times, the comparison is rather unfair...).. - * - * Side Effects: - * The ALLSRC variable for the given node is extended. - *----------------------------------------------------------------------- - */ static void -MakeAddAllSrc( - void *cgnp, /* The child to add */ - void *pgnp) /* The parent to whose ALLSRC variable it should be */ - /* added */ +MakeAddAllSrc(void *cgnp, void *pgnp) { - GNode *cgn = (GNode *)cgnp; - GNode *pgn = (GNode *)pgnp; - if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) { - const char *child; + GNode *child = (GNode *)cgnp; + GNode *parent = (GNode *)pgnp; + if ((child->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) { + const char *target; - if (OP_NOP(cgn->type) || - (child = Varq_Value(TARGET_INDEX, cgn)) == NULL) { + if (OP_NOP(child->type) || + (target = Varq_Value(TARGET_INDEX, child)) == NULL) { /* * this node is only source; use the specific pathname * for it */ - child = cgn->path != NULL ? cgn->path : cgn->name; + target = child->path != NULL ? child->path : + child->name; } - Varq_Append(ALLSRC_INDEX, child, pgn); - if (pgn->type & OP_JOIN) { - if (cgn->made == MADE) { - Varq_Append(OODATE_INDEX, child, pgn); - } - } else if (is_strictly_before(pgn->mtime, cgn->mtime) || - (!is_strictly_before(cgn->mtime, now) && - cgn->made == MADE)) { + Varq_Append(ALLSRC_INDEX, target, parent); + if (parent->type & OP_JOIN) { + if (child->made == MADE) + Varq_Append(OODATE_INDEX, target, parent); + } else if (is_strictly_before(parent->mtime, child->mtime) || + (!is_strictly_before(child->mtime, now) && + child->made == MADE)) { /* * It goes in the OODATE variable if the parent is * younger than the child or if the child has been * modified more recently than the start of the make. - * This is to keep pmake from getting confused if - * something else updates the parent after the make - * starts (shouldn't happen, I know, but sometimes it - * does). In such a case, if we've updated the kid, the - * parent is likely to have a modification time later - * than that of the kid and anything that relies on the - * OODATE variable will be hosed. - * + * This is to keep make from getting confused if + * something else updates the parent after the + * make starts (shouldn't happen, I know, but sometimes + * it does). In such a case, if we've updated the kid, + * the parent is likely to have a modification time + * later than that of the kid and anything that relies + * on the OODATE variable will be hosed. */ - Varq_Append(OODATE_INDEX, child, pgn); + Varq_Append(OODATE_INDEX, target, parent); } } } -/*- - *----------------------------------------------------------------------- - * Make_DoAllVar -- - * Set up the ALLSRC and OODATE variables. Sad to say, it must be - * done separately, rather than while traversing the graph. This is - * because Make defined OODATE to contain all sources whose modification - * times were later than that of the target, *not* those sources that - * were out-of-date. Since in both compatibility and native modes, - * the modification time of the parent isn't found until the child - * has been dealt with, we have to wait until now to fill in the - * variable. As for ALLSRC, the ordering is important and not - * guaranteed when in native mode, so it must be set here, too. - * - * Side Effects: - * The ALLSRC and OODATE variables of the given node is filled in. - * If the node is a .JOIN node, its TARGET variable will be set to - * match its ALLSRC variable. - *----------------------------------------------------------------------- - */ void Make_DoAllVar(GNode *gn) { @@ -371,35 +273,15 @@ Make_DoAllVar(GNode *gn) /* Wrapper to call Make_TimeStamp from a forEach loop. */ static void -MakeTimeStamp( - void *pgn, /* the current parent */ - void *cgn) /* the child we've just examined */ +MakeTimeStamp(void *parent, void *child) { - Make_TimeStamp((GNode *)pgn, (GNode *)cgn); + Make_TimeStamp((GNode *)parent, (GNode *)child); } -/*- - *----------------------------------------------------------------------- - * Make_OODate -- - * See if a given node is out of date with respect to its sources. - * Used by Make_Run when deciding which nodes to place on the - * toBeMade queue initially and by Make_Update to screen out USE and - * EXEC nodes. In the latter case, however, any other sort of node - * must be considered out-of-date since at least one of its children - * will have been recreated. - * - * Results: - * true if the node is out of date. false otherwise. - * - * Side Effects: - * The mtime field of the node and the cmtime field of its parents - * will/may be changed. - *----------------------------------------------------------------------- - */ bool -Make_OODate(GNode *gn) /* the node to check */ +Make_OODate(GNode *gn) { - bool oodate; + bool oodate; /* * Certain types of targets needn't even be sought as their datedness @@ -408,47 +290,38 @@ Make_OODate(GNode *gn) /* the node to check */ if ((gn->type & (OP_JOIN|OP_USE|OP_EXEC)) == 0) { (void)Dir_MTime(gn); if (DEBUG(MAKE)) { - if (!is_out_of_date(gn->mtime)) { + if (!is_out_of_date(gn->mtime)) printf("modified %s...", time_to_string(gn->mtime)); - } else { + else printf("non-existent..."); - } } } /* * A target is remade in one of the following circumstances: - * its modification time is smaller than that of its youngest child - * and it would actually be run (has commands or type OP_NOP) - * it's the object of a force operator - * it has no children, was on the lhs of an operator and doesn't - * exist already. + * - its modification time is smaller than that of its youngest child + * and it would actually be run (has commands or type OP_NOP) + * - it's the object of a force operator + * - it has no children, was on the lhs of an operator and doesn't + * exist already. * * Libraries are only considered out-of-date if the archive module says * they are. - * - * These weird rules are brought to you by Backward-Compatibility and - * the strange people who wrote 'Make'. */ if (gn->type & OP_USE) { /* * If the node is a USE node it is *never* out of date * no matter *what*. */ - if (DEBUG(MAKE)) { + if (DEBUG(MAKE)) printf(".USE node..."); - } oodate = false; } else if ((gn->type & OP_LIB) && Arch_IsLib(gn)) { - if (DEBUG(MAKE)) { - printf("library..."); - } - - /* - * always out of date if no children and :: target - */ + if (DEBUG(MAKE)) + printf("library..."); + /* always out of date if no children and :: target */ oodate = Arch_LibOODate(gn) || (is_out_of_date(gn->cmtime) && (gn->type & OP_DOUBLEDEP)); } else if (gn->type & OP_JOIN) { @@ -456,56 +329,43 @@ Make_OODate(GNode *gn) /* the node to check */ * A target with the .JOIN attribute is only considered * out-of-date if any of its children was out-of-date. */ - if (DEBUG(MAKE)) { + if (DEBUG(MAKE)) printf(".JOIN node..."); - } oodate = gn->childMade; } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { /* - * A node which is the object of the force (!) operator or - * which has the .EXEC attribute is always considered - * out-of-date. + * A node which is the object of the force (!) operator or which + * has the .EXEC attribute is always considered out-of-date. */ if (DEBUG(MAKE)) { - if (gn->type & OP_FORCE) { + if (gn->type & OP_FORCE) printf("! operator..."); - } else if (gn->type & OP_PHONY) { + else if (gn->type & OP_PHONY) printf(".PHONY node..."); - } else { + else printf(".EXEC node..."); - } } oodate = true; } else if (is_strictly_before(gn->mtime, gn->cmtime) || - (is_out_of_date(gn->cmtime) && + (is_out_of_date(gn->cmtime) && (is_out_of_date(gn->mtime) || (gn->type & OP_DOUBLEDEP)))) { /* * A node whose modification time is less than that of its * youngest child or that has no children (cmtime == * OUT_OF_DATE) and either doesn't exist (mtime == OUT_OF_DATE) - * or was the object of a :: operator is out-of-date. Why? - * Because that's the way Make does it. + * or was the object of a :: operator is out-of-date. */ if (DEBUG(MAKE)) { - if (is_strictly_before(gn->mtime, gn->cmtime)) { + if (is_strictly_before(gn->mtime, gn->cmtime)) printf("modified before source..."); - } else if (is_out_of_date(gn->mtime)) { + else if (is_out_of_date(gn->mtime)) printf("non-existent and no sources..."); - } else { + else printf(":: operator and no sources..."); - } } oodate = true; } else { -#if 0 - /* WHY? */ - if (DEBUG(MAKE)) { - printf("source %smade...", gn->childMade ? "" : "not "); - } - oodate = gn->childMade; -#else oodate = false; -#endif /* 0 */ } /* diff --git a/usr.bin/make/extern.h b/usr.bin/make/extern.h index 57681882d54..4ea798093aa 100644 --- a/usr.bin/make/extern.h +++ b/usr.bin/make/extern.h @@ -2,7 +2,7 @@ #define EXTERN_H /* $OpenPackages$ */ -/* $OpenBSD: extern.h,v 1.40 2007/09/17 12:01:16 espie Exp $ */ +/* $OpenBSD: extern.h,v 1.41 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: nonints.h,v 1.12 1996/11/06 17:59:19 christos Exp $ */ /*- diff --git a/usr.bin/make/gnode.h b/usr.bin/make/gnode.h index a4ce27b1ce6..7d5f1770495 100644 --- a/usr.bin/make/gnode.h +++ b/usr.bin/make/gnode.h @@ -1,7 +1,7 @@ #ifndef GNODE_H #define GNODE_H /* $OpenPackages$ */ -/* $OpenBSD: gnode.h,v 1.4 2001/11/23 23:42:45 deraadt Exp $ */ +/* $OpenBSD: gnode.h,v 1.5 2007/09/17 12:42:09 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -67,61 +67,78 @@ struct Suff_; * 17) a Lst of strings that are commands to be given to a shell * to create this target. */ + +#define UNMADE 0 +#define BEINGMADE 1 +#define MADE 2 +#define UPTODATE 3 +#define ERROR 4 +#define ABORTED 5 +#define CYCLE 6 +#define ENDCYCLE 7 +#define NOSUCHNODE 8 + +#define SPECIAL_NONE 0 +#define SPECIAL_PATH 21 +#define SPECIAL_MASK 63 +#define SPECIAL_TARGET 64 +#define SPECIAL_SOURCE 128 +#define SPECIAL_TARGETSOURCE (SPECIAL_TARGET|SPECIAL_SOURCE) + struct GNode_ { - char *path; /* The full pathname of the file */ - int type; /* Its type (see the OP flags, below) */ - int order; /* Its wait weight */ - - bool make; /* true if this target needs to be remade */ - enum { - UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED, - CYCLE, ENDCYCLE - } made; /* Set to reflect the state of processing - * on this node: - * UNMADE - Not examined yet - * BEINGMADE - Target is already being made. - * Indicates a cycle in the graph. (compat - * mode only) - * MADE - Was out-of-date and has been made - * UPTODATE - Was already up-to-date - * ERROR - An error occurred while it was being - * made (used only in compat mode) - * ABORTED - The target was aborted due to - * an error making an inferior (compat). - * CYCLE - Marked as potentially being part of - * a graph cycle. If we come back to a - * node marked this way, it is printed - * and 'made' is changed to ENDCYCLE. - * ENDCYCLE - the cycle has been completely - * printed. Go back and unmark all its - * members. - */ - bool childMade; /* true if one of this target's children was - * made */ - int unmade; /* The number of unmade children */ - - TIMESTAMP mtime; /* Its modification time */ - TIMESTAMP cmtime; /* The modification time of its youngest - * child */ - - LIST iParents; /* Links to parents for which this is an - * implied source, if any */ - LIST cohorts; /* Other nodes for the :: operator */ - LIST parents; /* Nodes that depend on this one */ - LIST children; /* Nodes on which this one depends */ - LIST successors; /* Nodes that must be made after this one */ - LIST preds; /* Nodes that must be made before this one */ - - SymTable context; /* The local variables */ - unsigned long lineno; /* First line number of commands. */ - const char * fname; /* File name of commands. */ - LIST commands; /* Creation commands */ - LstNode current; /* Current command, for job */ - - struct Suff_ *suffix; /* Suffix for the node (determined by - * Suff_FindDeps and opaque to everyone - * but the Suff module) */ - char name[1]; /* The target's name */ + int special_op; /* special op to apply */ + unsigned char special;/* type of special node */ + char make; /* true if this target needs to be remade */ + char childMade; /* true if one of this target's children was + * made */ + char made; /* Set to reflect the state of processing + * on this node: + * UNMADE - Not examined yet + * BEINGMADE - Target is already being made. + * Indicates a cycle in the graph. (compat + * mode only) + * MADE - Was out-of-date and has been made + * UPTODATE - Was already up-to-date + * ERROR - An error occurred while it was being + * made (used only in compat mode) + * ABORTED - The target was aborted due to + * an error making an inferior (compat). + * CYCLE - Marked as potentially being part of + * a graph cycle. If we come back to a + * node marked this way, it is printed + * and 'made' is changed to ENDCYCLE. + * ENDCYCLE - the cycle has been completely + * printed. Go back and unmark all its + * members. + */ + char *path; /* The full pathname of the file */ + int type; /* Its type (see the OP flags, below) */ + int order; /* Its wait weight */ + + int unmade; /* The number of unmade children */ + + TIMESTAMP mtime; /* Its modification time */ + TIMESTAMP cmtime; /* The modification time of its youngest + * child */ + + LIST iParents; /* Links to parents for which this is an + * implied source, if any */ + LIST cohorts; /* Other nodes for the :: operator */ + LIST parents; /* Nodes that depend on this one */ + LIST children; /* Nodes on which this one depends */ + LIST successors; /* Nodes that must be made after this one */ + LIST preds; /* Nodes that must be made before this one */ + + SymTable context; /* The local variables */ + unsigned long lineno;/* First line number of commands. */ + const char *fname; /* File name of commands. */ + LIST commands; /* Creation commands */ + LstNode current; /* Current command, for job */ + + struct Suff_ *suffix;/* Suffix for the node (determined by + * Suff_FindDeps and opaque to everyone + * but the Suff module) */ + char name[1]; /* The target's name */ }; /* @@ -151,7 +168,7 @@ struct GNode_ { #define OP_PRECIOUS 0x00000080 /* Don't remove the target when * interrupted */ #define OP_SILENT 0x00000100 /* Don't echo commands when executed */ -#define OP_MAKE 0x00000200 /* Target is a recurrsive make so its +#define OP_MAKE 0x00000200 /* Target is a recursive make so its * commands should always be executed when * it is out of date, regardless of the * state of the -n or -t flags */ @@ -166,6 +183,10 @@ struct GNode_ { * target' processing in parse.c */ #define OP_PHONY 0x00010000 /* Not a file target; run always */ #define OP_NOPATH 0x00020000 /* Don't search for file in the path */ +#define OP_NODEFAULT 0x00040000 /* Special node that never needs */ + /* DEFAULT commands applied */ +#define OP_DUMMY 0x00080000 /* node was created by default, but it */ + /* does not really exist. */ /* Attributes applied by PMake */ #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ #define OP_MEMBER 0x40000000 /* Target is a member of an archive */ diff --git a/usr.bin/make/init.c b/usr.bin/make/init.c index 231e3fe968f..21d2c89ae26 100644 --- a/usr.bin/make/init.c +++ b/usr.bin/make/init.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: init.c,v 1.3 2006/05/06 10:52:34 espie Exp $ */ +/* $OpenBSD: init.c,v 1.4 2007/09/17 12:42:09 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -44,6 +44,7 @@ Init(void) { Init_Timestamp(); Init_Stats(); + Targ_Init(); Dir_Init(); /* Initialize directory structures so -I flags * can be processed correctly */ Parse_Init(); /* Need to initialize the paths of #include @@ -51,7 +52,6 @@ Init(void) Var_Init(); /* As well as the lists of variables for * parsing arguments */ Arch_Init(); - Targ_Init(); Suff_Init(); } diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index 1105768e8bf..e0e2bf91e75 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: job.c,v 1.77 2007/09/17 12:03:40 espie Exp $ */ +/* $OpenBSD: job.c,v 1.78 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */ /* @@ -48,8 +48,6 @@ * frequently to keep the whole make going at * a decent clip, since job table entries aren't * removed until their process is caught this way. - * Its single argument is true if the function - * should block waiting for a child to terminate. * * Job_CatchOutput Print any output our children have produced. * Should also be called fairly frequently to @@ -132,11 +130,11 @@ * commands. * 4) An FILE* for writing out the commands. This is only * used before the job is actually started. - * 5) Things used for handling the shell's output. + * 5) Things used for handling the shell's output. * the output is being caught via a pipe and * the descriptors of our pipe, an array in which output is line * buffered and the current position in that buffer are all - * maintained for each job. + * maintained for each job. * 6) An identifier provided by and for the exclusive use of the * Rmt module. * 7) A word of flags which determine how the module handles errors, @@ -162,17 +160,17 @@ typedef struct Job_ { short flags; /* Flags to control treatment of job */ #define JOB_IGNERR 0x001 /* Ignore non-zero exits */ #define JOB_SILENT 0x002 /* no output */ -#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally - * if we can't export it and maxLocal is 0 */ -#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing - * commands */ +#define JOB_SPECIAL 0x004 /* Target is a special one. i.e., always run */ + /* it even when the table is full */ +#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing */ + /* commands */ #define JOB_FIRST 0x020 /* Job is first job for the node */ #define JOB_RESTART 0x080 /* Job needs to be completely restarted */ -#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, - * for some reason */ -#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. - * Used to avoid infinite recursion between - * JobFinish and JobRestart */ +#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, */ + /* for some reason */ +#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job */ + /* Used to avoid infinite recursion between */ + /* JobFinish and JobRestart */ int inPipe; /* Input side of pipe associated * with job's output channel */ int outPipe; /* Output side of pipe associated with @@ -183,6 +181,7 @@ typedef struct Job_ { int curPos; /* Current position in op_outBuf */ } Job; + /* * error handling variables */ @@ -198,13 +197,6 @@ static int aborting = 0; /* why is the make aborting? */ */ #define FILENO(a) ((unsigned) fileno(a)) -/* - * post-make command processing. The node postCommands is really just the - * .END target but we keep it around to avoid having to search for it - * all the time. - */ -static GNode *postCommands; /* node containing commands to execute when - * everything else is done */ static int numCommands; /* The number of commands actually printed * for a target. Should this number be * 0, no shell will be executed. */ @@ -235,16 +227,11 @@ static char tfile[sizeof(TMPPAT)]; static const char *shellPath = _PATH_BSHELL; static const char *shellName = "sh"; + static int maxJobs; /* The most children we can run at once */ -static int maxLocal; /* The most local ones we can have */ static int nJobs = 0; /* The number of children currently running */ -static int nLocal; /* The number of local children */ static LIST jobs; /* The structures that describe them */ -static bool jobFull; /* Flag to tell when the job table is full. It - * is set true when (1) the total number of - * running jobs equals the maximum allowed or - * (2) a job can only be run locally, but - * nLocal equals maxLocal */ +static bool jobFull; /* Flag to tell when the job table is full. */ static fd_set *outputsp; /* Set of descriptors of pipes connected to * the output channels of children */ static int outputsn; @@ -539,7 +526,7 @@ DBPRINTF(Job *job, const char *fmt, ...) * If the command is just "..." we take all future commands for this * job to be commands to be executed once the entire graph has been * made and return non-zero to signal that the end of the commands - * was reached. These commands are later attached to the postCommands + * was reached. These commands are later attached to the end_node * node and executed by Job_End when all things are done. * This function is called from JobStart via Lst_Find * @@ -555,20 +542,20 @@ DBPRINTF(Job *job, const char *fmt, ...) *----------------------------------------------------------------------- */ static int -JobPrintCommand(LstNode cmdNode, /* command string to print */ - void *jobp) /* job for which to print it */ +JobPrintCommand(LstNode cmdNode, /* command string to print */ + void *jobp) /* job for which to print it */ { - bool noSpecials; /* true if we shouldn't worry about - * inserting special commands into - * the input stream. */ - bool shutUp = false; /* true if we put a no echo command - * into the command file */ - bool errOff = false; /* true if we turned error checking - * off before printing the command - * and need to turn it back on */ - char *cmdTemplate; /* Template to use when printing the - * command */ - char *cmdStart; /* Start of expanded command */ + bool noSpecials; /* true if we shouldn't worry about + * inserting special commands into + * the input stream. */ + bool shutUp = false; /* true if we put a no echo command + * into the command file */ + bool errOff = false; /* true if we turned error checking + * off before printing the command + * and need to turn it back on */ + char *cmdTemplate; /* Template to use when printing the + * command */ + char *cmdStart; /* Start of expanded command */ char *cmd = (char *)Lst_Datum(cmdNode); Job *job = (Job *)jobp; @@ -583,6 +570,7 @@ JobPrintCommand(LstNode cmdNode, /* command string to print */ return 1; } + numCommands++; /* For debugging, we replace each command with the result of expanding @@ -618,13 +606,12 @@ JobPrintCommand(LstNode cmdNode, /* command string to print */ if (errOff) { if ( !(job->flags & JOB_IGNERR) && !noSpecials) { /* - * we don't want the error-control commands - * showing up either, so we turn off echoing - * while executing them. We could put another - * field in the shell structure to tell - * JobDoOutput to look for this string too, but - * why make it any more complex than it already - * is? + * we don't want the error-control commands showing + * up either, so we turn off echoing while executing + * them. We could put another field in the shell + * structure to tell JobDoOutput to look for this + * string too, but why make it any more complex than + * it already is? */ if (!(job->flags & JOB_SILENT) && !shutUp) { DBPRINTF(job, "%s; %s; %s\n", SHELL_ECHO_OFF, @@ -664,7 +651,7 @@ JobPrintCommand(LstNode cmdNode, /* command string to print */ * Callback function for JobFinish... * * Side Effects: - * The command is tacked onto the end of postCommands's commands list. + * The command is tacked onto the end of end_node's commands list. *----------------------------------------------------------------------- */ static void @@ -674,7 +661,7 @@ JobSaveCommand(void *cmd, void *gn) char *result; result = Var_Subst((char *)cmd, &g->context, false); - Lst_AtEnd(&postCommands->commands, result); + Lst_AtEnd(&end_node->commands, result); } @@ -710,7 +697,7 @@ JobClose(Job *job) * * Side Effects: * Some nodes may be put on the toBeMade queue. - * Final commands for the job are placed on postCommands. + * Final commands for the job are placed on end_node. * * If we got an error and are aborting (aborting == ABORT_ERROR) and * the job list is now empty, we are done for the day. @@ -723,7 +710,7 @@ static void JobFinish(Job *job, /* job to finish */ int *status) /* sub-why job went away */ { - bool done; + bool done; if ((WIFEXITED(*status) && WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) || @@ -773,8 +760,8 @@ JobFinish(Job *job, /* job to finish */ if (WIFEXITED(*status)) { if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %ld exited.\n", - (long)job->pid); + (void)fprintf(stdout, + "Process %ld exited.\n", (long)job->pid); (void)fflush(stdout); } if (WEXITSTATUS(*status) != 0) { @@ -800,8 +787,8 @@ JobFinish(Job *job, /* job to finish */ } } else if (WIFSTOPPED(*status)) { if (DEBUG(JOB)) { - (void)fprintf(stdout, "Process %ld stopped.\n", - (long)job->pid); + (void)fprintf(stdout, + "Process %ld stopped.\n", (long)job->pid); (void)fflush(stdout); } if (job->node != lastNode) { @@ -831,7 +818,7 @@ JobFinish(Job *job, /* job to finish */ if (!(job->flags & JOB_CONTINUING)) { if (DEBUG(JOB)) { (void)fprintf(stdout, - "Warning: process %ld was not continuing.\n", + "Warning: process %ld was not continuing.\n", (long)job->pid); (void)fflush(stdout); } @@ -855,7 +842,6 @@ JobFinish(Job *job, /* job to finish */ (long)job->pid); (void)fflush(stdout); } - nLocal++; if (nJobs == maxJobs) { jobFull = true; if (DEBUG(JOB)) { @@ -964,7 +950,7 @@ JobExec(Job *job, char **argv) pid_t cpid; /* ID of new child */ if (DEBUG(JOB)) { - int i; + int i; (void)fprintf(stdout, "Running %s\n", job->node->name); (void)fprintf(stdout, "\tCommand: "); @@ -1003,8 +989,8 @@ JobExec(Job *job, char **argv) (void)lseek(0, 0, SEEK_SET); /* - * Set up the child's output to be routed through the - * pipe we've created for it. + * Set up the child's output to be routed through the pipe + * we've created for it. */ if (dup2(job->outPipe, 1) == -1) Punt("Cannot dup2: %s", strerror(errno)); @@ -1069,7 +1055,6 @@ JobExec(Job *job, char **argv) FD_SET(job->inPipe, outputsp); } - nLocal++; /* * XXX: Used to not happen if REMOTE. Why? */ @@ -1111,7 +1096,7 @@ JobMakeArgv(Job *job, char **argv) if (args[1]) { argv[argc] = args; argc++; - } + } argv[argc] = NULL; } @@ -1146,7 +1131,7 @@ JobRestart(Job *job) job->node->name); (void)fflush(stdout); } - if (nLocal >= maxLocal && !(job->flags & JOB_SPECIAL)) { + if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) { /* * Can't be exported and not allowed to run locally -- * put it back on the hold queue and mark the table @@ -1182,13 +1167,10 @@ JobRestart(Job *job) (void)fprintf(stdout, "Resuming %s...", job->node->name); (void)fflush(stdout); } - if ((nLocal < maxLocal || - ((job->flags & JOB_SPECIAL) && - maxLocal == 0) - ) && nJobs != maxJobs) { + if (nJobs != maxJobs || (job->flags & JOB_SPECIAL)) { /* - * If we haven't reached the concurrency limit already - * (or maxLocal is 0), it's ok to resume the job. + * If we haven't reached the concurrency limit already, + * it's ok to resume the job. */ bool error; int status; @@ -1253,17 +1235,17 @@ JobRestart(Job *job) *----------------------------------------------------------------------- */ static int -JobStart(GNode *gn, /* target to create */ - int flags, /* flags for the job to override normal ones. - * e.g. JOB_SPECIAL or JOB_IGNDOTS */ - Job *previous) /* The previous Job structure for this node, - * if any. */ +JobStart(GNode *gn, /* target to create */ + int flags, /* flags for the job to override normal ones. + * e.g. JOB_SPECIAL or JOB_IGNDOTS */ + Job *previous) /* The previous Job structure for this node, + * if any. */ { - Job *job; /* new job descriptor */ - char *argv[4]; /* Argument vector to shell */ - bool cmdsOK; /* true if the nodes commands were all right */ - bool local; /* Set true if the job was run locally */ - bool noExec; /* Set true if we decide not to run the job */ + Job *job; /* new job descriptor */ + char *argv[4]; /* Argument vector to shell */ + bool cmdsOK; /* true if the nodes commands were all right */ + bool local; /* Set true if the job was run locally */ + bool noExec; /* Set true if we decide not to run the job */ if (previous != NULL) { previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT); @@ -1483,18 +1465,9 @@ JobStart(GNode *gn, /* target to create */ local = true; - if (local && nLocal >= maxLocal && - !(job->flags & JOB_SPECIAL) && - maxLocal != 0 - ) { - /* - * The job can only be run locally, but we've hit the limit of - * local concurrency, so put the job on hold until some other - * job finishes. Note that the special jobs (.BEGIN, .INTERRUPT - * and .END) may be run locally even when the local limit has - * been reached (e.g. when maxLocal == 0), though they will be - * exported if at all possible. In addition, any target marked - * with .NOEXPORT will be run locally if maxLocal is 0. + if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) { + /* we've hit the limit of concurrency, so put the job on hold + * until some other job finishes. */ jobFull = true; @@ -1504,20 +1477,6 @@ JobStart(GNode *gn, /* target to create */ } job->flags |= JOB_RESTART; Lst_AtEnd(&stoppedJobs, job); - } else { - if (nLocal >= maxLocal && local) { - /* - * If we're running this job locally as a special case - * (see above), at least say the table is full. - */ - jobFull = true; - if (DEBUG(JOB)) { - (void)fprintf(stdout, - "Local job queue is full.\n"); - (void)fflush(stdout); - } - } - JobExec(job, argv); } return JOB_RUNNING; } @@ -1536,11 +1495,10 @@ JobOutput(Job *job, char *cp, char *endp, int msg) lastNode = job->node; } /* - * The only way there wouldn't be a newline - * after this line is if it were the last in - * the buffer. however, since the - * non-printable comes after it, there must be - * a newline, so we don't print one. + * The only way there wouldn't be a newline after + * this line is if it were the last in the buffer. + * however, since the non-printable comes after it, + * there must be a newline, so we don't print one. */ (void)fprintf(stdout, "%s", cp); (void)fflush(stdout); @@ -1548,13 +1506,12 @@ JobOutput(Job *job, char *cp, char *endp, int msg) cp = ecp + strlen(SHELL_ECHO_OFF); if (cp != endp) { /* - * Still more to print, look again after - * skipping the whitespace following the - * non-printable command.... + * Still more to print, look again after skipping + * the whitespace following the non-printable + * command.... */ cp++; - while (*cp == ' ' || *cp == '\t' || - *cp == '\n') { + while (*cp == ' ' || *cp == '\t' || *cp == '\n') { cp++; } ecp = strstr(cp, SHELL_ECHO_OFF); @@ -1594,12 +1551,12 @@ JobDoOutput(Job *job, /* the job whose output needs printing */ bool finish) /* true if this is the last time we'll be * called for this job */ { - bool gotNL = false; /* true if got a newline */ + bool gotNL = false; /* true if got a newline */ bool fbuf; /* true if our buffer filled up */ int nr; /* number of bytes read */ int i; /* auxiliary index into outBuf */ - int max; /* limit for i (end of current data) */ - int nRead; /* (Temporary) number of bytes read */ + int max; /* limit for i (end of current data) */ + int nRead; /* (Temporary) number of bytes read */ /* * Read as many bytes as will fit in the buffer. @@ -1620,10 +1577,10 @@ end_loop: } /* - * If we hit the end-of-file (the job is dead), we must flush - * its remaining output, so pretend we read a newline if - * there's any output remaining in the buffer. Also clear the - * 'finish' flag so we stop looping. + * If we hit the end-of-file (the job is dead), we must flush its + * remaining output, so pretend we read a newline if there's any + * output remaining in the buffer. + * Also clear the 'finish' flag so we stop looping. */ if (nr == 0 && job->curPos != 0) { job->outBuf[job->curPos] = '\n'; @@ -1634,9 +1591,9 @@ end_loop: } /* - * Look for the last newline in the bytes we just got. If there - * is one, break out of the loop with 'i' as its index and - * gotNL set true. + * Look for the last newline in the bytes we just got. If there is + * one, break out of the loop with 'i' as its index and gotNL set + * true. */ max = job->curPos + nr; for (i = job->curPos + nr - 1; i >= job->curPos; i--) { @@ -1655,8 +1612,8 @@ end_loop: job->curPos += nr; if (job->curPos == JOB_BUFSIZE) { /* - * If we've run out of buffer space, we have no - * choice but to print the stuff. sigh. + * If we've run out of buffer space, we have no choice + * but to print the stuff. sigh. */ fbuf = true; i = job->curPos; @@ -1664,28 +1621,26 @@ end_loop: } if (gotNL || fbuf) { /* - * Need to send the output to the screen. Null - * terminate it first, overwriting the newline - * character if there was one. So long as the line - * isn't one we should filter (according to the shell - * description), we print the line, preceded by a - * target banner if this target isn't the same as the - * one for which we last printed something. The rest - * of the data in the buffer are then shifted down to - * the start of the buffer and curPos is set - * accordingly. + * Need to send the output to the screen. Null terminate it + * first, overwriting the newline character if there was one. + * So long as the line isn't one we should filter (according + * to the shell description), we print the line, preceded + * by a target banner if this target isn't the same as the + * one for which we last printed something. + * The rest of the data in the buffer are then shifted down + * to the start of the buffer and curPos is set accordingly. */ job->outBuf[i] = '\0'; if (i >= job->curPos) { char *cp; - cp = JobOutput(job, job->outBuf, - &job->outBuf[i], false); + cp = JobOutput(job, job->outBuf, &job->outBuf[i], + false); /* - * There's still more in that thar buffer. This - * time, though, we know there's no newline at - * the end, so we add one of our own free will. + * There's still more in that thar buffer. This time, + * though, we know there's no newline at the end, so we + * add one of our own free will. */ if (*cp != '\0') { if (job->node != lastNode) { @@ -1705,21 +1660,20 @@ end_loop: } else { /* - * We have written everything out, so we just - * start over from the start of the buffer. No - * copying. No nothing. + * We have written everything out, so we just start over + * from the start of the buffer. No copying. No nothing. */ job->curPos = 0; } } if (finish) { /* - * If the finish flag is true, we must loop until we - * hit end-of-file on the pipe. This is guaranteed to - * happen eventually since the other end of the pipe is - * now closed (we closed it explicitly and the child - * has exited). When we do get an EOF, finish will be - * set false and we'll fall through and out. + * If the finish flag is true, we must loop until we hit + * end-of-file on the pipe. This is guaranteed to happen + * eventually since the other end of the pipe is now closed + * (we closed it explicitly and the child has exited). When + * we do get an EOF, finish will be set false and we'll fall + * through and out. */ goto end_loop; } @@ -1743,15 +1697,15 @@ end_loop: void Job_CatchChildren() { - pid_t pid; /* pid of dead child */ - Job *job; /* job descriptor for dead child */ - LstNode jnode; /* list element for finding job */ - int status; /* Exit/termination status */ + pid_t pid; /* pid of dead child */ + Job *job; /* job descriptor for dead child */ + LstNode jnode; /* list element for finding job */ + int status; /* Exit/termination status */ /* * Don't even bother if we know there's no one around. */ - if (nLocal == 0) { + if (nJobs == 0) { return; } @@ -1790,7 +1744,6 @@ Job_CatchChildren() (void)fflush(stdout); } jobFull = false; - nLocal--; } JobFinish(job, &status); @@ -1820,7 +1773,6 @@ Job_CatchOutput(void) int count = howmany(outputsn+1, NFDBITS) * sizeof(fd_mask); fd_set *readfdsp = malloc(count); - (void)fflush(stdout); if (readfdsp == NULL) return; @@ -1874,12 +1826,8 @@ Job_Make(GNode *gn) *----------------------------------------------------------------------- */ void -Job_Init(int maxproc, /* the greatest number of jobs which may be - * running at one time */ - int maxlocal) /* the greatest number of local jobs which may - * be running at once. */ +Job_Init(int maxproc) { - GNode *begin; /* node for commands to do at the very start */ int tfd; (void)strlcpy(tfile, TMPPAT, sizeof(tfile)); @@ -1891,9 +1839,6 @@ Job_Init(int maxproc, /* the greatest number of jobs which may be Static_Lst_Init(&jobs); Static_Lst_Init(&stoppedJobs); maxJobs = maxproc; - maxLocal = maxlocal; - nJobs = 0; - nLocal = 0; jobFull = false; aborting = 0; @@ -1948,16 +1893,13 @@ Job_Init(int maxproc, /* the greatest number of jobs which may be } #endif - begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); - - if (begin != NULL) { - JobStart(begin, JOB_SPECIAL, (Job *)0); + if ((begin_node->type & OP_DUMMY) == 0) { + JobStart(begin_node, JOB_SPECIAL, (Job *)0); while (nJobs) { Job_CatchOutput(); Job_CatchChildren(); } } - postCommands = Targ_FindNode(".END", TARG_CREATE); } /*- @@ -2026,8 +1968,7 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT int signo) /* signal received */ { LstNode ln; /* element in job table */ - Job *job; /* job descriptor in that element */ - GNode *interrupt; /* the node describing the .INTERRUPT target */ + Job *job; /* job descriptor in that element */ aborting = ABORT_INTERRUPT; @@ -2053,11 +1994,10 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT } if (runINTERRUPT && !touchFlag) { - interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); - if (interrupt != NULL) { + if ((interrupt_node->type & OP_DUMMY) == 0) { ignoreErrors = false; - JobStart(interrupt, JOB_IGNDOTS, (Job *)0); + JobStart(interrupt_node, JOB_IGNDOTS, (Job *)0); while (nJobs) { Job_CatchOutput(); Job_CatchChildren(); @@ -2085,11 +2025,11 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT int Job_Finish(void) { - if (postCommands != NULL && !Lst_IsEmpty(&postCommands->commands)) { + if (end_node != NULL && !Lst_IsEmpty(&end_node->commands)) { if (errors) { Error("Errors reported so .END ignored"); } else { - JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); + JobStart(end_node, JOB_SPECIAL | JOB_IGNDOTS, NULL); while (nJobs) { Job_CatchOutput(); @@ -2101,20 +2041,10 @@ Job_Finish(void) return errors; } -/*- - *----------------------------------------------------------------------- - * Job_End -- - * Cleanup any memory used by the jobs module - * - * Side Effects: - * Memory is freed - *----------------------------------------------------------------------- - */ #ifdef CLEANUP void Job_End(void) { - efree(shellArgv); } #endif diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h index aae2fc8f0cd..eeb5e077738 100644 --- a/usr.bin/make/job.h +++ b/usr.bin/make/job.h @@ -2,7 +2,7 @@ #define _JOB_H_ /* $OpenPackages$ */ -/* $OpenBSD: job.h,v 1.17 2007/09/17 12:01:16 espie Exp $ */ +/* $OpenBSD: job.h,v 1.18 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: job.h,v 1.5 1996/11/06 17:59:10 christos Exp $ */ /* @@ -49,7 +49,7 @@ extern void Job_CatchChildren(void); extern void Job_CatchOutput(void); extern void Job_Make(GNode *); -extern void Job_Init(int, int); +extern void Job_Init(int); extern bool Job_Full(void); extern bool Job_Empty(void); extern int Job_Finish(void); diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index c980898a0e4..7453c020ccb 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: main.c,v 1.82 2007/09/17 12:01:17 espie Exp $ */ +/* $OpenBSD: main.c,v 1.83 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: main.c,v 1.34 1997/03/24 20:56:36 gwr Exp $ */ /* @@ -75,22 +75,16 @@ # endif #endif -#ifndef DEFMAXLOCAL -#define DEFMAXLOCAL DEFMAXJOBS -#endif /* DEFMAXLOCAL */ - #define MAKEFLAGS ".MAKEFLAGS" static LIST to_create; /* Targets to be made */ Lst create = &to_create; -GNode *DEFAULT; /* .DEFAULT node */ bool allPrecious; /* .PRECIOUS given on line by itself */ static bool noBuiltins; /* -r flag */ static LIST makefiles; /* ordered list of makefiles to read */ static LIST varstoprint; /* list of variables to print */ int maxJobs; /* -j argument */ -static int maxLocal; /* -L argument */ bool compatMake; /* -B argument */ int debug; /* -d flag */ bool noExecute; /* -n flag */ @@ -301,7 +295,6 @@ MainParseArgs(int argc, char **argv) optarg); usage(); } - maxLocal = maxJobs; record_option(c, optarg); break; } @@ -677,8 +670,7 @@ main(int argc, char **argv) touchFlag = false; /* Actually update targets */ debug = 0; /* No debug verbosity, please. */ - maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ - maxJobs = maxLocal; + maxJobs = DEFMAXJOBS; /* Set default local max concurrency */ compatMake = false; /* No compat mode */ @@ -716,8 +708,6 @@ main(int argc, char **argv) Var_AddCmdline(MAKEFLAGS); - DEFAULT = NULL; - /* * Set up the .TARGETS variable to contain the list of targets to be * created. If none specified, make the variable empty -- the parser @@ -753,9 +743,7 @@ main(int argc, char **argv) setup_VPATH(); - /* Now that all search paths have been read for suffixes et al, it's - * time to add the default search path to their lists... */ - Suff_DoPaths(); + process_suffixes_after_makefile_is_read(); /* Print the initial graph, if the user requested it. */ if (DEBUG(GRAPH1)) @@ -792,9 +780,7 @@ main(int argc, char **argv) * (to prevent the .BEGIN from being executed should * it exist). */ if (!queryFlag) { - if (maxLocal == -1) - maxLocal = maxJobs; - Job_Init(maxJobs, maxLocal); + Job_Init(maxJobs); } /* Traverse the graph, checking on all the targets. */ diff --git a/usr.bin/make/main.h b/usr.bin/make/main.h index 711e84b6806..ce737a921a0 100644 --- a/usr.bin/make/main.h +++ b/usr.bin/make/main.h @@ -1,7 +1,7 @@ #ifndef MAIN_H #define MAIN_H /* $OpenPackages$ */ -/* $OpenBSD: main.h,v 1.2 2007/09/17 09:28:36 espie Exp $ */ +/* $OpenBSD: main.h,v 1.3 2007/09/17 12:42:09 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -39,6 +39,4 @@ extern void Main_ParseArgLine(const char *); * .if make(...) statements. */ extern Lst create; -extern GNode *DEFAULT; /* .DEFAULT rule */ - #endif diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index 63fdfa2f103..ce248699a7b 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: parse.c,v 1.91 2007/09/17 11:32:25 espie Exp $ */ +/* $OpenBSD: parse.c,v 1.92 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ /* @@ -91,8 +91,13 @@ #include "parsevar.h" #include "stats.h" #include "garray.h" +#include "node_int.h" +#include "nodehashconsts.h" +/* gsources and gtargets should be local to some functions, but they're + * set as persistent arrays for performance reasons. + */ static struct growableArray gsources, gtargets; #define SOURCES_SIZE 128 #define TARGETS_SIZE 32 @@ -110,40 +115,13 @@ static GNode *mainNode; /* The main target to create. This is the * first target on the first dependency * line in the first makefile */ /*- - * specType contains the SPECial TYPE of the current target. It is - * Not if the target is unspecial. If it *is* special, however, the children - * are linked as children of the parent but not vice versa. This variable is - * set in ParseDoDependency + * specType contains the special TYPE of the current target. It is + * SPECIAL_NONE if the target is unspecial. If it *is* special, however, + * the children are linked as children of the parent but not vice versa. + * This variable is set in ParseDoDependency */ -typedef enum { - Begin, /* .BEGIN */ - Default, /* .DEFAULT */ - End, /* .END */ - Ignore, /* .IGNORE */ - Includes, /* .INCLUDES */ - Interrupt, /* .INTERRUPT */ - Libs, /* .LIBS */ - MFlags, /* .MFLAGS or .MAKEFLAGS */ - Main, /* .MAIN and we don't have anything user-specified to - * make */ - NoExport, /* .NOEXPORT */ - NoPath, /* .NOPATH */ - Not, /* Not special */ - NotParallel, /* .NOTPARALELL */ - Null, /* .NULL */ - Order, /* .ORDER */ - Parallel, /* .PARALLEL */ - ExPath, /* .PATH */ - Phony, /* .PHONY */ - Precious, /* .PRECIOUS */ - Silent, /* .SILENT */ - SingleShell, /* .SINGLESHELL */ - Suffixes, /* .SUFFIXES */ - Wait, /* .WAIT */ - Attribute /* Generic attribute */ -} ParseSpecial; - -static ParseSpecial specType; + +static int specType; static int waiting; /* @@ -152,66 +130,18 @@ static int waiting; */ static GNode *predecessor; -/* - * The parseKeywords table is searched using binary search when deciding - * if a target or source is special. The 'spec' field is the ParseSpecial - * type of the keyword ("Not" if the keyword isn't special as a target) while - * the 'op' field is the operator to apply to the list of targets if the - * keyword is used as a source ("0" if the keyword isn't special as a source) - */ -static struct { - char *name; /* Name of keyword */ - ParseSpecial spec; /* Type when used as a target */ - int op; /* Operator when used as a source */ -} parseKeywords[] = { -{ ".BEGIN", Begin, 0 }, -{ ".DEFAULT", Default, 0 }, -{ ".END", End, 0 }, -{ ".EXEC", Attribute, OP_EXEC }, -{ ".IGNORE", Ignore, OP_IGNORE }, -{ ".INCLUDES", Includes, 0 }, -{ ".INTERRUPT", Interrupt, 0 }, -{ ".INVISIBLE", Attribute, OP_INVISIBLE }, -{ ".JOIN", Attribute, OP_JOIN }, -{ ".LIBS", Libs, 0 }, -{ ".MADE", Attribute, OP_MADE }, -{ ".MAIN", Main, 0 }, -{ ".MAKE", Attribute, OP_MAKE }, -{ ".MAKEFLAGS", MFlags, 0 }, -{ ".MFLAGS", MFlags, 0 }, -#if 0 /* basic scaffolding for NOPATH, not working yet */ -{ ".NOPATH", NoPath, OP_NOPATH }, -#endif -{ ".NOTMAIN", Attribute, OP_NOTMAIN }, -{ ".NOTPARALLEL", NotParallel, 0 }, -{ ".NO_PARALLEL", NotParallel, 0 }, -{ ".NULL", Null, 0 }, -{ ".OPTIONAL", Attribute, OP_OPTIONAL }, -{ ".ORDER", Order, 0 }, -{ ".PARALLEL", Parallel, 0 }, -{ ".PATH", ExPath, 0 }, -{ ".PHONY", Phony, OP_PHONY }, -{ ".PRECIOUS", Precious, OP_PRECIOUS }, -{ ".RECURSIVE", Attribute, OP_MAKE }, -{ ".SILENT", Silent, OP_SILENT }, -{ ".SINGLESHELL", SingleShell, 0 }, -{ ".SUFFIXES", Suffixes, 0 }, -{ ".USE", Attribute, OP_USE }, -{ ".WAIT", Wait, 0 }, -}; - -static int ParseFindKeyword(const char *); static void ParseLinkSrc(GNode *, GNode *); -static int ParseDoOp(GNode *, int); +static int ParseDoOp(GNode **, int); static int ParseAddDep(GNode *, GNode *); -static void ParseDoSrc(int, const char *); +static void ParseDoSrc(struct growableArray *, struct growableArray *, int, + const char *, const char *); static int ParseFindMain(void *, void *); -static void ParseAddDir(void *, void *); static void ParseClearPath(void *); -static void add_target_node(const char *); -static void add_target_nodes(const char *); -static void ParseDoDependency(char *); +static void add_target_node(const char *, const char *); +static void add_target_nodes(const char *, const char *); +static void apply_op(struct growableArray *, int, GNode *); +static void ParseDoDependency(const char *); static void ParseAddCmd(void *, void *); static void ParseHasCommands(void *); static bool handle_poison(const char *); @@ -227,43 +157,100 @@ static void lookup_sysv_style_include(const char *, const char *, bool); static void lookup_sysv_include(const char *, const char *); static void lookup_conditional_include(const char *, const char *); static bool parse_as_special_line(Buffer, Buffer, const char *); + +static const char *parse_do_targets(Lst, int *, const char *); static void parse_target_line(struct growableArray *, const char *, const char *); -/*- - *---------------------------------------------------------------------- - * ParseFindKeyword -- - * Look in the table of keywords for one matching the given string. - * - * Results: - * The index of the keyword, or -1 if it isn't there. - *---------------------------------------------------------------------- - */ -static int -ParseFindKeyword(const char *str) /* keyword to look up */ +static void finish_commands(struct growableArray *); +static void parse_commands(struct growableArray *, const char *); +static void create_special_nodes(void); +static bool found_delimiter(const char *); +static int handle_special_targets(Lst); + +#define SPECIAL_EXEC 4 +#define SPECIAL_IGNORE 5 +#define SPECIAL_INCLUDES 6 +#define SPECIAL_INVISIBLE 8 +#define SPECIAL_JOIN 9 +#define SPECIAL_LIBS 10 +#define SPECIAL_MADE 11 +#define SPECIAL_MAIN 12 +#define SPECIAL_MAKE 13 +#define SPECIAL_MFLAGS 14 +#define SPECIAL_NOTMAIN 15 +#define SPECIAL_NOTPARALLEL 16 +#define SPECIAL_NULL 17 +#define SPECIAL_OPTIONAL 18 +#define SPECIAL_ORDER 19 +#define SPECIAL_PARALLEL 20 +#define SPECIAL_PHONY 22 +#define SPECIAL_PRECIOUS 23 +#define SPECIAL_SILENT 25 +#define SPECIAL_SINGLESHELL 26 +#define SPECIAL_SUFFIXES 27 +#define SPECIAL_USE 28 +#define SPECIAL_WAIT 29 +#define SPECIAL_NOPATH 30 +#define SPECIAL_ERROR 31 + + +#define P(k) k, sizeof(k), K_##k + +static struct { + const char *keyword; + size_t sz; + uint32_t hv; + int type; + int special_op; +} specials[] = { + { P(NODE_EXEC), SPECIAL_EXEC | SPECIAL_TARGETSOURCE, OP_EXEC, }, + { P(NODE_IGNORE), SPECIAL_IGNORE | SPECIAL_TARGETSOURCE, OP_IGNORE, }, + { P(NODE_INCLUDES), SPECIAL_INCLUDES | SPECIAL_TARGET, 0, }, + { P(NODE_INVISIBLE),SPECIAL_INVISIBLE | SPECIAL_TARGETSOURCE,OP_INVISIBLE, }, + { P(NODE_JOIN), SPECIAL_JOIN | SPECIAL_TARGETSOURCE, OP_JOIN, }, + { P(NODE_LIBS), SPECIAL_LIBS | SPECIAL_TARGET, 0, }, + { P(NODE_MADE), SPECIAL_MADE | SPECIAL_TARGETSOURCE, OP_MADE, }, + { P(NODE_MAIN), SPECIAL_MAIN | SPECIAL_TARGET, 0, }, + { P(NODE_MAKE), SPECIAL_MAKE | SPECIAL_TARGETSOURCE, OP_MAKE, }, + { P(NODE_MAKEFLAGS), SPECIAL_MFLAGS | SPECIAL_TARGET, 0, }, + { P(NODE_MFLAGS), SPECIAL_MFLAGS | SPECIAL_TARGET, 0, }, + { P(NODE_NOTMAIN), SPECIAL_NOTMAIN | SPECIAL_TARGETSOURCE, OP_NOTMAIN, }, + { P(NODE_NOTPARALLEL),SPECIAL_NOTPARALLEL | SPECIAL_TARGET, 0, }, + { P(NODE_NO_PARALLEL),SPECIAL_NOTPARALLEL | SPECIAL_TARGET, 0, }, + { P(NODE_NULL), SPECIAL_NULL | SPECIAL_TARGET, 0, }, + { P(NODE_OPTIONAL), SPECIAL_OPTIONAL | SPECIAL_TARGETSOURCE,OP_OPTIONAL, }, + { P(NODE_ORDER), SPECIAL_ORDER | SPECIAL_TARGET, 0, }, + { P(NODE_PARALLEL), SPECIAL_PARALLEL | SPECIAL_TARGET, 0, }, + { P(NODE_PATH), SPECIAL_PATH | SPECIAL_TARGET, 0, }, + { P(NODE_PHONY), SPECIAL_PHONY | SPECIAL_TARGETSOURCE, OP_PHONY, }, + { P(NODE_PRECIOUS), SPECIAL_PRECIOUS | SPECIAL_TARGETSOURCE,OP_PRECIOUS, }, + { P(NODE_RECURSIVE),SPECIAL_MAKE | SPECIAL_TARGETSOURCE, OP_MAKE, }, + { P(NODE_SILENT), SPECIAL_SILENT | SPECIAL_TARGETSOURCE, OP_SILENT, }, + { P(NODE_SINGLESHELL),SPECIAL_SINGLESHELL | SPECIAL_TARGET, 0, }, + { P(NODE_SUFFIXES), SPECIAL_SUFFIXES | SPECIAL_TARGET, 0, }, + { P(NODE_USE), SPECIAL_USE | SPECIAL_TARGETSOURCE, OP_USE, }, + { P(NODE_WAIT), SPECIAL_WAIT | SPECIAL_TARGETSOURCE, 0 }, +#if 0 + { P(NODE_NOPATH), SPECIAL_NOPATH, }, +#endif +}; + +#undef P + +static void +create_special_nodes() { - int start, - end, - cur; - int diff; - - start = 0; - end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; - - do { - cur = start + (end - start) / 2; - diff = strcmp(str, parseKeywords[cur].name); - - if (diff == 0) { - return cur; - } else if (diff < 0) { - end = cur - 1; - } else { - start = cur + 1; + unsigned int i; + + for (i = 0; i < sizeof(specials)/sizeof(specials[0]); i++) { + GNode *gn = Targ_FindNodeh(specials[i].keyword, + specials[i].sz, specials[i].hv, TARG_CREATE); + gn->special = specials[i].type; + gn->special_op = specials[i].special_op; } - } while (start <= end); - return -1; } + /*- *--------------------------------------------------------------------- * ParseLinkSrc -- @@ -282,18 +269,18 @@ ParseLinkSrc( GNode *pgn, /* The parent node */ GNode *cgn) /* The child node */ { - if (Lst_AddNew(&pgn->children, cgn)) { - if (specType == Not) - Lst_AtEnd(&cgn->parents, pgn); - pgn->unmade++; - } + if (Lst_AddNew(&pgn->children, cgn)) { + if (specType == SPECIAL_NONE) + Lst_AtEnd(&cgn->parents, pgn); + pgn->unmade++; + } } /*- *--------------------------------------------------------------------- * ParseDoOp -- * Apply the parsed operator to the given target node. Used in a - * Lst_Find call by ParseDoDependency once all targets have + * Array_Find call by ParseDoDependency once all targets have * been found and their operator parsed. If the previous and new * operators are incompatible, a major error is taken. * @@ -304,56 +291,52 @@ ParseLinkSrc( */ static int ParseDoOp( - GNode *gn, /* The node to which the operator is to be applied */ + GNode **gnp, int op) /* The operator to apply */ { - /* - * If the dependency mask of the operator and the node don't match and - * the node has actually had an operator applied to it before, and - * the operator actually has some dependency information in it, complain. - */ - if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && - !OP_NOP(gn->type) && !OP_NOP(op)) { - Parse_Error(PARSE_FATAL, - "Inconsistent operator for %s", gn->name); - return 0; - } + GNode *gn = *gnp; + /* + * If the dependency mask of the operator and the node don't match and + * the node has actually had an operator applied to it before, and + * the operator actually has some dependency information in it, complain. + */ + if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && + !OP_NOP(gn->type) && !OP_NOP(op)) { + Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); + return 0; + } - if (op == OP_DOUBLEDEP && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { - /* If the node was the object of a :: operator, we need to - * create a new instance of it for the children and commands on - * this dependency line. The new instance is placed on the - * 'cohorts' list of the initial one (note the initial one is - * not on its own cohorts list) and the new instance is linked - * to all parents of the initial instance. */ - GNode *cohort; - LstNode ln; - unsigned int i; - - cohort = Targ_NewGN(gn->name); - /* Duplicate links to parents so graph traversal is simple. - * Perhaps some type bits should be duplicated? - * - * Make the cohort invisible as well to avoid duplicating it - * into other variables. True, parents of this target won't - * tend to do anything with their local variables, but better - * safe than sorry. */ - for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) - ParseLinkSrc((GNode *)Lst_Datum(ln), cohort); - cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; - Lst_AtEnd(&gn->cohorts, cohort); - - /* Replace the node in the targets list with the new copy */ - for (i = 0; i < gtargets.n; i++) - if (gtargets.a[i] == gn) - break; - gtargets.a[i] = cohort; - gn = cohort; - } - /* We don't want to nuke any previous flags (whatever they were) so we - * just OR the new operator into the old. */ - gn->type |= op; - return 1; + if (op == OP_DOUBLEDEP && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { + /* If the node was the object of a :: operator, we need to create a + * new instance of it for the children and commands on this dependency + * line. The new instance is placed on the 'cohorts' list of the + * initial one (note the initial one is not on its own cohorts list) + * and the new instance is linked to all parents of the initial + * instance. */ + GNode *cohort; + LstNode ln; + + cohort = Targ_NewGN(gn->name); + /* Duplicate links to parents so graph traversal is simple. Perhaps + * some type bits should be duplicated? + * + * Make the cohort invisible as well to avoid duplicating it into + * other variables. True, parents of this target won't tend to do + * anything with their local variables, but better safe than + * sorry. */ + for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) + ParseLinkSrc((GNode *)Lst_Datum(ln), cohort); + cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; + Lst_AtEnd(&gn->cohorts, cohort); + + /* Replace the node in the targets list with the new copy */ + *gnp = cohort; + gn = cohort; + } + /* We don't want to nuke any previous flags (whatever they were) so we + * just OR the new operator into the old. */ + gn->type |= op; + return 1; } /*- @@ -375,18 +358,26 @@ ParseDoOp( static int ParseAddDep(GNode *p, GNode *s) { - if (p->order < s->order) { - /* XXX: This can cause loops, and loops can cause unmade - * targets, but checking is tedious, and the debugging output - * can show the problem. */ - Lst_AtEnd(&p->successors, s); - Lst_AtEnd(&s->preds, p); - return 1; - } - else - return 0; + if (p->order < s->order) { + /* XXX: This can cause loops, and loops can cause unmade targets, + * but checking is tedious, and the debugging output can show the + * problem. */ + Lst_AtEnd(&p->successors, s); + Lst_AtEnd(&s->preds, p); + return 1; + } + else + return 0; } +static void +apply_op(struct growableArray *targets, int op, GNode *gn) +{ + if (op) + gn->type |= op; + else + Array_ForEach(targets, ParseLinkSrc, gn); +} /*- *--------------------------------------------------------------------- @@ -404,102 +395,77 @@ ParseAddDep(GNode *p, GNode *s) */ static void ParseDoSrc( + struct growableArray *targets, + struct growableArray *sources, int tOp, /* operator (if any) from special targets */ - const char *src) /* name of the source to handle */ + const char *src, /* name of the source to handle */ + const char *esrc) { - GNode *gn = NULL; - - if (*src == '.' && isupper(src[1])) { - int keywd = ParseFindKeyword(src); - if (keywd != -1) { - int op = parseKeywords[keywd].op; - if (op != 0) { - Array_Find(>argets, ParseDoOp, op); - return; - } - if (parseKeywords[keywd].spec == Wait) { - waiting++; - return; - } + GNode *gn = Targ_FindNodei(src, esrc, TARG_CREATE); + if ((gn->special & SPECIAL_SOURCE) != 0) { + if (gn->special_op) { + Array_FindP(targets, ParseDoOp, gn->special_op); + return; + } else { + assert((gn->special & SPECIAL_MASK) == SPECIAL_WAIT); + waiting++; + return; } } switch (specType) { - case Main: + case SPECIAL_MAIN: /* * If we have noted the existence of a .MAIN, it means we need * to add the sources of said target to the list of things - * to create. The string 'src' is likely to be freed, so we - * must make a new copy of it. Note that this will only be - * invoked if the user didn't specify a target on the command - * line. This is to allow #ifmake's to succeed, or something... + * to create. Note that this will only be invoked if the user + * didn't specify a target on the command line. This is to + * allow #ifmake's to succeed, or something... */ - Lst_AtEnd(create, estrdup(src)); + Lst_AtEnd(create, gn->name); /* * Add the name to the .TARGETS variable as well, so the user * can employ that, if desired. */ - Var_Append(".TARGETS", src); + Var_Append(".TARGETS", gn->name); return; - case Order: + case SPECIAL_ORDER: /* * Create proper predecessor/successor links between the * previous source and the current one. */ - gn = Targ_FindNode(src, TARG_CREATE); if (predecessor != NULL) { Lst_AtEnd(&predecessor->successors, gn); Lst_AtEnd(&gn->preds, predecessor); } - /* - * The current source now becomes the predecessor for the next - * one. - */ predecessor = gn; break; default: /* - * If the source is not an attribute, we need to find/create - * a node for it. After that we can apply any operator to it - * from a special target or link it to its parents, as - * appropriate. - * * In the case of a source that was the object of a :: operator, * the attribute is applied to all of its instances (as kept in * the 'cohorts' list of the node) or all the cohorts are linked * to all the targets. */ - gn = Targ_FindNode(src, TARG_CREATE); - if (tOp) { - gn->type |= tOp; - } else { - Array_ForEach(>argets, ParseLinkSrc, gn); - } + apply_op(targets, tOp, gn); if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { - GNode *cohort; LstNode ln; - for (ln=Lst_First(&gn->cohorts); ln != NULL; + for (ln=Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)){ - cohort = (GNode *)Lst_Datum(ln); - if (tOp) { - cohort->type |= tOp; - } else { - Array_ForEach(>argets, ParseLinkSrc, - cohort); - } + apply_op(targets, tOp, + (GNode *)Lst_Datum(ln)); } } break; } gn->order = waiting; - Array_AtEnd(&gsources, gn); - if (waiting) { - Array_Find(&gsources, ParseAddDep, gn); - } + Array_AtEnd(sources, gn); + if (waiting) + Array_Find(sources, ParseAddDep, gn); } /*- @@ -513,7 +479,7 @@ ParseDoSrc( * 1 if main not found yet, 0 if it is. * * Side Effects: - * mainNode is changed and Targ_SetMain is called. + * mainNode is changed and. *----------------------------------------------------------------------- */ static int @@ -521,29 +487,13 @@ ParseFindMain( void *gnp, /* Node to examine */ void *dummy UNUSED) { - GNode *gn = (GNode *)gnp; - if ((gn->type & OP_NOTARGET) == 0) { - mainNode = gn; - Targ_SetMain(gn); - return 0; - } else { - return 1; - } -} - -/*- - *----------------------------------------------------------------------- - * ParseAddDir -- - * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going - * - * Side Effects: - * See Dir_AddDir. - *----------------------------------------------------------------------- - */ -static void -ParseAddDir(void *path, void *name) -{ - Dir_AddDir((Lst)path, (char *)name); + GNode *gn = (GNode *)gnp; + if ((gn->type & OP_NOTARGET) == 0 && gn->special == SPECIAL_NONE) { + mainNode = gn; + return 0; + } else { + return 1; + } } /*- @@ -555,31 +505,33 @@ ParseAddDir(void *path, void *name) static void ParseClearPath(void *p) { - Lst path = (Lst)p; + Lst path = (Lst)p; - Lst_Destroy(path, Dir_Destroy); - Lst_Init(path); + Lst_Destroy(path, Dir_Destroy); + Lst_Init(path); } static void -add_target_node(const char *line) +add_target_node(const char *line, const char *end) { GNode *gn; - if (!Suff_IsTransform(line)) - gn = Targ_FindNode(line, TARG_CREATE); - else - gn = Suff_AddTransform(line); + gn = Suff_ParseAsTransform(line, end); + + if (gn == NULL) { + gn = Targ_FindNodei(line, end, TARG_CREATE); + gn->type &= ~OP_DUMMY; + } if (gn != NULL) Array_AtEnd(>argets, gn); } static void -add_target_nodes(const char *line) +add_target_nodes(const char *line, const char *end) { - if (Dir_HasWildcards(line)) { + if (Dir_HasWildcardsi(line, end)) { /* * Targets are to be sought only in the current directory, * so create an empty path for the thing. Note we need to @@ -592,14 +544,201 @@ add_target_nodes(const char *line) Lst_Init(&emptyPath); Lst_Init(&curTargs); - Dir_Expand(line, &emptyPath, &curTargs); + Dir_Expandi(line, end, &emptyPath, &curTargs); Lst_Destroy(&emptyPath, Dir_Destroy); while ((targName = (char *)Lst_DeQueue(&curTargs)) != NULL) { - add_target_node(targName); + add_target_node(targName, targName + strlen(targName)); } Lst_Destroy(&curTargs, NOFREE); } else { - add_target_node(line); + add_target_node(line, end); + } +} + +/* special target line check: a proper delimiter is a ':' or '!', but + * we don't want to end a target on such a character if there is a better + * match later on. + * By "better" I mean one that is followed by whitespace. This allows the + * user to have targets like: + * fie::fi:fo: fum + * where "fie::fi:fo" is the target. In real life this is used for perl5 + * library man pages where "::" separates an object from its class. Ie: + * "File::Spec::Unix". + * This behaviour is also consistent with other versions of make. + */ +static bool +found_delimiter(const char *s) +{ + if (*s == '!' || *s == ':') { + const char *p = s + 1; + + if (*s == ':' && *p == ':') + p++; + + /* Found the best match already. */ + if (isspace(*p) || *p == '\0') + return true; + + do { + p += strcspn(p, "!:"); + if (*p == '\0') + break; + p++; + } while (!isspace(*p)); + + /* No better match later on... */ + if (*p == '\0') + return true; + } + return false; +} + +static const char * +parse_do_targets(Lst paths, int *op, const char *line) +{ + const char *cp; + + do { + for (cp = line; *cp && !isspace(*cp) && *cp != '(';) { + if (*cp == '$') + /* Must be a dynamic source (would have been + * expanded otherwise), so call the Var module + * to parse the puppy so we can safely advance + * beyond it...There should be no errors in + * this, as they would have been discovered in + * the initial Var_Subst and we wouldn't be + * here. */ + Var_ParseSkip(&cp, NULL); + else { + if (found_delimiter(cp)) + break; + cp++; + } + } + + if (*cp == '(') { + LIST temp; + Lst_Init(&temp); + /* Archives must be handled specially to make sure the + * OP_ARCHV flag is set in their 'type' field, for one + * thing, and because things like "archive(file1.o + * file2.o file3.o)" are permissible. + * Arch_ParseArchive will set 'line' to be the first + * non-blank after the archive-spec. It creates/finds + * nodes for the members and places them on the given + * list, returning true if all went well and false if + * there was an error in the specification. On error, + * line should remain untouched. */ + if (!Arch_ParseArchive(&line, &temp, NULL)) { + Parse_Error(PARSE_FATAL, + "Error in archive specification: \"%s\"", + line); + return NULL; + } else { + AppendList2Array(&temp, >argets); + Lst_Destroy(&temp, NOFREE); + cp = line; + continue; + } + } + if (*cp == '\0') { + /* Ending a dependency line without an operator is a + * Bozo no-no */ + Parse_Error(PARSE_FATAL, "Need an operator"); + return NULL; + } + /* + * Have word in line. Get or create its nodes and stick it at + * the end of the targets list + */ + if (*line != '\0') + add_target_nodes(line, cp); + + while (isspace(*cp)) + cp++; + line = cp; + } while (*line != '!' && *line != ':' && *line); + *op = handle_special_targets(paths); + return cp; +} + +static void +dump_targets() +{ + size_t i; + for (i = 0; i < gtargets.n; i++) + fprintf(stderr, "%s", gtargets.a[i]->name); + fprintf(stderr, "\n"); +} + +static int +handle_special_targets(Lst paths) +{ + size_t i; + int seen_path = 0; + int seen_special = 0; + int seen_normal = 0; + int type; + + for (i = 0; i < gtargets.n; i++) { + type = gtargets.a[i]->special; + if ((type & SPECIAL_MASK) == SPECIAL_PATH) { + seen_path++; + Lst_AtEnd(paths, find_suffix_path(gtargets.a[i])); + } else if ((type & SPECIAL_TARGET) != 0) + seen_special++; + else + seen_normal++; + } + if ((seen_path != 0) + (seen_special != 0) + (seen_normal != 0) > 1) { + Parse_Error(PARSE_FATAL, "Wrong mix of special targets"); + dump_targets(); + specType = SPECIAL_ERROR; + return 0; + } + if (seen_normal != 0) { + specType = SPECIAL_NONE; + return 0; + } + else if (seen_path != 0) { + specType = SPECIAL_PATH; + return 0; + } else if (seen_special == 0) { + specType = SPECIAL_NONE; + return 0; + } else if (seen_special != 1) { + Parse_Error(PARSE_FATAL, "Mixing special targets is not allowed"); + dump_targets(); + return 0; + } else if (seen_special == 1) { + specType = gtargets.a[0]->special & SPECIAL_MASK; + switch (specType) { + case SPECIAL_MAIN: + if (!Lst_IsEmpty(create)) { + specType = SPECIAL_NONE; + } + break; + case SPECIAL_NOTPARALLEL: + { + extern int maxJobs; + + maxJobs = 1; + break; + } + case SPECIAL_SINGLESHELL: + compatMake = 1; + break; + case SPECIAL_ORDER: + predecessor = NULL; + break; + default: + break; + } + return gtargets.a[0]->special_op; + } else { + /* we're allowed to have 0 target */ + specType = SPECIAL_NONE; + return 0; } } @@ -635,444 +774,215 @@ add_target_nodes(const char *line) *--------------------------------------------------------------------- */ static void -ParseDoDependency(char *line) /* the line to parse */ +ParseDoDependency(const char *line) /* the line to parse */ { - char *cp; /* our current position */ - GNode *gn; /* a general purpose temporary node */ - int op; /* the operator on the line */ - char savec; /* a place to save a character */ - LIST paths; /* List of search paths to alter when parsing - * a list of .PATH targets */ - int tOp; /* operator from special target */ - tOp = 0; - - specType = Not; - waiting = 0; - Lst_Init(&paths); - - Array_Reset(&gsources); - - do { - for (cp = line; *cp && !isspace(*cp) && *cp != '(';) - if (*cp == '$') - /* Must be a dynamic source (would have been expanded - * otherwise), so call the Var module to parse the puppy - * so we can safely advance beyond it...There should be - * no errors in this, as they would have been discovered - * in the initial Var_Subst and we wouldn't be here. */ - Var_ParseSkip(&cp, NULL); - else { - /* We don't want to end a word on ':' or '!' if there is a - * better match later on in the string. By "better" I mean - * one that is followed by whitespace. This allows the user - * to have targets like: - * fie::fi:fo: fum - * where "fie::fi:fo" is the target. In real life this is used - * for perl5 library man pages where "::" separates an object - * from its class. Ie: "File::Spec::Unix". This behaviour - * is also consistent with other versions of make. */ - if (*cp == '!' || *cp == ':') { - char *p = cp + 1; - - if (*cp == ':' && *p == ':') - p++; + const char *cp; /* our current position */ + int op; /* the operator on the line */ + LIST paths; /* List of search paths to alter when parsing + * a list of .PATH targets */ + int tOp; /* operator from special target */ - /* Found the best match already. */ - if (isspace(*p) || *p == '\0') - break; - do { - p += strcspn(p, "!:"); - if (*p == '\0') - break; - p++; - } while (!isspace(*p)); + waiting = 0; + Lst_Init(&paths); - /* No better match later on... */ - if (*p == '\0') - break; + Array_Reset(&gsources); + cp = parse_do_targets(&paths, &tOp, line); + if (cp == NULL || specType == SPECIAL_ERROR) + return; + + /* Have now parsed all the target names. Must parse the operator next. + * The result is left in op . */ + if (*cp == '!') { + op = OP_FORCE; + } else if (*cp == ':') { + if (cp[1] == ':') { + op = OP_DOUBLEDEP; + cp++; + } else { + op = OP_DEPENDS; } - cp++; - } - if (*cp == '(') { - LIST temp; - Lst_Init(&temp); - /* Archives must be handled specially to make sure the OP_ARCHV - * flag is set in their 'type' field, for one thing, and because - * things like "archive(file1.o file2.o file3.o)" are permissible. - * Arch_ParseArchive will set 'line' to be the first non-blank - * after the archive-spec. It creates/finds nodes for the members - * and places them on the given list, returning true if all - * went well and false if there was an error in the - * specification. On error, line should remain untouched. */ - if (!Arch_ParseArchive(&line, &temp, NULL)) { - Parse_Error(PARSE_FATAL, - "Error in archive specification: \"%s\"", line); + } else { + Parse_Error(PARSE_FATAL, "Missing dependency operator"); return; - } else { - AppendList2Array(&temp, >argets); - Lst_Destroy(&temp, NOFREE); - continue; - } } - savec = *cp; - if (*cp == '\0') { - /* Ending a dependency line without an operator is a Bozo no-no */ - Parse_Error(PARSE_FATAL, "Need an operator"); - return; - } - *cp = '\0'; - /* Have a word in line. See if it's a special target and set - * specType to match it. */ - if (*line == '.' && isupper(line[1])) { - /* See if the target is a special target that must have it - * or its sources handled specially. */ - int keywd = ParseFindKeyword(line); - if (keywd != -1) { - if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { - Parse_Error(PARSE_FATAL, "Mismatched special targets"); - return; - } + cp++; /* Advance beyond operator */ - specType = parseKeywords[keywd].spec; - tOp = parseKeywords[keywd].op; + Array_FindP(>argets, ParseDoOp, op); - /* - * Certain special targets have special semantics: - * .PATH Have to set the defaultPath - * variable too - * .MAIN Its sources are only used if - * nothing has been specified to - * create. - * .DEFAULT Need to create a node to hang - * commands on, but we don't want - * it in the graph, nor do we want - * it to be the Main Target, so we - * create it, set OP_NOTMAIN and - * add it to the list, setting - * DEFAULT to the new node for - * later use. We claim the node is - * A transformation rule to make - * life easier later, when we'll - * use Make_HandleUse to actually - * apply the .DEFAULT commands. - * .PHONY The list of targets - * .NOPATH Don't search for file in the path - * .BEGIN - * .END - * .INTERRUPT Are not to be considered the - * main target. - * .NOTPARALLEL Make only one target at a time. - * .SINGLESHELL Create a shell for each command. - * .ORDER Must set initial predecessor to NULL - */ + /* + * Get to the first source + */ + while (isspace(*cp)) + cp++; + line = cp; + + /* + * Several special targets take different actions if present with no + * sources: + * a .SUFFIXES line with no sources clears out all old suffixes + * a .PRECIOUS line makes all targets precious + * a .IGNORE line ignores errors for all targets + * a .SILENT line creates silence when making all targets + * a .PATH removes all directories from the search path(s). + */ + if (!*line) { switch (specType) { - case ExPath: - Lst_AtEnd(&paths, defaultPath); - break; - case Main: - if (!Lst_IsEmpty(create)) { - specType = Not; - } + case SPECIAL_SUFFIXES: + Suff_ClearSuffixes(); break; - case Begin: - case End: - case Interrupt: - gn = Targ_FindNode(line, TARG_CREATE); - gn->type |= OP_NOTMAIN; - Array_AtEnd(>argets, gn); + case SPECIAL_PRECIOUS: + allPrecious = true; break; - case Default: - gn = Targ_NewGN(".DEFAULT"); - gn->type |= OP_NOTMAIN|OP_TRANSFORM; - Array_AtEnd(>argets, gn); - DEFAULT = gn; + case SPECIAL_IGNORE: + ignoreErrors = true; break; - case NotParallel: - { - extern int maxJobs; - - maxJobs = 1; + case SPECIAL_SILENT: + beSilent = true; break; - } - case SingleShell: - compatMake = 1; - break; - case Order: - predecessor = NULL; + case SPECIAL_PATH: + Lst_Every(&paths, ParseClearPath); break; - default: + default: break; } - } else if (strncmp(line, ".PATH", 5) == 0) { - /* - * .PATH<suffix> has to be handled specially. - * Call on the suffix module to give us a path to - * modify. - */ - Lst path; - - specType = ExPath; - path = Suff_GetPath(&line[5]); - if (path == NULL) { - Parse_Error(PARSE_FATAL, - "Suffix '%s' not defined (yet)", - &line[5]); - return; - } else { - Lst_AtEnd(&paths, path); - } - } + } else if (specType == SPECIAL_MFLAGS) { + /*Call on functions in main.c to deal with these arguments */ + Main_ParseArgLine(line); + return; + } else if (specType == SPECIAL_NOTPARALLEL || + specType == SPECIAL_SINGLESHELL) { + return; } /* - * Have word in line. Get or create its node and stick it at - * the end of the targets list + * NOW GO FOR THE SOURCES */ - if (specType == Not && *line != '\0') { - add_target_nodes(line); - } else if (specType == ExPath && *line != '.' && *line != '\0') - Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); - - *cp = savec; - /* - * If it is a special type and not .PATH, it's the only target we - * allow on this line... - */ - if (specType != Not && specType != ExPath) { - bool warn = false; + if (specType == SPECIAL_SUFFIXES || specType == SPECIAL_PATH || + specType == SPECIAL_INCLUDES || specType == SPECIAL_LIBS || + specType == SPECIAL_NULL) { + while (*line) { + /* + * If the target was one that doesn't take files as its + * sources but takes something like suffixes, we take each + * space-separated word on the line as a something and deal + * with it accordingly. + * + * If the target was .SUFFIXES, we take each source as a + * suffix and add it to the list of suffixes maintained by + * the Suff module. + * + * If the target was a .PATH, we add the source as a + * directory to search on the search path. + * + * If it was .INCLUDES, the source is taken to be the + * suffix of files which will be #included and whose search + * path should be present in the .INCLUDES variable. + * + * If it was .LIBS, the source is taken to be the suffix of + * files which are considered libraries and whose search + * path should be present in the .LIBS variable. + * + * If it was .NULL, the source is the suffix to use when a + * file has no valid suffix. + */ + while (*cp && !isspace(*cp)) + cp++; + switch (specType) { + case SPECIAL_SUFFIXES: + Suff_AddSuffixi(line, cp); + break; + case SPECIAL_PATH: + { + LstNode ln; - while (*cp != '!' && *cp != ':' && *cp) { - if (*cp != ' ' && *cp != '\t') { - warn = true; + for (ln = Lst_First(&paths); ln != NULL; + ln = Lst_Adv(ln)) + Dir_AddDiri((Lst)Lst_Datum(ln), line, cp); + break; + } + case SPECIAL_INCLUDES: + Suff_AddIncludei(line, cp); + break; + case SPECIAL_LIBS: + Suff_AddLibi(line, cp); + break; + case SPECIAL_NULL: + Suff_SetNulli(line, cp); + break; + default: + break; + } + if (*cp != '\0') + cp++; + while (isspace(*cp)) + cp++; + line = cp; } - cp++; - } - if (warn) { - Parse_Error(PARSE_WARNING, "Extra target ignored"); - } - } else { - while (isspace(*cp)) { - cp++; - } - } - line = cp; - } while (*line != '!' && *line != ':' && *line); - - if (!Array_IsEmpty(>argets)) { - switch (specType) { - default: - Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); - break; - case Default: - case Begin: - case End: - case Interrupt: - /* These four create nodes on which to hang commands, so - * targets shouldn't be empty... */ - case Not: - /* Nothing special here -- targets can be empty if it wants. */ - break; - } - } - - /* Have now parsed all the target names. Must parse the operator next. The - * result is left in op . */ - if (*cp == '!') { - op = OP_FORCE; - } else if (*cp == ':') { - if (cp[1] == ':') { - op = OP_DOUBLEDEP; - cp++; + Lst_Destroy(&paths, NOFREE); } else { - op = OP_DEPENDS; - } - } else { - Parse_Error(PARSE_FATAL, "Missing dependency operator"); - return; - } - - cp++; /* Advance beyond operator */ + while (*line) { + /* + * The targets take real sources, so we must beware of + * archive specifications (i.e. things with left + * parentheses in them) and handle them accordingly. + */ + while (*cp && !isspace(*cp)) { + if (*cp == '(' && cp > line && cp[-1] != '$') { + /* + * Only stop for a left parenthesis if + * it isn't at the start of a word + * (that'll be for variable changes + * later) and isn't preceded by a + * dollar sign (a dynamic source). + */ + break; + } else { + cp++; + } + } - Array_Find(>argets, ParseDoOp, op); + if (*cp == '(') { + GNode *gn; + LIST sources; /* list of archive source + * names after expansion */ - /* - * Get to the first source - */ - while (isspace(*cp)) { - cp++; - } - line = cp; - - /* - * Several special targets take different actions if present with no - * sources: - * a .SUFFIXES line with no sources clears out all old suffixes - * a .PRECIOUS line makes all targets precious - * a .IGNORE line ignores errors for all targets - * a .SILENT line creates silence when making all targets - * a .PATH removes all directories from the search path(s). - */ - if (!*line) { - switch (specType) { - case Suffixes: - Suff_ClearSuffixes(); - break; - case Precious: - allPrecious = true; - break; - case Ignore: - ignoreErrors = true; - break; - case Silent: - beSilent = true; - break; - case ExPath: - Lst_Every(&paths, ParseClearPath); - break; - default: - break; - } - } else if (specType == MFlags) { - /* - * Call on functions in main.c to deal with these arguments and - * set the initial character to a null-character so the loop to - * get sources won't get anything - */ - Main_ParseArgLine(line); - *line = '\0'; - } else if (specType == NotParallel || specType == SingleShell) { - *line = '\0'; - } + Lst_Init(&sources); + if (!Arch_ParseArchive(&line, &sources, NULL)) { + Parse_Error(PARSE_FATAL, + "Error in source archive spec \"%s\"", + line); + return; + } - /* - * NOW GO FOR THE SOURCES - */ - if (specType == Suffixes || specType == ExPath || - specType == Includes || specType == Libs || - specType == Null) { - while (*line) { - /* - * If the target was one that doesn't take files as its sources - * but takes something like suffixes, we take each - * space-separated word on the line as a something and deal - * with it accordingly. - * - * If the target was .SUFFIXES, we take each source as a - * suffix and add it to the list of suffixes maintained by the - * Suff module. - * - * If the target was a .PATH, we add the source as a directory - * to search on the search path. - * - * If it was .INCLUDES, the source is taken to be the suffix of - * files which will be #included and whose search path should - * be present in the .INCLUDES variable. - * - * If it was .LIBS, the source is taken to be the suffix of - * files which are considered libraries and whose search path - * should be present in the .LIBS variable. - * - * If it was .NULL, the source is the suffix to use when a file - * has no valid suffix. - */ - char savec; - while (*cp && !isspace(*cp)) { - cp++; - } - savec = *cp; - *cp = '\0'; - switch (specType) { - case Suffixes: - Suff_AddSuffix(line); - break; - case ExPath: - Lst_ForEach(&paths, ParseAddDir, line); - break; - case Includes: - Suff_AddInclude(line); - break; - case Libs: - Suff_AddLib(line); - break; - case Null: - Suff_SetNull(line); - break; - default: - break; - } - *cp = savec; - if (savec != '\0') { - cp++; - } - while (isspace(*cp)) { - cp++; - } - line = cp; - } - Lst_Destroy(&paths, NOFREE); - } else { - while (*line) { - /* - * The targets take real sources, so we must beware of archive - * specifications (i.e. things with left parentheses in them) - * and handle them accordingly. - */ - while (*cp && !isspace(*cp)) { - if (*cp == '(' && cp > line && cp[-1] != '$') { - /* - * Only stop for a left parenthesis if it isn't at the - * start of a word (that'll be for variable changes - * later) and isn't preceded by a dollar sign (a dynamic - * source). - */ - break; - } else { - cp++; - } - } - - if (*cp == '(') { - GNode *gn; - LIST sources; /* list of archive source names after - * expansion */ - - Lst_Init(&sources); - if (!Arch_ParseArchive(&line, &sources, NULL)) { - Parse_Error(PARSE_FATAL, - "Error in source archive spec \"%s\"", line); - return; - } + while ((gn = (GNode *)Lst_DeQueue(&sources)) != + NULL) + ParseDoSrc(>argets, &gsources, tOp, + gn->name, NULL); + cp = line; + } else { + const char *endSrc = cp; - while ((gn = (GNode *)Lst_DeQueue(&sources)) != NULL) - ParseDoSrc(tOp, gn->name); - cp = line; - } else { - if (*cp) { - *cp = '\0'; - cp++; + ParseDoSrc(>argets, &gsources, tOp, line, + endSrc); + if (*cp) + cp++; + } + while (isspace(*cp)) + cp++; + line = cp; } - - ParseDoSrc(tOp, line); - } - while (isspace(*cp)) { - cp++; - } - line = cp; } - } - - if (mainNode == NULL) { - /* If we have yet to decide on a main target to make, in the - * absence of any user input, we want the first target on - * the first dependency line that is actually a real target - * (i.e. isn't a .USE or .EXEC rule) to be made. */ - Array_Find(>argets, ParseFindMain, NULL); - } - /* Finally, destroy the list of sources. */ + if (mainNode == NULL) { + /* If we have yet to decide on a main target to make, in the + * absence of any user input, we want the first target on + * the first dependency line that is actually a real target + * (i.e. isn't a .USE or .EXEC rule) to be made. */ + Array_Find(>argets, ParseFindMain, NULL); + } } /*- @@ -1114,13 +1024,11 @@ static void ParseHasCommands(void *gnp) /* Node to examine */ { GNode *gn = (GNode *)gnp; - if (!Lst_IsEmpty(&gn->commands)) { + if (!Lst_IsEmpty(&gn->commands)) gn->type |= OP_HAS_COMMANDS; - } } - /* Strip comments from line. Build a copy in buffer if necessary, */ static char * strip_comments(Buffer copy, const char *line) @@ -1399,6 +1307,7 @@ handle_poison(const char *line) } } + static bool handle_for_loop(Buffer linebuf, const char *line) { @@ -1436,6 +1345,7 @@ handle_undef(const char *line) return true; } +/* global hub for the construct */ static bool handle_bsd_command(Buffer linebuf, Buffer copy, const char *line) { @@ -1481,7 +1391,6 @@ handle_bsd_command(Buffer linebuf, Buffer copy, const char *line) static void finish_commands(struct growableArray *targets) { - Array_Every(targets, Suff_EndTransform); Array_Every(targets, ParseHasCommands); Array_Reset(targets); } @@ -1632,8 +1541,9 @@ Parse_Init(void) mainNode = NULL; Static_Lst_Init(userIncludePath); Static_Lst_Init(systemIncludePath); - Array_Init(&gsources, SOURCES_SIZE); Array_Init(>argets, TARGETS_SIZE); + Array_Init(&gsources, SOURCES_SIZE); + create_special_nodes(); LowParse_Init(); #ifdef CLEANUP @@ -1657,14 +1567,14 @@ void Parse_MainName(Lst listmain) /* result list */ { - if (mainNode == NULL) { - Punt("no target to make."); - /*NOTREACHED*/ - } else if (mainNode->type & OP_DOUBLEDEP) { - Lst_AtEnd(listmain, mainNode); - Lst_Concat(listmain, &mainNode->cohorts); - } - else - Lst_AtEnd(listmain, mainNode); + if (mainNode == NULL) { + Punt("no target to make."); + /*NOTREACHED*/ + } else if (mainNode->type & OP_DOUBLEDEP) { + Lst_AtEnd(listmain, mainNode); + Lst_Concat(listmain, &mainNode->cohorts); + } + else + Lst_AtEnd(listmain, mainNode); } diff --git a/usr.bin/make/suff.c b/usr.bin/make/suff.c index c362329ee11..45aface4c09 100644 --- a/usr.bin/make/suff.c +++ b/usr.bin/make/suff.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: suff.c,v 1.69 2007/09/17 11:43:12 espie Exp $ */ +/* $OpenBSD: suff.c,v 1.70 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: suff.c,v 1.13 1996/11/06 17:59:25 christos Exp $ */ /* @@ -46,25 +46,9 @@ * * Suff_End Cleanup the module * - * Suff_DoPaths This function is used to make life easier - * when searching for a file according to its - * suffix. It takes the global search path, - * as defined using the .PATH: target, and appends - * its directories to the path of each of the - * defined suffixes, as specified using - * .PATH<suffix>: targets. In addition, all - * directories given for suffixes labeled as - * include files or libraries, using the .INCLUDES - * or .LIBS targets, are played with using - * Dir_MakeFlags to create the .INCLUDES and - * .LIBS global variables. - * * Suff_ClearSuffixes Clear out all the suffixes and defined * transformations. * - * Suff_IsTransform Return true if the passed string is the lhs - * of a transformation rule. - * * Suff_AddSuffix Add the passed string as another known suffix. * * Suff_GetPath Return the search path for the given suffix. @@ -74,9 +58,11 @@ * * Suff_AddLib Mark the given suffix as denoting a library. * - * Suff_AddTransform Add another transformation to the suffix - * graph. Returns GNode suitable for framing, I - * mean, tacking commands, attributes, etc. on. + * Suff_ParseAsTransform Line might be a suffix line, check it. + * If it's not, return NULL. Otherwise, add + * another transformation to the suffix graph. + * Returns GNode suitable for framing, I mean, + * tacking commands, attributes, etc. on. * * Suff_SetNull Define the suffix to consider the suffix of * any file that doesn't have a known one. @@ -87,14 +73,40 @@ * 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 <stdio.h> #include <stdlib.h> +#include <stdint.h> +#include <stddef.h> #include <string.h> +#include <ohash.h> #include "config.h" #include "defines.h" #include "dir.h" #include "direxpand.h" +#include "engine.h" #include "arch.h" #include "suff.h" #include "var.h" @@ -104,15 +116,13 @@ #include "lst.h" #include "memory.h" #include "gnode.h" +#include "make.h" #include "stats.h" -#include "engine.h" -static LIST sufflist; /* Lst of suffixes */ -#ifdef CLEANUP -static LIST suffClean; /* Lst of suffixes to be cleaned */ -#endif +static struct ohash suffixes; /* hash of suffixes */ +size_t maxLen; /* optimization: remember longest suffix */ static LIST srclist; /* Lst of sources */ -static LIST transforms; /* Lst of transformation rules */ +static struct ohash transforms; static int sNum = 0; /* Counter for assigning suffix numbers */ @@ -120,33 +130,38 @@ static int sNum = 0; /* Counter for assigning suffix numbers */ * Structure describing an individual suffix. */ typedef struct Suff_ { - char *name; /* The suffix itself */ - int nameLen; /* Length of the suffix */ - short flags; /* Type of suffix */ -#define SUFF_INCLUDE 0x01 /* One which is #include'd */ -#define SUFF_LIBRARY 0x02 /* One which contains a library */ -#define SUFF_NULL 0x04 /* The empty suffix */ - LIST searchPath; /* The path along which files of this suffix - * may be found */ - int sNum; /* The suffix number */ - LIST parents; /* Suffixes we have a transformation to */ - LIST children; /* Suffixes we have a transformation from */ - LIST ref; /* List of lists this suffix is referenced */ + size_t nameLen; /* Length of the suffix */ + short flags; /* Type of suffix */ +#define SUFF_INCLUDE 0x01 /* One which is #include'd */ +#define SUFF_LIBRARY 0x02 /* One which contains a library */ +#define SUFF_NULL 0x04 /* The empty suffix */ +#define SUFF_EXISTS 0x08 /* So that we don't have to destroy them */ +#define SUFF_PATH 0x10 /* False suffix: actually, the path keyword */ + LIST searchPath; /* The path along which files of this suffix + * may be found */ + int sNum; /* The suffix number */ + LIST parents; /* Suffixes we have a transformation to */ + LIST children; /* Suffixes we have a transformation from */ + char name[1]; /* The suffix itself */ } Suff; +static struct ohash_info suff_info = { + offsetof(struct Suff_, name), NULL, hash_alloc, hash_free, element_alloc +}; + /* * Structure used in the search for implied sources. */ typedef struct Src_ { - char *file; /* The file to look for */ - char *pref; /* Prefix from which file was formed */ - Suff *suff; /* The suffix on the file */ - struct Src_ *parent; /* The Src for which this is a source */ - GNode *node; /* The node describing the file */ - int children; /* Count of existing children (so we don't free + char *file; /* The file to look for */ + char *pref; /* Prefix from which file was formed */ + Suff *suff; /* The suffix on the file */ + struct Src_ *parent; /* The Src for which this is a source */ + GNode *node; /* The node describing the file */ + int children; /* Count of existing children (so we don't free * this thing too early or never nuke it) */ #ifdef DEBUG_SRC - LIST cp; /* Debug; children list */ + LIST cp; /* Debug; children list */ #endif } Src; @@ -155,28 +170,34 @@ typedef struct Src_ { * function... */ typedef struct { - Lst l; - Src *s; + Lst l; + Src *s; } LstSrc; -static Suff *suffNull; /* The NULL suffix for this run */ -static Suff *emptySuff; /* The empty suffix required for POSIX - * single-suffix transformation rules */ +static Suff *suffNull; /* The NULL suffix for this run */ +static Suff *emptySuff; /* The empty suffix required for POSIX + * single-suffix transformation rules */ + + +static void build_path_variable(struct ohash *, int, const char *, const char *); +static void add_property(const char *, const char *, int); +#define parse_transform(s, p, q) parse_transformi(s, s + strlen(s), p, q) +static bool parse_transformi(const char *, const char *, Suff **, Suff **); +#define new_suffix(s) new_suffixi(s, NULL) +static Suff *new_suffixi(const char *, const char *); +static void reverse_hash_add_char(uint32_t *, const char *); +static uint32_t reverse_hashi(const char *, const char **); +static unsigned int reverse_slot(struct ohash *, const char *, const char **); +static void clear_suffixes(void); +static void record_possible_suffix(Suff *, GNode *, char *, Lst, Lst); +static void record_possible_suffixes(GNode *, Lst, Lst); +static Suff *find_suffix_as_suffix(Lst, const char *, const char *); +static Suff *add_suffixi(const char *, const char *); - -static char *SuffStrIsPrefix(const char *, const char *); -static char *SuffSuffIsSuffix(Suff *, const char *); -static int SuffSuffIsSuffixP(void *, const void *); -static int SuffSuffIsPrefix(void *, const void *); -static int SuffHasNameP(void *, const void *); -static int GNodeHasNameP(void *, const void *); -static void SuffUnRef(Lst, Suff *); #ifdef CLEANUP static void SuffFree(void *); #endif static void SuffInsert(Lst, Suff *); -static bool SuffParseTransform(const char *, Suff **, Suff **); -static void SuffRebuildGraph(void *, void *); static void SuffAddSrc(void *, void *); static int SuffRemoveSrc(Lst); static void SuffAddLevel(Lst, Src *); @@ -191,54 +212,71 @@ static void SuffFindArchiveDeps(GNode *, Lst); static void SuffFindNormalDeps(GNode *, Lst); static void SuffPrintName(void *); static void SuffPrintSuff(void *); -static void SuffPrintTrans(void *); +static void SuffPrintTrans(GNode *); -static LstNode suff_find_by_name(const char *); -static LstNode transform_find_by_name(const char *); +#define find_suff(name) find_suffi(name, NULL) +static Suff *find_suffi(const char *, const char *); +static Suff *find_best_suffix(const char *, const char *); +static GNode *find_transform(const char *); +static GNode *find_or_create_transformi(const char *, const char *); +static void setup_paths(void); +static void build_suffixes_graph(void); +static void special_path_hack(void); #ifdef DEBUG_SRC static void PrintAddr(void *); #endif - /*************** Lst Predicates ****************/ -/*- - *----------------------------------------------------------------------- - * SuffStrIsPrefix -- - * See if prefix is a prefix of str. - * - * Results: - * NULL if it ain't, pointer to character in str after prefix if so - *----------------------------------------------------------------------- + +/* we usually look at suffixes `backwards', which makes it necessary for + * us to have a specific hash function that proceeds backwards. */ -static char * -SuffStrIsPrefix(const char *prefix, const char *str) + + +static void +reverse_hash_add_char(uint32_t *pk, const char *s) { - while (*str && *prefix == *str) { - prefix++; - str++; + *pk = ((*pk << 2) | (*pk >> 30)) ^ *s; +} + +static uint32_t +reverse_hashi(const char *s, const char **e) +{ + const char *p; + uint32_t k; + + if (*e == NULL) + *e = s + strlen(s); + p = *e; + if (p == s) + k = 0; + else + k = *--p; + while (p != s) { + reverse_hash_add_char(&k, --p); } + return k; +} - return *prefix ? NULL : (char *)str; +static unsigned int +reverse_slot(struct ohash *h, const char *s, const char **e) +{ + uint32_t hv; + + hv = reverse_hashi(s, e); + return ohash_lookup_interval(h, s, *e, hv); } -/*- - *----------------------------------------------------------------------- - * SuffSuffIsSuffix -- - * See if suff is a suffix of str. str should point to the end of the - * string to check. - * - * Results: - * NULL if it ain't, pointer to first character of suffix in str if - * it is. - *----------------------------------------------------------------------- - */ + static char * -SuffSuffIsSuffix(Suff *s, const char *str) +suffix_is_suffix(Suff *s, const char *str, const char *estr) { - const char *p1; /* Pointer into suffix name */ - const char *p2; /* Pointer into string being examined */ + const char *p1; /* Pointer into suffix name */ + const char *p2; /* Pointer into string being examined */ + if (estr - str < (ptrdiff_t) s->nameLen) + return NULL; p1 = s->name + s->nameLen; - p2 = str; + p2 = estr; while (p1 != s->name) { p1--; @@ -250,79 +288,49 @@ SuffSuffIsSuffix(Suff *s, const char *str) return (char *)p2; } -/*- - *----------------------------------------------------------------------- - * SuffSuffIsSuffixP -- - * Predicate form of SuffSuffIsSuffix. Passed as the callback function - * to Lst_Find. - * - * Results: - * 0 if the suffix is the one desired, non-zero if not. - *----------------------------------------------------------------------- - */ -static int -SuffSuffIsSuffixP(void *s, const void *str) +static Suff * +find_suffi(const char *name, const char *ename) { - return !SuffSuffIsSuffix((Suff *)s, (const char *)str); + unsigned int slot; +#ifdef STATS_SUFF + STAT_SUFF_LOOKUP_NAME++; +#endif + slot = reverse_slot(&suffixes, name, &ename); + return ohash_find(&suffixes, slot); } -static int -SuffHasNameP(void *s, const void *sname) +static GNode * +find_transform(const char *name) { - return strcmp((const char *)sname, ((Suff *)s)->name); -} + unsigned int slot; -static LstNode -suff_find_by_name(const char *name) -{ #ifdef STATS_SUFF - STAT_SUFF_LOOKUP_NAME++; + STAT_TRANSFORM_LOOKUP_NAME++; #endif - return Lst_FindConst(&sufflist, SuffHasNameP, name); -} + slot = ohash_qlookup(&transforms, name); -static int -GNodeHasNameP(void *gn, const void *name) -{ - return strcmp((const char *)name, ((GNode *)gn)->name); + return ohash_find(&transforms, slot); } -static LstNode -transform_find_by_name(const char *name) +static GNode * +find_or_create_transformi(const char *name, const char *end) { + GNode *r; + unsigned int slot; + #ifdef STATS_SUFF STAT_TRANSFORM_LOOKUP_NAME++; #endif - return Lst_FindConst(&transforms, GNodeHasNameP, name); -} -/*- - *----------------------------------------------------------------------- - * SuffSuffIsPrefix -- - * See if the suffix described by s is a prefix of the string. Care - * must be taken when using this to search for transformations and - * what-not, since there could well be two suffixes, one of which - * is a prefix of the other... - * - * Results: - * 0 if s is a prefix of str. non-zero otherwise - *----------------------------------------------------------------------- - */ -static int -SuffSuffIsPrefix(void *s, const void *str) -{ - return SuffStrIsPrefix(((Suff *)s)->name, - (const char *)str) == NULL ? 1 : 0; -} + slot = ohash_qlookupi(&transforms, name, &end); - /*********** Maintenance Functions ************/ + r = ohash_find(&transforms, slot); -static void -SuffUnRef(Lst l, Suff *sp) -{ - LstNode ln = Lst_Member(l, sp); - if (ln != NULL) - Lst_Remove(l, ln); - } + if (r == NULL) { + r = Targ_NewGNi(name, end); + ohash_insert(&transforms, slot, r); + } + return r; +} #ifdef CLEANUP /*- @@ -337,15 +345,11 @@ SuffUnRef(Lst l, Suff *sp) static void SuffFree(void *sp) { - Suff *s = (Suff *)sp; - - if (s == suffNull) - suffNull = NULL; + Suff *s = (Suff *)sp; if (s == emptySuff) emptySuff = NULL; - Lst_Destroy(&s->ref, NOFREE); Lst_Destroy(&s->children, NOFREE); Lst_Destroy(&s->parents, NOFREE); Lst_Destroy(&s->searchPath, Dir_Destroy); @@ -369,8 +373,8 @@ SuffFree(void *sp) static void SuffInsert(Lst l, Suff *s) { - LstNode ln; /* current element in l we're examining */ - Suff *s2 = NULL; /* the suffix descriptor in this element */ + LstNode ln; /* current element in l we're examining */ + Suff *s2 = NULL; /* the suffix descriptor in this element */ for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { s2 = (Suff *)Lst_Datum(ln); @@ -378,21 +382,16 @@ SuffInsert(Lst l, Suff *s) break; } - if (DEBUG(SUFF)) { + if (DEBUG(SUFF)) printf("inserting %s(%d)...", s->name, s->sNum); - } if (ln == NULL) { - if (DEBUG(SUFF)) { + if (DEBUG(SUFF)) printf("at end of list\n"); - } Lst_AtEnd(l, s); - Lst_AtEnd(&s->ref, l); } else if (s2->sNum != s->sNum) { - if (DEBUG(SUFF)) { + if (DEBUG(SUFF)) printf("before %s(%d)\n", s2->name, s2->sNum); - } Lst_Insert(l, ln, s); - Lst_AtEnd(&s->ref, l); } else if (DEBUG(SUFF)) { printf("already there\n"); } @@ -401,359 +400,329 @@ SuffInsert(Lst l, Suff *s) /*- *----------------------------------------------------------------------- * Suff_ClearSuffixes -- - * This is gross. Nuke the list of suffixes but keep all transformation - * rules around. The transformation graph is destroyed in this process, - * but we leave the list of rules so when a new graph is formed the rules - * will remain. - * This function is called from the parse module when a - * .SUFFIXES:\n line is encountered. + * Nuke the list of suffixes but keep all transformation + * rules around. * * Side Effects: - * the sufflist and its graph nodes are destroyed + * Current suffixes are reset *----------------------------------------------------------------------- */ -void -Suff_ClearSuffixes(void) +static void +clear_suffixes(void) { -#ifdef CLEANUP - Lst_ConcatDestroy(&suffClean, &sufflist); -#endif - Lst_Init(&sufflist); + unsigned int i; + Suff *s; + + for (s = ohash_first(&suffixes, &i); s != NULL; + s = ohash_next(&suffixes, &i)) + s->flags &= ~SUFF_EXISTS; + sNum = 0; + maxLen = 0; suffNull = emptySuff; } -/*- - *----------------------------------------------------------------------- - * SuffParseTransform -- - * Parse a transformation string to find its two component suffixes. - * - * Results: - * true if the string is a valid transformation and false otherwise. - * - * Side Effects: - * The passed pointers are overwritten. - *----------------------------------------------------------------------- +void +Suff_ClearSuffixes(void) +{ + clear_suffixes(); +} + + +/* okay = parse_transform(str, &src, &targ); + * try parsing a string as a transformation rule, returns true if + * successful. Fills &src, &targ with the constituent suffixes. + * Special hack: source suffixes must exist OR be the special SUFF_PATH + * pseudo suffix (.PATH) */ static bool -SuffParseTransform( - const char *str, /* String being parsed */ - Suff **srcPtr, /* Place to store source of trans. */ - Suff **targPtr) /* Place to store target of trans. */ +parse_transformi(const char *str, const char *e, Suff **srcPtr, Suff **targPtr) { - LstNode srcLn; /* element in suffix list of trans source*/ - Suff *src; /* Source of transformation */ - LstNode targLn; /* element in suffix list of trans target*/ - const char *str2; /* Extra pointer (maybe target suffix) */ - LstNode singleLn; /* element in suffix list of any suffix - * that exactly matches str */ - Suff *single = NULL;/* Source of possible transformation to - * null suffix */ - - srcLn = NULL; - singleLn = NULL; + Suff *src, *target, *best_src, *best_target; + const char *p; - /* - * Loop looking first for a suffix that matches the start of the - * string and then for one that exactly matches the rest of it. If - * we can find two that meet these criteria, we've successfully - * parsed the string. - */ - for (;;) { - if (srcLn == NULL) - srcLn = Lst_FindConst(&sufflist, SuffSuffIsPrefix, str); - else - srcLn = Lst_FindFromConst(Lst_Succ(srcLn), - SuffSuffIsPrefix, str); - if (srcLn == NULL) { - /* - * Ran out of source suffixes -- no such rule - */ - if (singleLn != NULL) { - /* - * Not so fast Mr. Smith! There was a suffix - * that encompassed the entire string, so we - * assume it was a transformation to the null - * suffix (thank you POSIX). We still prefer to - * find a double rule over a singleton, hence - * we leave this check until the end. - * - * XXX: Use emptySuff over suffNull? + size_t len; + uint32_t hv; + unsigned int slot; + + /* empty string -> no suffix */ + if (e == str) + return false; + + len = e - str; + + if (len > 2 * maxLen) + return false; + + p = e; + best_src = best_target = NULL; + + hv = *--p; + while (p != str) { + slot = ohash_lookup_interval(&suffixes, p, e, hv); + /* no double suffix in there */ + if (p - str <= (ptrdiff_t)maxLen) { + target = ohash_find(&suffixes, slot); + if (target != NULL && (target->flags & SUFF_EXISTS)) { + src = find_suffi(str, p); + if (src != NULL && + (src->flags & (SUFF_EXISTS | SUFF_PATH))) { + /* XXX even if we find a set of suffixes, we + * have to keep going to find the best one, + * namely, the one whose src appears first in + * .SUFFIXES */ - *srcPtr = single; - *targPtr = suffNull; - return true; + if (best_src == NULL || + src->sNum < best_src->sNum) { + best_src = src; + best_target = target; + } + } } - return false; } - src = (Suff *)Lst_Datum(srcLn); - str2 = str + src->nameLen; - if (*str2 == '\0') { - single = src; - singleLn = srcLn; - } else { - targLn = suff_find_by_name(str2); - if (targLn != NULL) { - *srcPtr = src; - *targPtr = (Suff *)Lst_Datum(targLn); - return true; - } + /* can't be a suffix anyways */ + if (e - p >= (ptrdiff_t)maxLen) + break; + reverse_hash_add_char(&hv, --p); + } + + if (p == str && best_src == NULL) { + /* no double suffix transformation, resort to single suffix if + * we find one. */ + slot = ohash_lookup_interval(&suffixes, p, e, hv); + src = ohash_find(&suffixes, slot); + if (src != NULL && (src->flags & (SUFF_EXISTS | SUFF_PATH))) { + best_src = src; + best_target = suffNull; } } + if (best_src != NULL) { + *srcPtr = best_src; + *targPtr = best_target; + return true; + } else { + return false; + } } -/*- - *----------------------------------------------------------------------- - * Suff_IsTransform -- - * Return true if the given string is a transformation rule - * - * Results: - * true if the string is a concatenation of two known suffixes. - * false otherwise - *----------------------------------------------------------------------- - */ -bool -Suff_IsTransform(const char *str) +static void +special_path_hack(void) +{ + Suff *path = add_suffixi(".PATH", NULL); + path->flags |= SUFF_PATH; +} + +static Suff * +find_best_suffix(const char *s, const char *e) { - Suff *src, *targ; + const char *p; + uint32_t hv; + unsigned int slot; + Suff *best = NULL; + Suff *suff; - return SuffParseTransform(str, &src, &targ); + if (e == s) + return NULL; + p = e; + hv = *--p; + while (p != s) { + slot = ohash_lookup_interval(&suffixes, p, e, hv); + suff = ohash_find(&suffixes, slot); + if (suff != NULL) + if (best == NULL || suff->sNum < best->sNum) + best = suff; + if (e - p >= (ptrdiff_t)maxLen) + break; + reverse_hash_add_char(&hv, --p); + } + return best; } /*- *----------------------------------------------------------------------- - * Suff_AddTransform -- - * Add the transformation rule described by the line to the - * list of rules and place the transformation itself in the graph - * - * Results: - * The node created for the transformation in the transforms list + * Suff_ParseAsTransform -- + * Try parsing a target line as a transformation rule, depending on + * existing suffixes. * - * Side Effects: - * The node is placed on the end of the transforms Lst and links are - * made between the two suffixes mentioned in the target name + * Possibly create anew transform, or reset an existing one. *----------------------------------------------------------------------- */ GNode * -Suff_AddTransform(const char *line) +Suff_ParseAsTransform(const char *line, const char *end) { - GNode *gn; /* GNode of transformation rule */ - Suff *s, /* source suffix */ - *t; /* target suffix */ - LstNode ln; /* Node for existing transformation */ + GNode *gn; /* GNode of transformation rule */ + Suff *s; /* source suffix */ + Suff *t; /* target suffix */ - ln = transform_find_by_name(line); - if (ln == NULL) { - /* - * Make a new graph node for the transformation. It will be - * filled in by the Parse module. - */ - gn = Targ_NewGN(line); - Lst_AtEnd(&transforms, gn); - } else { - /* - * New specification for transformation rule. Just nuke the old - * list of commands so they can be filled in again... We don't - * actually free the commands themselves, because a given - * command can be attached to several different - * transformations. - */ - gn = (GNode *)Lst_Datum(ln); + if (!parse_transformi(line, end, &s, &t)) + return NULL; + + gn = find_or_create_transformi(line, end); + /* In case the transform already exists, nuke old commands and children. + * Note we can't free them, since there might be stuff that references + * them elsewhere + */ + if (!Lst_IsEmpty(&gn->commands)) { Lst_Destroy(&gn->commands, NOFREE); Lst_Init(&gn->commands); + } + if (!Lst_IsEmpty(&gn->children)) { Lst_Destroy(&gn->children, NOFREE); Lst_Init(&gn->children); } gn->type = OP_TRANSFORM; + if (s->flags & SUFF_PATH) { + gn->special = SPECIAL_PATH | SPECIAL_TARGET; + gn->suffix = t; + } - (void)SuffParseTransform(line, &s, &t); - - /* - * link the two together in the proper relationship and order - */ - if (DEBUG(SUFF)) { + if (DEBUG(SUFF)) printf("defining transformation from `%s' to `%s'\n", s->name, t->name); + return gn; +} + +static void +make_suffix_known(Suff *s) +{ + if ((s->flags & SUFF_EXISTS) == 0) { + s->sNum = sNum++; + s->flags |= SUFF_EXISTS; + if (s->nameLen > maxLen) + maxLen = s->nameLen; } - SuffInsert(&t->children, s); - SuffInsert(&s->parents, t); +} - return gn; +static Suff * +new_suffixi(const char *str, const char *eptr) +{ + Suff *s; + + s = ohash_create_entry(&suff_info, str, &eptr); + s->nameLen = eptr - str; + Lst_Init(&s->searchPath); + Lst_Init(&s->children); + Lst_Init(&s->parents); + s->flags = 0; + return s; } /*- *----------------------------------------------------------------------- - * Suff_EndTransform -- - * Handle the finish of a transformation definition, removing the - * transformation from the graph if it has neither commands nor - * sources. This is a callback procedure for the Parse module via - * Lst_ForEach + * Suff_AddSuffix -- + * Add the suffix in string to the end of the list of known suffixes. + * Should we restructure the suffix graph? Make doesn't... * * Side Effects: - * If the node has no commands or children, the children and parents - * lists of the affected suffices are altered. + * A GNode is created for the suffix and a Suff structure is created and + * added to the known suffixes, unless it was already known. *----------------------------------------------------------------------- */ void -Suff_EndTransform(void *gnp) +Suff_AddSuffixi(const char *str, const char *end) { - GNode *gn = (GNode *)gnp; - - if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(&gn->commands) && - Lst_IsEmpty(&gn->children)) { - Suff *s, *t; - - if (!SuffParseTransform(gn->name, &s, &t)) - return; + (void)add_suffixi(str, end); +} - if (DEBUG(SUFF)) { - printf("deleting transformation from `%s' to `%s'\n", - s->name, t->name); - } +static Suff * +add_suffixi(const char *str, const char *end) +{ + Suff *s; /* new suffix descriptor */ - /* - * Remove the source from the target's children list. - * - * We'll be called twice when the next target is seen, but .c - * and .o are only linked once... - */ - SuffUnRef(&t->children, s); + unsigned int slot; - /* - * Remove the target from the source's parents list - */ - if (s != NULL) - SuffUnRef(&s->parents, t); - } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) { - printf("transformation %s complete\n", gn->name); + slot = reverse_slot(&suffixes, str, &end); + s = ohash_find(&suffixes, slot); + if (s == NULL) { + s = new_suffixi(str, end); + ohash_insert(&suffixes, slot, s); } + make_suffix_known(s); + return s; } -/*- - *----------------------------------------------------------------------- - * SuffRebuildGraph -- - * Called from Suff_AddSuffix via Lst_ForEach to search through the - * list of existing transformation rules and rebuild the transformation - * graph when it has been destroyed by Suff_ClearSuffixes. If the - * given rule is a transformation involving this suffix and another, - * existing suffix, the proper relationship is established between - * the two. - * - * Side Effects: - * The appropriate links will be made between this suffix and - * others if transformation rules exist for it. - *----------------------------------------------------------------------- +Lst +find_suffix_path(GNode *gn) +{ + if (gn->suffix != NULL && gn->suffix != emptySuff) + return &(gn->suffix->searchPath); + else + return defaultPath; +} + +/* find out the tagged suffixes, build a temporary path, and construct + * a variable based on that. */ static void -SuffRebuildGraph( - void *transformp, /* Transformation to test */ - void *sp) /* Suffix to rebuild */ +build_path_variable(struct ohash *h, int opt, const char *name, + const char *flag) { - GNode *transform = (GNode *)transformp; - Suff *s = (Suff *)sp; - char *cp; - LstNode ln; - Suff *s2; - - /* First see if it is a transformation from this suffix. */ - cp = SuffStrIsPrefix(s->name, transform->name); - if (cp != NULL) { - ln = suff_find_by_name(cp); - if (ln != NULL) { - /* Found target. Link in and return, since it can't be - * anything else. */ - s2 = (Suff *)Lst_Datum(ln); - SuffInsert(&s2->children, s); - SuffInsert(&s->parents, s2); - return; - } + char *value; + LIST path; + Suff *s; + unsigned int i; + + Lst_Init(&path); + for (s = ohash_first(h, &i); s != NULL; s = ohash_next(h, &i)) { + if (Lst_IsEmpty(&s->searchPath)) + continue; + if (s->flags & opt) + Dir_Concat(&path, &s->searchPath); } - /* Not from, maybe to? */ - cp = SuffSuffIsSuffix(s, transform->name + strlen(transform->name)); - if (cp != NULL) { - /* Null-terminate the source suffix in order to find it. */ - *cp = '\0'; - ln = suff_find_by_name(transform->name); - /* Replace the start of the target suffix. */ - *cp = s->name[0]; - if (ln != NULL) { - /* Found it -- establish the proper relationship. */ - s2 = (Suff *)Lst_Datum(ln); - SuffInsert(&s->children, s2); - SuffInsert(&s2->parents, s); - } + value = Dir_MakeFlags(flag, &path); + Var_Set(name, value); + free(value); + Lst_Destroy(&path, Dir_Destroy); +} + +static void +add_property(const char *sname, const char *end, int opt) +{ + Suff *s; + + s = find_suffi(sname, end); + if (s != NULL) { + s->flags |= opt; } } -/*- - *----------------------------------------------------------------------- - * Suff_AddSuffix -- - * Add the suffix in string to the end of the list of known suffixes. - * Should we restructure the suffix graph? Make doesn't... - * - * Side Effects: - * A GNode is created for the suffix and a Suff structure is created and - * added to the suffixes list unless the suffix was already known. - *----------------------------------------------------------------------- - */ void -Suff_AddSuffix(const char *str) +Suff_AddIncludei(const char *sname, const char *end) { - Suff *s; /* new suffix descriptor */ - LstNode ln; + add_property(sname, end, SUFF_INCLUDE); +} - ln = suff_find_by_name(str); - if (ln == NULL) { - s = emalloc(sizeof(Suff)); - - s->name = estrdup(str); - s->nameLen = strlen(s->name); - Lst_Init(&s->searchPath); - Lst_Init(&s->children); - Lst_Init(&s->parents); - Lst_Init(&s->ref); - s->sNum = sNum++; - s->flags = 0; - - Lst_AtEnd(&sufflist, s); - /* - * Look for any existing transformations from or to this suffix. - * XXX: Only do this after a Suff_ClearSuffixes? - */ - Lst_ForEach(&transforms, SuffRebuildGraph, s); - } +void +Suff_AddLibi(const char *sname, const char *end) +{ + add_property(sname, end, SUFF_LIBRARY); } -/*- - *----------------------------------------------------------------------- - * Suff_GetPath -- - * Return the search path for the given suffix, if it's defined. - * - * Results: - * The searchPath for the desired suffix or NULL if the suffix isn't - * defined. - *----------------------------------------------------------------------- - */ -Lst -Suff_GetPath(const char *sname) +static void +build_suffixes_graph(void) { - LstNode ln; - Suff *s; + Suff *s, *s2; + GNode *gn; + unsigned int i; - ln = suff_find_by_name(sname); - if (ln == NULL) { - return NULL; - } else { - s = (Suff *)Lst_Datum(ln); - return &s->searchPath; + for (gn = ohash_first(&transforms, &i); gn != NULL; + gn = ohash_next(&transforms, &i)) { + if (Lst_IsEmpty(&gn->commands) && Lst_IsEmpty(&gn->children)) + continue; + if ((gn->special & SPECIAL_MASK) == SPECIAL_PATH) + continue; + if (parse_transform(gn->name, &s, &s2)) { + SuffInsert(&s2->children, s); + SuffInsert(&s->parents, s2); + } } } /*- *----------------------------------------------------------------------- - * Suff_DoPaths -- + * setup_paths * Extend the search paths for all suffixes to include the default * search path. * @@ -766,90 +735,34 @@ Suff_GetPath(const char *sname) * ".LIBS" and the flag is -L. *----------------------------------------------------------------------- */ -void -Suff_DoPaths(void) +static void +setup_paths(void) { - Suff *s; - LstNode ln; - char *ptr; - LIST inIncludes; /* Cumulative .INCLUDES path */ - LIST inLibs; /* Cumulative .LIBS path */ - - Lst_Init(&inIncludes); - Lst_Init(&inLibs); + unsigned int i; + Suff *s; - for (ln = Lst_First(&sufflist); ln != NULL; ln = Lst_Adv(ln)) { - s = (Suff *)Lst_Datum(ln); - if (!Lst_IsEmpty(&s->searchPath)) { - if (s->flags & SUFF_INCLUDE) { - Dir_Concat(&inIncludes, &s->searchPath); - } - if (s->flags & SUFF_LIBRARY) { - Dir_Concat(&inLibs, &s->searchPath); - } + for (s = ohash_first(&suffixes, &i); s != NULL; + s = ohash_next(&suffixes, &i)) { + if (!Lst_IsEmpty(&s->searchPath)) Dir_Concat(&s->searchPath, defaultPath); - } else + else Lst_Clone(&s->searchPath, defaultPath, Dir_CopyDir); } - Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", &inIncludes)); - free(ptr); - Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", &inLibs)); - free(ptr); - - Lst_Destroy(&inIncludes, Dir_Destroy); - Lst_Destroy(&inLibs, Dir_Destroy); -} - -/*- - *----------------------------------------------------------------------- - * Suff_AddInclude -- - * Add the given suffix as a type of file which gets included. - * Called from the parse module when a .INCLUDES line is parsed. - * The suffix must have already been defined. - * - * Side Effects: - * The SUFF_INCLUDE bit is set in the suffix's flags field - *----------------------------------------------------------------------- - */ -void -Suff_AddInclude(const char *sname) /* Name of suffix to mark */ -{ - LstNode ln; - Suff *s; - - ln = suff_find_by_name(sname); - if (ln != NULL) { - s = (Suff *)Lst_Datum(ln); - s->flags |= SUFF_INCLUDE; - } + build_path_variable(&suffixes, SUFF_INCLUDE, ".INCLUDES", "-I"); + build_path_variable(&suffixes, SUFF_LIBRARY, ".LIBS", "-L"); } -/*- - *----------------------------------------------------------------------- - * Suff_AddLib -- - * Add the given suffix as a type of file which is a library. - * Called from the parse module when parsing a .LIBS line. The - * suffix must have been defined via .SUFFIXES before this is - * called. - * - * Side Effects: - * The SUFF_LIBRARY bit is set in the suffix's flags field - *----------------------------------------------------------------------- - */ void -Suff_AddLib(const char *sname) /* Name of suffix to mark */ +process_suffixes_after_makefile_is_read(void) { - LstNode ln; - Suff *s; - - ln = suff_find_by_name(sname); - if (ln != NULL) { - s = (Suff *)Lst_Datum(ln); - s->flags |= SUFF_LIBRARY; - } + /* once the Makefile is finish reading, we can set up the default PATH + * stuff, and build the final suffixes graph + */ + setup_paths(); + /* and we link all transforms to active suffixes at this point. */ + build_suffixes_graph(); } - /********** Implicit Source Search Functions *********/ /*- @@ -865,13 +778,13 @@ Suff_AddLib(const char *sname) /* Name of suffix to mark */ */ static void SuffAddSrc( - void *sp, /* suffix for which to create a Src structure */ - void *lsp) /* list and parent for the new Src */ + void *sp, /* suffix for which to create a Src structure */ + void *lsp) /* list and parent for the new Src */ { - Suff *s = (Suff *)sp; - LstSrc *ls = (LstSrc *)lsp; - Src *s2; /* new Src structure */ - Src *targ; /* Target structure */ + Suff *s = (Suff *)sp; + LstSrc *ls = (LstSrc *)lsp; + Src *s2; /* new Src structure */ + Src *targ; /* Target structure */ targ = ls->s; @@ -882,12 +795,12 @@ SuffAddSrc( * Two birds, and all that... */ s2 = emalloc(sizeof(Src)); - s2->file = estrdup(targ->pref); - s2->pref = targ->pref; - s2->parent = targ; - s2->node = NULL; - s2->suff = s; - s2->children = 0; + s2->file = estrdup(targ->pref); + s2->pref = targ->pref; + s2->parent = targ; + s2->node = NULL; + s2->suff = s; + s2->children = 0; targ->children++; Lst_AtEnd(ls->l, s2); #ifdef DEBUG_SRC @@ -899,16 +812,16 @@ SuffAddSrc( #endif } s2 = emalloc(sizeof(Src)); - s2->file = Str_concat(targ->pref, s->name, 0); - s2->pref = targ->pref; - s2->parent = targ; - s2->node = NULL; - s2->suff = s; - s2->children = 0; + s2->file = Str_concat(targ->pref, s->name, 0); + s2->pref = targ->pref; + s2->parent = targ; + s2->node = NULL; + s2->suff = s; + s2->children = 0; targ->children++; Lst_AtEnd(ls->l, s2); #ifdef DEBUG_SRC - Lst_Init(&s2->cp); + Lst_Init(&s2->cp); Lst_AtEnd(&targ->cp, s2); printf("2 add %x %x to %x:", targ, s2, ls->l); Lst_Every(ls->l, PrintAddr); @@ -928,8 +841,8 @@ SuffAddSrc( */ static void SuffAddLevel( - Lst l, /* list to which to add the new level */ - Src *targ) /* Src structure to use as the parent */ + Lst l, /* list to which to add the new level */ + Src *targ) /* Src structure to use as the parent */ { LstSrc ls; @@ -1011,19 +924,18 @@ SuffRemoveSrc(Lst l) */ static Src * SuffFindThem( - Lst srcs, /* list of Src structures to search through */ - Lst slst) + Lst srcs, /* list of Src structures to search through */ + Lst slst) { - Src *s; /* current Src */ - Src *rs; /* returned Src */ - char *ptr; + Src *s; /* current Src */ + Src *rs; /* returned Src */ + char *ptr; rs = NULL; while ((s = (Src *)Lst_DeQueue(srcs)) != NULL) { - if (DEBUG(SUFF)) { + if (DEBUG(SUFF)) printf("\ttrying %s...", s->file); - } /* * A file is considered to exist if either a node exists in the @@ -1047,17 +959,15 @@ SuffFindThem( break; } - if (DEBUG(SUFF)) { - printf("not there\n"); - } + if (DEBUG(SUFF)) + printf("not there\n"); SuffAddLevel(srcs, s); Lst_AtEnd(slst, s); } - if (DEBUG(SUFF) && rs) { - printf("got it\n"); - } + if (DEBUG(SUFF) && rs) + printf("got it\n"); return rs; } @@ -1080,13 +990,13 @@ SuffFindCmds( Src *targ, /* Src structure to play with */ Lst slst) { - LstNode ln; /* General-purpose list node */ - GNode *t, /* Target GNode */ - *s; /* Source GNode */ - int prefLen;/* The length of the defined prefix */ - Suff *suff; /* Suffix on matching beastie */ - Src *ret; /* Return value */ - const char *cp; + LstNode ln; /* General-purpose list node */ + GNode *t; /* Target GNode */ + GNode *s; /* Source GNode */ + int prefLen; /* The length of the defined prefix */ + Suff *suff; /* Suffix on matching beastie */ + Src *ret; /* Return value */ + const char *cp; t = targ->node; prefLen = strlen(targ->pref); @@ -1103,9 +1013,8 @@ SuffFindCmds( if (strncmp(cp, targ->pref, prefLen) == 0) { /* The node matches the prefix ok, see if it has a known * suffix. */ - LstNode ln2; - ln2 = suff_find_by_name(&cp[prefLen]); - if (ln2 != NULL) { + suff = find_suff(&cp[prefLen]); + if (suff != NULL) { /* * It even has a known suffix, see if there's a * transformation defined between the node's @@ -1114,8 +1023,6 @@ SuffFindCmds( * XXX: Handle multi-stage transformations * here, too. */ - suff = (Suff *)Lst_Datum(ln2); - if (Lst_Member(&suff->parents, targ->suff) != NULL) { /* @@ -1140,11 +1047,12 @@ SuffFindCmds( Lst_AtEnd(&targ->cp, ret); #endif Lst_AtEnd(slst, ret); - if (DEBUG(SUFF)) { - printf ("\tusing existing source %s\n", s->name); - } + if (DEBUG(SUFF)) + printf( + "\tusing existing source %s\n", + s->name); return ret; - } + } } } } @@ -1154,9 +1062,9 @@ SuffFindCmds( static void SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) { - GNode *gn; /* New source 8) */ - char *cp; /* Expanded value */ - LIST members; + GNode *gn; /* New source 8) */ + char *cp; /* Expanded value */ + LIST members; if (DEBUG(SUFF)) @@ -1177,7 +1085,7 @@ SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) * on the Arch module to find the nodes for us, expanding * variables in the parent's context. */ - const char *sacrifice = cp; + const char *sacrifice = (const char *)cp; (void)Arch_ParseArchive(&sacrifice, &members, &pgn->context); } else { @@ -1186,7 +1094,7 @@ SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) * Unfortunately, we can't use brk_string because it * doesn't understand about variable specifications with * spaces in them... */ - char *start, *cp2; + const char *start, *cp2; for (start = cp; *start == ' ' || *start == '\t'; start++) continue; @@ -1212,13 +1120,13 @@ SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) cp2+=2; else cp2++; - } + } - if (cp2 != start) { - /* Stuff left over -- add it to the list too. */ - gn = Targ_FindNodei(start, cp2, TARG_CREATE); - Lst_AtEnd(&members, gn); - } + if (cp2 != start) { + /* Stuff left over -- add it to the list too. */ + gn = Targ_FindNodei(start, cp2, TARG_CREATE); + Lst_AtEnd(&members, gn); + } } /* Add all elements of the members list to the parent node. */ while ((gn = (GNode *)Lst_DeQueue(&members)) != NULL) { @@ -1240,11 +1148,11 @@ SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) static void SuffExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn) { - LstNode ln; /* List element for old source */ - char *cp; /* Expanded value */ + Suff *s; + char *cp; /* Expanded value */ - LIST exp; /* List of expansions */ - Lst path; /* Search path along which to expand */ + LIST exp; /* List of expansions */ + Lst path; /* Search path along which to expand */ if (DEBUG(SUFF)) printf("Wildcard expanding \"%s\"...", cgn->name); @@ -1255,12 +1163,9 @@ SuffExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn) * If it has no known suffix and we're allowed to use the null * suffix, use its path. * Else use the default system search path. */ - cp = cgn->name + strlen(cgn->name); - ln = Lst_FindConst(&sufflist, SuffSuffIsSuffixP, cp); - - if (ln != NULL) { - Suff *s = (Suff *)Lst_Datum(ln); + s = find_best_suffix(cgn->name, cgn->name + strlen(cgn->name)); + if (s != NULL) { if (DEBUG(SUFF)) printf("suffix is \"%s\"...", s->name); path = &s->searchPath; @@ -1274,7 +1179,7 @@ SuffExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn) /* Fetch next expansion off the list and find its GNode. */ while ((cp = (char *)Lst_DeQueue(&exp)) != NULL) { - GNode *gn; /* New source 8) */ + GNode *gn; /* New source 8) */ if (DEBUG(SUFF)) printf("%s...", cp); gn = Targ_FindNode(cp, TARG_CREATE); @@ -1326,7 +1231,7 @@ SuffExpandChildren( else if (Dir_HasWildcards(cgn->name)) SuffExpandWildChildren(ln, cgn, pgn); else - /* Third case: nothing to expand. */ + /* Third case: nothing to expand. */ return; /* Since the source was expanded, remove it from the list of children to @@ -1390,10 +1295,10 @@ SuffApplyTransform( } /* Locate the transformation rule itself. */ tname = Str_concat(s->name, t->name, 0); - ln = transform_find_by_name(tname); + gn = find_transform(tname); free(tname); - if (ln == NULL) + if (gn == NULL) /* * Not really such a transformation rule (can happen when we're * called to link an OP_MEMBER and OP_ARCHV node), so return @@ -1401,8 +1306,6 @@ SuffApplyTransform( */ return false; - gn = (GNode *)Lst_Datum(ln); - if (DEBUG(SUFF)) printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name); @@ -1426,6 +1329,19 @@ SuffApplyTransform( return true; } +static Suff * +find_suffix_as_suffix(Lst l, const char *b, const char *e) +{ + LstNode ln; + Suff *s; + + for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { + s = (Suff *)Lst_Datum(ln); + if (suffix_is_suffix(s, b, e)) + return s; + } + return NULL; +} /*- *----------------------------------------------------------------------- @@ -1438,14 +1354,14 @@ SuffApplyTransform( */ static void SuffFindArchiveDeps( - GNode *gn, /* Node for which to locate dependencies */ + GNode *gn, /* Node for which to locate dependencies */ Lst slst) { - char *eoarch; /* End of archive portion */ - char *eoname; /* End of member portion */ - GNode *mem; /* Node for member */ - Suff *ms; /* Suffix descriptor for member */ - char *name; /* Start of member's name */ + char *eoarch; /* End of archive portion */ + char *eoname; /* End of member portion */ + GNode *mem; /* Node for member */ + Suff *ms; /* Suffix descriptor for member */ + char *name; /* Start of member's name */ /* The node is an archive(member) pair. so we must find a suffix * for both of them. */ @@ -1498,17 +1414,17 @@ SuffFindArchiveDeps( * searching through the entire list, we just look at suffixes * to which the member's suffix may be transformed... */ - LstNode ln; - /* Use first matching suffix... */ - ln = Lst_FindConst(&ms->parents, SuffSuffIsSuffixP, eoarch); + Suff *suff; - if (ln != NULL) { + suff = find_suffix_as_suffix(&ms->parents, gn->name, eoarch); + + if (suff != NULL) { /* Got one -- apply it. */ - if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), - ms) && DEBUG(SUFF)) + if (!SuffApplyTransform(gn, mem, suff, ms) && + DEBUG(SUFF)) printf("\tNo transformation from %s -> %s\n", - ms->name, ((Suff *)Lst_Datum(ln))->name); + ms->name, suff->name); } } @@ -1523,6 +1439,65 @@ SuffFindArchiveDeps( mem->type |= OP_MEMBER; } +static void +record_possible_suffix(Suff *s, GNode *gn, char *eoname, Lst srcs, Lst targs) +{ + int prefLen; + Src *targ; + char *sopref = gn->name; + + targ = emalloc(sizeof(Src)); + targ->file = estrdup(gn->name); + targ->suff = s; + targ->node = gn; + targ->parent = NULL; + targ->children = 0; +#ifdef DEBUG_SRC + Lst_Init(&targ->cp); +#endif + + /* Allocate room for the prefix, whose end is found by + * subtracting the length of the suffix from the end of + * the name. */ + prefLen = (eoname - targ->suff->nameLen) - sopref; + targ->pref = emalloc(prefLen + 1); + memcpy(targ->pref, sopref, prefLen); + targ->pref[prefLen] = '\0'; + + /* Add nodes from which the target can be made. */ + SuffAddLevel(srcs, targ); + + /* Record the target so we can nuke it. */ + Lst_AtEnd(targs, targ); +} + +static void +record_possible_suffixes(GNode *gn, Lst srcs, Lst targs) +{ + char *s = gn->name; + char *e = s + strlen(s); + const char *p; + uint32_t hv; + unsigned int slot; + Suff *suff; + + if (e == s) + return; + + p = e; + hv = *--p; + + while (p != s) { + slot = ohash_lookup_interval(&suffixes, p, e, hv); + suff = ohash_find(&suffixes, slot); + if (suff != NULL && (suff->flags & SUFF_EXISTS)) + record_possible_suffix(suff, gn, e, srcs, targs); + if (e - p >= (ptrdiff_t)maxLen) + break; + reverse_hash_add_char(&hv, --p); + } +} + /*- *----------------------------------------------------------------------- * SuffFindNormalDeps -- @@ -1537,26 +1512,18 @@ SuffFindNormalDeps( GNode *gn, /* Node for which to find sources */ Lst slst) { - char *eoname; /* End of name */ - char *sopref; /* Start of prefix */ - LstNode ln; /* Next suffix node to check */ LstNode np; - LIST srcs; /* List of sources at which to look */ - LIST targs; /* List of targets to which things can be - * transformed. They all have the same file, - * but different suff and pref fields */ - Src *bottom; /* Start of found transformation path */ - Src *src; /* General Src pointer */ - char *pref; /* Prefix to use */ - Src *targ; /* General Src target pointer */ - - - eoname = gn->name + strlen(gn->name); + LstNode ln; + LIST srcs; /* List of sources at which to look */ + LIST targs; /* List of targets to which things can be + * transformed. They all have the same file, + * but different suff and pref fields */ + Src *bottom; /* Start of found transformation path */ + Src *src; /* General Src pointer */ + char *pref; /* Prefix to use */ + Src *targ; /* General Src target pointer */ - sopref = gn->name; - /* Begin at the beginning... */ - ln = Lst_First(&sufflist); Lst_Init(&srcs); Lst_Init(&targs); @@ -1577,51 +1544,13 @@ SuffFindNormalDeps( * children, then look for any overriding transformations they imply. * Should we find one, we discard the one we found before. */ - while (ln != NULL) { - /* Look for next possible suffix... */ - ln = Lst_FindFromConst(ln, SuffSuffIsSuffixP, eoname); - - if (ln != NULL) { - int prefLen; /* Length of the prefix */ - Src *targ; - - /* Allocate a Src structure to which things can be - * transformed. */ - targ = emalloc(sizeof(Src)); - targ->file = estrdup(gn->name); - targ->suff = (Suff *)Lst_Datum(ln); - targ->node = gn; - targ->parent = NULL; - targ->children = 0; -#ifdef DEBUG_SRC - Lst_Init(&targ->cp); -#endif - - /* Allocate room for the prefix, whose end is found by - * subtracting the length of the suffix from the end of - * the name. */ - prefLen = (eoname - targ->suff->nameLen) - sopref; - targ->pref = emalloc(prefLen + 1); - memcpy(targ->pref, sopref, prefLen); - targ->pref[prefLen] = '\0'; - - /* Add nodes from which the target can be made. */ - SuffAddLevel(&srcs, targ); - - /* Record the target so we can nuke it. */ - Lst_AtEnd(&targs, targ); - - /* Search from this suffix's successor... */ - ln = Lst_Succ(ln); - } - } + record_possible_suffixes(gn, &srcs, &targs); /* Handle target of unknown suffix... */ - if (Lst_IsEmpty(&targs) && suffNull != NULL) { - if (DEBUG(SUFF)) { + if (Lst_IsEmpty(&targs)) { + if (DEBUG(SUFF)) printf("\tNo known suffix on %s. Using .NULL suffix\n", gn->name); - } targ = emalloc(sizeof(Src)); targ->file = estrdup(gn->name); @@ -1629,7 +1558,7 @@ SuffFindNormalDeps( targ->node = gn; targ->parent = NULL; targ->children = 0; - targ->pref = estrdup(sopref); + targ->pref = estrdup(gn->name); #ifdef DEBUG_SRC Lst_Init(&targ->cp); #endif @@ -1688,9 +1617,9 @@ SuffFindNormalDeps( printf("\tNo valid suffix on %s\n", gn->name); sfnd_abort: - /* Deal with finding the thing on the default search path if - * the node is only a source (not on the lhs of a dependency - * operator or [XXX] it has neither children or commands). */ + /* Deal with finding the thing on the default search path if the + * node is only a source (not on the lhs of a dependency operator + * or [XXX] it has neither children or commands). */ if (OP_NOP(gn->type) || (Lst_IsEmpty(&gn->children) && Lst_IsEmpty(&gn->commands))) { @@ -1714,8 +1643,8 @@ sfnd_abort: savec = gn->path[savep]; gn->path[savep] = '\0'; - if ((ptr = strrchr(gn->path, '/')) - != NULL) + if ((ptr = strrchr(gn->path, '/')) != + NULL) ptr++; else ptr = gn->path; @@ -1724,12 +1653,12 @@ sfnd_abort: gn->path[savep] = savec; } else { - /* The .PREFIX gets the full path if - * the target has no known suffix. */ + /* The .PREFIX gets the full path if the + * target has no known suffix. */ gn->suffix = NULL; - if ((ptr = strrchr(gn->path, '/')) - != NULL) + if ((ptr = strrchr(gn->path, '/')) != + NULL) ptr++; else ptr = gn->path; @@ -1797,8 +1726,8 @@ sfnd_abort: targ->node = Targ_FindNode(targ->file, TARG_CREATE); } - SuffApplyTransform(targ->node, src->node, targ->suff, - src->suff); + SuffApplyTransform(targ->node, src->node, + targ->suff, src->suff); if (targ->node != gn) { /* Finish off the dependency-search process for any @@ -1882,9 +1811,8 @@ SuffFindDeps(GNode *gn, Lst slst) gn->type |= OP_DEPS_FOUND; } - if (DEBUG(SUFF)) { + if (DEBUG(SUFF)) printf("SuffFindDeps (%s)\n", gn->name); - } if (gn->type & OP_ARCHV) { SuffFindArchiveDeps(gn, slst); @@ -1897,12 +1825,11 @@ SuffFindDeps(GNode *gn, Lst slst) * do for it, so we just set the TARGET variable to the node's * name in order to give it a value). */ - LstNode ln; Suff *s; - ln = suff_find_by_name(LIBSUFF); - if (ln != NULL) { - gn->suffix = s = (Suff *)Lst_Datum(ln); + s = find_suff(LIBSUFF); + if (s != NULL) { + gn->suffix = s; Arch_FindLib(gn, &s->searchPath); } else { gn->suffix = NULL; @@ -1919,34 +1846,24 @@ SuffFindDeps(GNode *gn, Lst slst) } /*- - *----------------------------------------------------------------------- - * Suff_SetNull -- - * Define which suffix is the null suffix. - * - * Side Effects: - * 'suffNull' is altered. - * * Notes: - * Need to handle the changing of the null suffix gracefully so the - * old transformation rules don't just go away. - *----------------------------------------------------------------------- */ void -Suff_SetNull(const char *name) +Suff_SetNulli(const char *name, const char *end) { Suff *s; - LstNode ln; - ln = suff_find_by_name(name); - if (ln != NULL) { - s = (Suff *)Lst_Datum(ln); - if (suffNull != NULL) { - suffNull->flags &= ~SUFF_NULL; - } + s= find_suffi(name, end); + if (s != NULL) { + /* pass the pumpkin */ + suffNull->flags &= ~SUFF_NULL; s->flags |= SUFF_NULL; /* * XXX: Here's where the transformation mangling would take * place + * we would need to handle the changing of the null suffix + * gracefully so the old transformation rules don't just go + * away. */ suffNull = s; } else { @@ -1967,30 +1884,22 @@ Suff_SetNull(const char *name) void Suff_Init(void) { - Static_Lst_Init(&sufflist); -#ifdef CLEANUP - Static_Lst_Init(&suffClean); -#endif Static_Lst_Init(&srclist); - Static_Lst_Init(&transforms); + ohash_init(&transforms, 4, &gnode_info); - sNum = 0; /* * Create null suffix for single-suffix rules (POSIX). The thing doesn't * actually go on the suffix list or everyone will think that's its * suffix. */ - emptySuff = suffNull = emalloc(sizeof(Suff)); - - suffNull->name = estrdup(""); - suffNull->nameLen = 0; - Lst_Init(&suffNull->searchPath); - Dir_Concat(&suffNull->searchPath, defaultPath); - Lst_Init(&suffNull->children); - Lst_Init(&suffNull->parents); - Lst_Init(&suffNull->ref); - suffNull->sNum = sNum++; - suffNull->flags = SUFF_NULL; + emptySuff = new_suffix(""); + emptySuff->flags |= SUFF_NULL; + make_suffix_known(emptySuff); + Dir_Concat(&emptySuff->searchPath, defaultPath); + ohash_init(&suffixes, 4, &suff_info); + sNum = 0; + clear_suffixes(); + special_path_hack(); } @@ -2009,19 +1918,19 @@ Suff_Init(void) void Suff_End(void) { - Lst_Destroy(&sufflist, SuffFree); - Lst_Destroy(&suffClean, SuffFree); - if (suffNull) - SuffFree(suffNull); + free_hash(&suffixes); + if (emptySuff) + SuffFree(emptySuff); Lst_Destroy(&srclist, NOFREE); - Lst_Destroy(&transforms, NOFREE); + ohash_delete(&transforms): } #endif /********************* DEBUGGING FUNCTIONS **********************/ -static void SuffPrintName(void *s) +static void +SuffPrintName(void *s) { printf("%s ", ((Suff *)s)->name); } @@ -2068,10 +1977,8 @@ SuffPrintSuff(void *sp) } static void -SuffPrintTrans(void *tp) +SuffPrintTrans(GNode *t) { - GNode *t = (GNode *)tp; - printf("%-16s: ", t->name); Targ_PrintType(t->type); fputc('\n', stdout); @@ -2082,11 +1989,20 @@ SuffPrintTrans(void *tp) void Suff_PrintAll(void) { + Suff *s; + GNode *gn; + unsigned int i; + printf("#*** Suffixes:\n"); - Lst_Every(&sufflist, SuffPrintSuff); + + for (s = ohash_first(&suffixes, &i); s != NULL; + s = ohash_next(&suffixes, &i)) + SuffPrintSuff(s); printf("#*** Transformations:\n"); - Lst_Every(&transforms, SuffPrintTrans); + for (gn = ohash_first(&transforms, &i); gn != NULL; + gn = ohash_next(&transforms, &i)) + SuffPrintTrans(gn); } #ifdef DEBUG_SRC diff --git a/usr.bin/make/suff.h b/usr.bin/make/suff.h index 977b839a0c1..fd6a6d19873 100644 --- a/usr.bin/make/suff.h +++ b/usr.bin/make/suff.h @@ -1,7 +1,7 @@ #ifndef SUFF_H #define SUFF_H /* $OpenPackages$ */ -/* $OpenBSD: suff.h,v 1.2 2004/05/05 09:10:48 espie Exp $ */ +/* $OpenBSD: suff.h,v 1.3 2007/09/17 12:42:09 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -29,17 +29,16 @@ */ extern void Suff_ClearSuffixes(void); -extern bool Suff_IsTransform(const char *); -extern GNode *Suff_AddTransform(const char *); -extern void Suff_EndTransform(void *); -extern void Suff_AddSuffix(const char *); -extern Lst Suff_GetPath(const char *); -extern void Suff_DoPaths(void); -extern void Suff_AddInclude(const char *); -extern void Suff_AddLib(const char *); +extern GNode *Suff_ParseAsTransform(const char *, const char *); +struct Suff_; +extern void Suff_AddSuffixi(const char *, const char *); +extern void Suff_AddIncludei(const char *, const char *); +extern void Suff_AddLibi(const char *, const char *); extern void Suff_FindDeps(GNode *); -extern void Suff_SetNull(const char *); +extern void Suff_SetNulli(const char *, const char *); extern void Suff_Init(void); +extern void process_suffixes_after_makefile_is_read(void); +extern Lst find_suffix_path(GNode *); #ifdef CLEANUP extern void Suff_End(void); #else diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c index 588c1add13b..cb3ce35c0bc 100644 --- a/usr.bin/make/targ.c +++ b/usr.bin/make/targ.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: targ.c,v 1.45 2007/09/17 09:28:36 espie Exp $ */ +/* $OpenBSD: targ.c,v 1.46 2007/09/17 12:42:09 espie Exp $ */ /* $NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $ */ /* @@ -115,14 +115,15 @@ #include "extern.h" #include "timestamp.h" #include "lst.h" +#include "node_int.h" +#include "nodehashconsts.h" #ifdef CLEANUP #include <stdlib.h> #endif static struct ohash targets; /* a hash table of same */ -static struct ohash_info gnode_info = { - offsetof(GNode, name), - NULL, hash_alloc, hash_free, element_alloc +struct ohash_info gnode_info = { + offsetof(GNode, name), NULL, hash_alloc, hash_free, element_alloc }; static void TargPrintOnlySrc(GNode *); @@ -133,15 +134,8 @@ static LIST allTargets; static void TargFreeGN(void *); #endif -/*- - *----------------------------------------------------------------------- - * Targ_Init -- - * Initialize this module - * - * Side Effects: - * The targets hash table is initialized - *----------------------------------------------------------------------- - */ +GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; + void Targ_Init(void) { @@ -150,17 +144,17 @@ Targ_Init(void) #ifdef CLEANUP Lst_Init(&allTargets); #endif + begin_node = Targ_FindConstantNode(NODE_BEGIN, TARG_CREATE); + begin_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; + end_node = Targ_FindConstantNode(NODE_END, TARG_CREATE); + end_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; + interrupt_node = Targ_FindConstantNode(NODE_INTERRUPT, TARG_CREATE); + interrupt_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; + DEFAULT = Targ_FindConstantNode(NODE_DEFAULT, TARG_CREATE); + DEFAULT->type |= OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT; + } -/*- - *----------------------------------------------------------------------- - * Targ_End -- - * Finalize this module - * - * Side Effects: - * All lists and gnodes are cleared - *----------------------------------------------------------------------- - */ #ifdef CLEANUP void Targ_End(void) @@ -170,37 +164,24 @@ Targ_End(void) } #endif -/*- - *----------------------------------------------------------------------- - * Targ_NewGNi -- - * Create and initialize a new graph node - * - * Results: - * An initialized graph node with the name field filled with a copy - * of the passed name - * - * Side effect: - * add targets to list of all targets if CLEANUP - *----------------------------------------------------------------------- - */ GNode * -Targ_NewGNi(const char *name, /* the name to stick in the new node */ - const char *ename) +Targ_NewGNi(const char *name, const char *ename) { GNode *gn; gn = ohash_create_entry(&gnode_info, name, &ename); gn->path = NULL; - if (name[0] == '-' && name[1] == 'l') { + if (name[0] == '-' && name[1] == 'l') gn->type = OP_LIB; - } else { + else gn->type = 0; - } - gn->unmade = 0; - gn->make = false; - gn->made = UNMADE; + + gn->special = SPECIAL_NONE; + gn->unmade = 0; + gn->make = false; + gn->made = UNMADE; gn->childMade = false; - gn->order = 0; + gn->order = 0; ts_set_out_of_date(gn->mtime); ts_set_out_of_date(gn->cmtime); Lst_Init(&gn->iParents); @@ -226,12 +207,6 @@ Targ_NewGNi(const char *name, /* the name to stick in the new node */ } #ifdef CLEANUP -/*- - *----------------------------------------------------------------------- - * TargFreeGN -- - * Destroy a GNode - *----------------------------------------------------------------------- - */ static void TargFreeGN(void *gnp) { @@ -250,30 +225,22 @@ TargFreeGN(void *gnp) } #endif +GNode * +Targ_FindNodei(const char *name, const char *ename, int flags) +{ + uint32_t hv; + + hv = ohash_interval(name, &ename); + return Targ_FindNodeih(name, ename, hv, flags); +} -/*- - *----------------------------------------------------------------------- - * Targ_FindNodei -- - * Find a node in the list using the given name for matching - * - * Results: - * The node in the list if it was. If it wasn't, return NULL if - * flags was TARG_NOCREATE or the newly created and initialized node - * if flags was TARG_CREATE - * - * Side Effects: - * Sometimes a node is created and added to the list - *----------------------------------------------------------------------- - */ GNode * -Targ_FindNodei(const char *name, const char *ename, - int flags) /* flags governing events when target not - * found */ +Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags) { - GNode *gn; /* node in that element */ + GNode *gn; unsigned int slot; - slot = ohash_qlookupi(&targets, name, &ename); + slot = ohash_lookup_interval(&targets, name, ename, hv); gn = ohash_find(&targets, slot); @@ -285,25 +252,11 @@ Targ_FindNodei(const char *name, const char *ename, return gn; } -/*- - *----------------------------------------------------------------------- - * Targ_FindList -- - * Make a complete list of GNodes from the given list of names - * - * Side Effects: - * Nodes will be created for all names in names which do not yet have graph - * nodes. - * - * A complete list of graph nodes corresponding to all instances of all - * the names in names is added to nodes. - * ----------------------------------------------------------------------- - */ void -Targ_FindList(Lst nodes, /* result list */ - Lst names) /* list of names to find */ +Targ_FindList(Lst nodes, Lst names) { - LstNode ln; /* name list element */ - GNode *gn; /* node in tLn */ + LstNode ln; + GNode *gn; char *name; for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { @@ -345,25 +298,6 @@ Targ_Precious(GNode *gn) return false; } -/******************* DEBUG INFO PRINTING ****************/ - -static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ -/*- - *----------------------------------------------------------------------- - * Targ_SetMain -- - * Set our idea of the main target we'll be creating. Used for - * debugging output. - * - * Side Effects: - * "mainTarg" is set to the main target's node. - *----------------------------------------------------------------------- - */ -void -Targ_SetMain(GNode *gn) -{ - mainTarg = gn; -} - static void TargPrintName(void *gnp) { @@ -378,25 +312,13 @@ Targ_PrintCmd(void *cmd) printf("\t%s\n", (char *)cmd); } -/*- - *----------------------------------------------------------------------- - * Targ_PrintType -- - * Print out a type field giving only those attributes the user can - * set. - *----------------------------------------------------------------------- - */ void Targ_PrintType(int type) { int tbit; -#define PRINTBIT(attr) case CONCAT(OP_,attr): \ - printf("." #attr " "); \ - break -#define PRINTDBIT(attr) case CONCAT(OP_,attr): \ - if (DEBUG(TARG)) \ - printf("." #attr " "); \ - break +#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break +#define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break type &= ~OP_OPMASK; @@ -423,7 +345,7 @@ Targ_PrintType(int type) break; PRINTDBIT(ARCHV); } - } + } } static void @@ -432,29 +354,22 @@ TargPrintNode(GNode *gn, int pass) if (OP_NOP(gn->type)) return; printf("#\n"); - if (gn == mainTarg) { - printf("# *** MAIN TARGET ***\n"); - } if (pass == 2) { - if (gn->unmade) { - printf("# %d unmade children\n", gn->unmade); - } else { - printf("# No unmade children\n"); - } + printf("# %d unmade children\n", gn->unmade); if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { if (!is_out_of_date(gn->mtime)) { printf("# last modified %s: %s\n", - time_to_string(gn->mtime), - (gn->made == UNMADE ? "unmade" : - (gn->made == MADE ? "made" : - (gn->made == UPTODATE ? "up-to-date" : - "error when made")))); + time_to_string(gn->mtime), + (gn->made == UNMADE ? "unmade" : + (gn->made == MADE ? "made" : + (gn->made == UPTODATE ? "up-to-date" : + "error when made")))); } else if (gn->made != UNMADE) { printf("# non-existent (maybe): %s\n", - (gn->made == MADE ? "made" : - (gn->made == UPTODATE ? "up-to-date" : - (gn->made == ERROR ? "error when made" : - "aborted")))); + (gn->made == MADE ? "made" : + (gn->made == UPTODATE ? "up-to-date" : + (gn->made == ERROR ? "error when made" : + "aborted")))); } else { printf("# unmade\n"); } @@ -516,8 +431,12 @@ Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing printf("#\n# Files that are only sources:\n"); for (gn = ohash_first(&targets, &i); gn != NULL; gn = ohash_next(&targets, &i)) - TargPrintOnlySrc(gn); + TargPrintOnlySrc(gn); Var_Dump(); printf("\n"); +#ifdef DEBUG_DIRECTORY_CACHE + Dir_PrintDirectories(); + printf("\n"); +#endif Suff_PrintAll(); } diff --git a/usr.bin/make/targ.h b/usr.bin/make/targ.h index 86d2bb7ed0e..312f2d69939 100644 --- a/usr.bin/make/targ.h +++ b/usr.bin/make/targ.h @@ -1,7 +1,7 @@ #ifndef TARG_H #define TARG_H /* $OpenPackages$ */ -/* $OpenBSD: targ.h,v 1.2 2007/09/16 12:09:36 espie Exp $ */ +/* $OpenBSD: targ.h,v 1.3 2007/09/17 12:42:09 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. @@ -51,14 +51,32 @@ extern GNode *Targ_NewGNi(const char *, const char *); #define Targ_NewGN(n) Targ_NewGNi(n, NULL); extern GNode *Targ_FindNodei(const char *, const char *, int); #define Targ_FindNode(n, i) Targ_FindNodei(n, NULL, i) + + + +/* set of helpers for constant nodes */ +extern GNode *Targ_FindNodeih(const char *, const char *, uint32_t, int); + +extern inline GNode * +Targ_FindNodeh(const char *, size_t, uint32_t, int); +extern inline GNode * +Targ_FindNodeh(const char *name, size_t n, uint32_t hv, int flags) +{ + return Targ_FindNodeih(name, name + n - 1, hv, flags); +} +#define Targ_FindConstantNode(n, f) Targ_FindNodeh(n, sizeof(n), K_##n, f) + extern void Targ_FindList(Lst, Lst); extern bool Targ_Ignore(GNode *); extern bool Targ_Silent(GNode *); extern bool Targ_Precious(GNode *); -extern void Targ_SetMain(GNode *); extern void Targ_PrintCmd(void *); extern void Targ_PrintType(int); extern void Targ_PrintGraph(int); +extern GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; +struct ohash_info; + +extern struct ohash_info gnode_info; #endif |