tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: make: dealing with targets with multiple outputs



David Holland <dholland-tech%netbsd.org@localhost> wrote:
> I don't think that's the right way to do it; it should be done by
> tracking where recipes are shared (and not parameterized). I don't
> have time or energy to go look at the internals right now to think
> about how best to arrange that.

The big concern I have with your proposal (assuming I understand it
correctly) is the risk of surprising lots of people with new magic
behavior.  bmake is used by lots of projects so we can never hope to
pre-fix all makefiles that a behavior change may impact.

Adding explicit syntax ensures that cannot happen.

I spent a few minutes implementing it - for compat mode it is trivial
[I used .COLLATERAL as the magic target]

--------------------8<--------------------
all: a b c

a b c:
	@echo making $@
	@echo A > a; echo B > b; echo C > c

# always build b if any of a b c are out-of-date
.COLLATERAL: b a c
--------------------8<--------------------

In compat mode will always build b
even if you say 'make a'
If a or c are missing for some bizzare reason, b will be made

This is basically the behavior that was requested.

And of course  a make binary that does not grok the special target will
do nothing unusual.

For jobs mode if we find 'b' has already been examined and found up to
date when a or c are out-of-date, we basically just reschedule it.
If b's node is still in REQUESTED state we just ensure it will be
considered out-of-date.

I'm pretty sure there are some corner cases to address...
but the diff is pretty minimal

diff -r 6f103b9234c3 bmake/compat.c
--- a/bmake/compat.c	Sun Dec 30 09:28:02 2018 -0800
+++ b/bmake/compat.c	Tue Jun 18 22:53:23 2019 -0700
@@ -581,6 +581,19 @@
 	    exit(1);
 	}
 
+	if (gn->proxygn) {
+	    int rc;
+
+	    /*
+	     * This is what needs to be made
+	     */
+	    gn->proxygn->made = UNMADE;
+	    gn->proxygn->flags |= FORCE;
+	    rc = Compat_Make(gn->proxygn, pgn);
+	    gn->made = gn->proxygn->made;
+	    return (rc);
+	}
+	    
 	/*
 	 * 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
diff -r 6f103b9234c3 bmake/make.c
--- a/bmake/make.c	Sun Dec 30 09:28:02 2018 -0800
+++ b/bmake/make.c	Tue Jun 18 22:53:23 2019 -0700
@@ -1121,6 +1121,20 @@
 	    if (queryFlag) {
 		return (TRUE);
 	    }
+	    if (gn->proxygn) {
+		/*
+		 * This is what needs to be made
+		 */
+		gn->proxygn->flags |= FORCE; /* make sure! */
+
+		if (gn->proxygn->made == UPTODATE) {
+		    gn->proxygn->made = REQUESTED;
+		    Lst_InsertBefore(toBeMade, Lst_First(toBeMade),
+				     gn->proxygn);
+		}
+		gn->made = UPTODATE;	/* yes we lie */
+		continue;
+	    }
 	    Make_DoAllVar(gn);
 	    Job_Make(gn);
 	    have_token = 0;
diff -r 6f103b9234c3 bmake/make.h
--- a/bmake/make.h	Sun Dec 30 09:28:02 2018 -0800
+++ b/bmake/make.h	Tue Jun 18 22:53:23 2019 -0700
@@ -221,6 +221,7 @@
 
     time_t          mtime;     	/* Its modification time */
     struct GNode    *cmgn;    	/* The youngest child */
+    struct GNode    *proxygn;	/* Node to build if we are out-of-date */
 
     Lst     	    iParents;  	/* Links to parents for which this is an
 				 * implied source, if any */
diff -r 6f103b9234c3 bmake/parse.c
--- a/bmake/parse.c	Sun Dec 30 09:28:02 2018 -0800
+++ b/bmake/parse.c	Tue Jun 18 22:53:23 2019 -0700
@@ -187,6 +187,7 @@
  */
 typedef enum {
     Begin,  	    /* .BEGIN */
+    Collateral,	    /* .COLLATERAL */
     Default,	    /* .DEFAULT */
     DeleteOnError,  /* .DELETE_ON_ERROR */
     End,    	    /* .END */
@@ -305,6 +306,7 @@
     int	    	  op;	    	/* Operator when used as a source */
 } parseKeywords[] = {
 { ".BEGIN", 	  Begin,    	0 },
+{ ".COLLATERAL",  Collateral,   0 },
 { ".DEFAULT",	  Default,  	0 },
 { ".DELETE_ON_ERROR", DeleteOnError, 0 },
 { ".END",   	  End,	    	0 },
@@ -361,7 +363,7 @@
 static int ParseFindKeyword(const char *);
 static int ParseLinkSrc(void *, void *);
 static int ParseDoOp(void *, void *);
-static void ParseDoSrc(int, const char *);
+static void ParseDoSrc(int, const char *, GNode *);
 static int ParseFindMain(void *, void *);
 static int ParseAddDir(void *, void *);
 static int ParseClearPath(void *, void *);
@@ -996,7 +998,7 @@
  *---------------------------------------------------------------------
  */
 static void
-ParseDoSrc(int tOp, const char *src)
+ParseDoSrc(int tOp, const char *src, GNode *proxygn)
 {
     GNode	*gn = NULL;
     static int wait_number = 0;
@@ -1088,6 +1090,7 @@
 
 	/* Find/create the 'src' node and attach to all targets */
 	gn = Targ_FindNode(src, TARG_CREATE);
+	gn->proxygn = proxygn;
 	if (doing_depend)
 	    ParseMark(gn);
 	if (tOp) {
@@ -1212,6 +1215,7 @@
 {
     char  	   *cp;		/* our current position */
     GNode 	   *gn = NULL;	/* a general purpose temporary node */
+    GNode	   *proxygn = NULL;
     int             op;		/* the operator on the line */
     char            savec;	/* a place to save a character */
     Lst    	    paths;   	/* List of search paths to alter when parsing
@@ -1738,7 +1742,7 @@
 
 		while (!Lst_IsEmpty (sources)) {
 		    gn = (GNode *)Lst_DeQueue(sources);
-		    ParseDoSrc(tOp, gn->name);
+		    ParseDoSrc(tOp, gn->name, proxygn);
 		}
 		Lst_Destroy(sources, NULL);
 		cp = line;
@@ -1748,7 +1752,11 @@
 		    cp += 1;
 		}
 
-		ParseDoSrc(tOp, line);
+		if (specType == Collateral && proxygn == NULL) {
+		    /* first src is the one the rest should use */
+		    proxygn = Targ_FindNode(line, TARG_CREATE);
+		} else
+		    ParseDoSrc(tOp, line, proxygn);
 	    }
 	    while (*cp && isspace ((unsigned char)*cp)) {
 		cp++;


Home | Main Index | Thread Index | Old Index