Subject: fix for MAKEOBJDIRPREFIX=/obj make build
To: None <tech-toolchain@netbsd.org>
From: Simon J. Gerraty <sjg@quick.com.au>
List: tech-toolchain
Date: 03/11/2000 20:23:10
Attempting to do a make build with MAKEOBJDIRPREFIX set (so that the
src tree can remain read-only) fails utterly when it encounters: 

	${MAKE} cleandir
	${MAKE} includes

etc.  This is due to the fact that unlike ./obj* (links or not), even
if a directory says NOOBJ, if any of its children don't then
MAKEOBJDIRPREFX`pwd` will exist and make(1) will have cd'd to it.
This means that the ${MAKE} includes is run in a directory with no
Makefile. 

Changing the above to:

	cd ${.CURDIR} && ${MAKE} cleandir

works fine, but its bogus to expect everyone to fix their makefiles.

The fix below, only applies if MAKEOBJDIRPREFIX or MAKEOBJDIR is set.
What it does is spot if make, ${.MAKE} or ${.MAKE:T} are invoked
without a preceeding 'cd' and if so does a chdir(${.CURDIR}).  This
only happens in the child just before exec(2), so does not affect the
parent.

Does anyone see anything dreadfully wrong with this?
My make build is now progressing happily btw.
If I don't get any howls within the next few days I'll commit.

--sjg

Index: main.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/make/main.c,v
retrieving revision 1.51
diff -u -p -r1.51 main.c
--- main.c	2000/02/08 12:43:25	1.51
+++ main.c	2000/03/11 09:21:38
@@ -595,6 +595,8 @@ main(argc, argv)
 			objdir = curdir;
 	}
 
+	Check_Cwd(NULL);		/* initialize it */
+	
 	setenv("PWD", objdir, 1);
 
 	create = Lst_Init(FALSE);
@@ -931,6 +933,74 @@ found:		Var_Set("MAKEFILE", fname, VAR_G
 	free(path);
 	return(TRUE);
 }
+
+
+/*
+ * If MAKEOBJDIRPREFIX is in use, make ends up not in .CURDIR
+ * in situations that would not arrise with ./obj (links or not).
+ * This tends to break things like:
+ *
+ * build:
+ * 	${MAKE} includes
+ *
+ * This function spots when 'make', ${.MAKE:T} or ${.MAKE} is in a
+ * command without a preceding 'cd', and if so does a
+ * chdir(${.CURDIR}) so that the assumptions made by the Makefile hold
+ * true.
+ *
+ * The chdir() only happens in the child process, and does nothing if
+ * MAKEOBJDIRPREFIX and MAKEOBJDIR are not in the environment so it
+ * should not break anything.
+ */
+
+void
+Check_Cwd(argv)
+     char **argv;
+{
+	static char *make[4];
+	static char *curdir = NULL;
+	char *cp, *cp2, **mp;
+	int i;
+
+	if (curdir == NULL) {
+		make[0] = "make";
+		make[2] = Var_Value(".MAKE", VAR_GLOBAL, &cp);
+		if ((make[1] = strrchr(make[2], '/')) == NULL) {
+			make[1] = make[2];
+			make[2] = NULL;
+		} else
+			++make[1];
+		make[3] = NULL;
+		curdir = Var_Value(".CURDIR", VAR_GLOBAL, &cp);
+	}
+	if (argv == NULL)
+		return;			/* initialization only */
+
+	if (getenv("MAKEOBJDIR") == NULL &&
+	    getenv("MAKEOBJDIRPREFIX") == NULL)
+		return;
+	
+	for (i = 0; argv[i] != 0; ++i) {
+		if (strcmp(argv[i], "cd") == 0) {
+			break;
+		}
+		for (mp = make; *mp != NULL; ++mp) {
+			if (strcmp(argv[i], *mp) == 0 ||
+			    (cp = strstr(argv[i], *mp)) != NULL) {
+				if (cp != NULL) {
+					cp2 = strstr(argv[i], "cd ");
+					if (cp2 != NULL &&
+					    cp2 < cp) {
+						return;
+					}
+				}
+				chdir(curdir);
+				return;
+			}
+		}
+	}
+}
+
 
 /*-
  * Cmd_Exec --
Index: make.h
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/make/make.h,v
retrieving revision 1.23
diff -u -p -r1.23 make.h
--- make.h	1999/09/16 19:57:54	1.23
+++ make.h	2000/03/11 09:21:42
@@ -395,5 +395,6 @@ int Make_HandleUse __P((GNode *, GNode *
 void Make_Update __P((GNode *));
 void Make_DoAllVar __P((GNode *));
 Boolean Make_Run __P((Lst));
+void Check_Cwd __P((char **));
 
 #endif /* _MAKE_H_ */

Index: compat.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/make/compat.c,v
retrieving revision 1.29
diff -u -p -r1.29 compat.c
--- compat.c	2000/01/21 17:08:35	1.29
+++ compat.c	2000/03/11 09:21:21
@@ -281,6 +281,7 @@ CompatRunCommand (cmdp, gnp)
 	Fatal("Could not fork");
     }
     if (cpid == 0) {
+	Check_Cwd(av);
 	if (local) {
 	    execvp(av[0], av);
 	    (void) write (2, av[0], strlen (av[0]));
Index: job.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/make/job.c,v
retrieving revision 1.32
diff -u -p -r1.32 job.c
--- job.c	2000/01/21 17:08:35	1.32
+++ job.c	2000/03/11 09:21:29
@@ -1279,6 +1279,7 @@ JobExec(job, argv)
 	(void) setpgid(0, getpid());
 # endif
 #endif /* USE_PGRP */
+	Check_Cwd(argv);
 
 #ifdef REMOTE
 	if (job->flags & JOB_REMOTE) {