Subject: Re: toolchain/20828: make: .WAIT doesn't work if macro expansion needed.
To: None <gnats-bugs@netbsd.org>
From: Simon J. Gerraty <sjg@crufty.net>
List: tech-toolchain
Date: 03/21/2003 00:20:45
Currently, given:

job-one job-two:      a b c .WAIT finish-${.TARGET:S/job-//}

make will run finish-one or finish-two in parallel with a b and c.
Which is incorrect.  The patch below deals with this (and possibly
some other nasty cases - have to check).

Thanks
--sjg

Index: parse.c
===================================================================
RCS file: /cvsroot/src/usr.bin/make/parse.c,v
retrieving revision 1.86
diff -u -p -r1.86 parse.c
--- parse.c	2002/12/01 05:53:30	1.86
+++ parse.c	2003/03/21 08:08:21
@@ -250,6 +250,15 @@ static struct {
 { ".WAIT",	  Wait, 	0 },
 };
 
+/*
+ * Used by ParseDoSpecialSrc()
+ */
+typedef struct {
+    int		op;
+    char	*src;
+    Lst		allsrc;
+} SpecialSrc;
+
 static int ParseIsEscaped(const char *, const char *);
 static void ParseErrorInternal(char *, size_t, int, char *, ...)
      __attribute__((__format__(__printf__, 4, 5)));
@@ -259,6 +268,7 @@ static int ParseFindKeyword(char *);
 static int ParseLinkSrc(ClientData, ClientData);
 static int ParseDoOp(ClientData, ClientData);
 static int ParseAddDep(ClientData, ClientData);
+static int ParseDoSpecialSrc(ClientData, ClientData);
 static void ParseDoSrc(int, char *, Lst);
 static int ParseFindMain(ClientData, ClientData);
 static int ParseAddDir(ClientData, ClientData);
@@ -590,6 +600,56 @@ ParseAddDep(ClientData pp, ClientData sp
 	return 1;
 }
 
+/* -
+ *---------------------------------------------------------------------
+ * ParseDoSpecialSrc  --
+ *	ParseDoSrc struck an unexpanded variable in a src.
+ *	The most likely reason is a src that refers to .TARGET or
+ *	.PREFIX so we get called to set those for each target
+ *	and then call ParseDoSrc again provided we were able to
+ *	resolve things.
+ *	XXX We set the fail on undefined var flag TRUE when we call
+ *	Var_Subst.
+ *
+ * Input:
+ *	tp		A target GNode *
+ *	sp		A SpecialSrc * which contains the args we need
+ *			for ParseDoSrc.
+ *
+ * Results:
+ *	Goodness
+ *
+ * Side Effects:
+ *	The target GNode will have .TARGET and .PREFIX set, this seems
+ *	harmless.
+ */
+static int
+ParseDoSpecialSrc(ClientData tp, ClientData sp)
+{
+    GNode *tn = (GNode *) tp;
+    SpecialSrc *ss = (SpecialSrc *) sp;
+    char *cp;
+    char *cp2;
+    char *pref;
+    
+    Var_Set(TARGET, tn->name, tn, 0);
+    if ((pref = strrchr(tn->name, '/')))
+	pref++;
+    else
+	pref = tn->name;
+    if ((cp2 = strchr(pref, '.')) > tn->name) {
+	cp = strdup(pref);
+	cp[cp2 - pref] = '\0';
+	Var_Set(PREFIX, cp, tn, 0);
+	free(cp);
+    } else
+	Var_Set(PREFIX, pref, tn, 0);   
+    cp = Var_Subst(NULL, ss->src, tn, TRUE);
+    if (!strchr(cp, '$'))		/* avoid trouble! */
+	ParseDoSrc(ss->op, cp, ss->allsrc);
+    return 0;
+}
+
 
 /*-
  *---------------------------------------------------------------------
@@ -679,6 +739,19 @@ ParseDoSrc(int tOp, char *src, Lst allsr
 	 * the 'cohorts' list of the node) or all the cohorts are linked
 	 * to all the targets.
 	 */
+	if (strchr(src, '$')) {
+	    SpecialSrc ss;
+
+	    ss.op = tOp;
+	    ss.src = src;
+	    ss.allsrc = allsrc;
+
+	    /*
+	     * This will come back to us in a sec if possible.
+	     */
+	    Lst_ForEach(targets, ParseDoSpecialSrc, (ClientData)&ss);
+	    return;
+	}
 	gn = Targ_FindNode (src, TARG_CREATE);
 	if (tOp) {
 	    gn->type |= tOp;