xref: /freebsd/contrib/bmake/main.c (revision 8d5c8e21c690b35d0a9a604d6b886fba222cd2fe)
1*8d5c8e21SSimon J. Gerraty /*	$NetBSD: main.c,v 1.624 2024/06/02 15:31:26 rillig Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990, 1993
53955d011SMarcel Moolenaar  *	The Regents of the University of California.  All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
373955d011SMarcel Moolenaar  * All rights reserved.
383955d011SMarcel Moolenaar  *
393955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
403955d011SMarcel Moolenaar  * Adam de Boor.
413955d011SMarcel Moolenaar  *
423955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
433955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
443955d011SMarcel Moolenaar  * are met:
453955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
463955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
473955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
483955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
493955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
503955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
513955d011SMarcel Moolenaar  *    must display the following acknowledgement:
523955d011SMarcel Moolenaar  *	This product includes software developed by the University of
533955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
543955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
553955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
563955d011SMarcel Moolenaar  *    without specific prior written permission.
573955d011SMarcel Moolenaar  *
583955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
593955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
623955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
633955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
643955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
653955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
663955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
673955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
683955d011SMarcel Moolenaar  * SUCH DAMAGE.
693955d011SMarcel Moolenaar  */
703955d011SMarcel Moolenaar 
7106b9b3e0SSimon J. Gerraty /*
7206b9b3e0SSimon J. Gerraty  * The main file for this entire program. Exit routines etc. reside here.
733955d011SMarcel Moolenaar  *
743955d011SMarcel Moolenaar  * Utility functions defined in this file:
753955d011SMarcel Moolenaar  *
76dba7b0efSSimon J. Gerraty  *	Main_ParseArgLine
77dba7b0efSSimon J. Gerraty  *			Parse and process command line arguments from a
78dba7b0efSSimon J. Gerraty  *			single string.  Used to implement the special targets
79dba7b0efSSimon J. Gerraty  *			.MFLAGS and .MAKEFLAGS.
803955d011SMarcel Moolenaar  *
81e2eeea75SSimon J. Gerraty  *	Error		Print a tagged error message.
823955d011SMarcel Moolenaar  *
83e2eeea75SSimon J. Gerraty  *	Fatal		Print an error message and exit.
84e2eeea75SSimon J. Gerraty  *
85e2eeea75SSimon J. Gerraty  *	Punt		Abort all jobs and exit with a message.
863955d011SMarcel Moolenaar  *
87dba7b0efSSimon J. Gerraty  *	Finish		Finish things up by printing the number of errors
88dba7b0efSSimon J. Gerraty  *			that occurred, and exit.
893955d011SMarcel Moolenaar  */
903955d011SMarcel Moolenaar 
913955d011SMarcel Moolenaar #include <sys/types.h>
923955d011SMarcel Moolenaar #include <sys/time.h>
933955d011SMarcel Moolenaar #include <sys/param.h>
943955d011SMarcel Moolenaar #include <sys/resource.h>
953955d011SMarcel Moolenaar #include <sys/stat.h>
960dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL)
970dede8b0SSimon J. Gerraty #include <sys/sysctl.h>
980dede8b0SSimon J. Gerraty #endif
993955d011SMarcel Moolenaar #include <sys/utsname.h>
1003955d011SMarcel Moolenaar #include "wait.h"
1013955d011SMarcel Moolenaar 
1023955d011SMarcel Moolenaar #include <errno.h>
10351ee2c1cSSimon J. Gerraty #include <signal.h>
1043955d011SMarcel Moolenaar #include <stdarg.h>
1053955d011SMarcel Moolenaar #include <time.h>
1063955d011SMarcel Moolenaar 
1073955d011SMarcel Moolenaar #include "make.h"
1083955d011SMarcel Moolenaar #include "dir.h"
1093955d011SMarcel Moolenaar #include "job.h"
1103955d011SMarcel Moolenaar #include "pathnames.h"
1113955d011SMarcel Moolenaar #include "trace.h"
1123955d011SMarcel Moolenaar 
113956e45f6SSimon J. Gerraty /*	"@(#)main.c	8.3 (Berkeley) 3/19/94"	*/
114*8d5c8e21SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.624 2024/06/02 15:31:26 rillig Exp $");
115d5e0a182SSimon J. Gerraty #if defined(MAKE_NATIVE)
116956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
117956e45f6SSimon J. Gerraty 	    "The Regents of the University of California.  "
118956e45f6SSimon J. Gerraty 	    "All rights reserved.");
1193955d011SMarcel Moolenaar #endif
1203955d011SMarcel Moolenaar 
1210dede8b0SSimon J. Gerraty #ifndef __arraycount
1220dede8b0SSimon J. Gerraty # define __arraycount(__x)	(sizeof(__x) / sizeof(__x[0]))
1230dede8b0SSimon J. Gerraty #endif
1240dede8b0SSimon J. Gerraty 
125956e45f6SSimon J. Gerraty CmdOpts opts;
1263955d011SMarcel Moolenaar time_t now;			/* Time at start of make */
127e2eeea75SSimon J. Gerraty GNode *defaultNode;		/* .DEFAULT node */
128d5e0a182SSimon J. Gerraty bool allPrecious;		/* .PRECIOUS given on a line by itself */
129b0c40a00SSimon J. Gerraty bool deleteOnError;		/* .DELETE_ON_ERROR: set */
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar static int maxJobTokens;	/* -j argument */
1328c973ee2SSimon J. Gerraty static bool enterFlagObj;	/* -w and objdir != srcdir */
133956e45f6SSimon J. Gerraty 
1343955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
135b0c40a00SSimon J. Gerraty bool doing_depend;		/* Set while reading .depend */
136b0c40a00SSimon J. Gerraty static bool jobsRunning;	/* true if the jobs might be running */
1373955d011SMarcel Moolenaar static const char *tracefile;
1389f45a3c8SSimon J. Gerraty static bool ReadMakefile(const char *);
139e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void);
1403955d011SMarcel Moolenaar 
141b0c40a00SSimon J. Gerraty static bool ignorePWD;		/* if we use -C, PWD is meaningless */
1423955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
1433955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1];	/* Startup directory */
14406b9b3e0SSimon J. Gerraty const char *progname;
1453955d011SMarcel Moolenaar char *makeDependfile;
1463955d011SMarcel Moolenaar pid_t myPid;
14751ee2c1cSSimon J. Gerraty int makelevel;
1483955d011SMarcel Moolenaar 
149b0c40a00SSimon J. Gerraty bool forceJobs = false;
15006b9b3e0SSimon J. Gerraty static int main_errors = 0;
151e2eeea75SSimon J. Gerraty static HashTable cached_realpaths;
1523955d011SMarcel Moolenaar 
15351ee2c1cSSimon J. Gerraty /*
15451ee2c1cSSimon J. Gerraty  * For compatibility with the POSIX version of MAKEFLAGS that includes
155e2eeea75SSimon J. Gerraty  * all the options without '-', convert 'flags' to '-f -l -a -g -s '.
15651ee2c1cSSimon J. Gerraty  */
15751ee2c1cSSimon J. Gerraty static char *
15851ee2c1cSSimon J. Gerraty explode(const char *flags)
15951ee2c1cSSimon J. Gerraty {
1609f45a3c8SSimon J. Gerraty 	char *exploded, *ep;
1619f45a3c8SSimon J. Gerraty 	const char *p;
16251ee2c1cSSimon J. Gerraty 
16351ee2c1cSSimon J. Gerraty 	if (flags == NULL)
16451ee2c1cSSimon J. Gerraty 		return NULL;
16551ee2c1cSSimon J. Gerraty 
1669f45a3c8SSimon J. Gerraty 	for (p = flags; *p != '\0'; p++)
1679f45a3c8SSimon J. Gerraty 		if (!ch_isalpha(*p))
16851ee2c1cSSimon J. Gerraty 			return bmake_strdup(flags);
16951ee2c1cSSimon J. Gerraty 
1709f45a3c8SSimon J. Gerraty 	exploded = bmake_malloc((size_t)(p - flags) * 3 + 1);
1719f45a3c8SSimon J. Gerraty 	for (p = flags, ep = exploded; *p != '\0'; p++) {
1729f45a3c8SSimon J. Gerraty 		*ep++ = '-';
1739f45a3c8SSimon J. Gerraty 		*ep++ = *p;
1749f45a3c8SSimon J. Gerraty 		*ep++ = ' ';
17551ee2c1cSSimon J. Gerraty 	}
1769f45a3c8SSimon J. Gerraty 	*ep = '\0';
1779f45a3c8SSimon J. Gerraty 	return exploded;
17851ee2c1cSSimon J. Gerraty }
17951ee2c1cSSimon J. Gerraty 
180e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void
181e2eeea75SSimon J. Gerraty usage(void)
182e2eeea75SSimon J. Gerraty {
183e2eeea75SSimon J. Gerraty 	size_t prognameLen = strcspn(progname, "[");
184e2eeea75SSimon J. Gerraty 
185e2eeea75SSimon J. Gerraty 	(void)fprintf(stderr,
186e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n"
187e2eeea75SSimon J. Gerraty "            [-C directory] [-D variable] [-d flags] [-f makefile]\n"
188e2eeea75SSimon J. Gerraty "            [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
189e2eeea75SSimon J. Gerraty "            [-V variable] [-v variable] [variable=value] [target ...]\n",
190e2eeea75SSimon J. Gerraty 	    (int)prognameLen, progname);
191e2eeea75SSimon J. Gerraty 	exit(2);
192e2eeea75SSimon J. Gerraty }
193e2eeea75SSimon J. Gerraty 
1943955d011SMarcel Moolenaar static void
195dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg)
1963955d011SMarcel Moolenaar {
1973955d011SMarcel Moolenaar 	const char *mode;
198956e45f6SSimon J. Gerraty 	size_t len;
1993955d011SMarcel Moolenaar 	char *fname;
2003955d011SMarcel Moolenaar 
201956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout && opts.debug_file != stderr)
202956e45f6SSimon J. Gerraty 		fclose(opts.debug_file);
203956e45f6SSimon J. Gerraty 
204dba7b0efSSimon J. Gerraty 	if (*arg == '+') {
205dba7b0efSSimon J. Gerraty 		arg++;
2063955d011SMarcel Moolenaar 		mode = "a";
2073955d011SMarcel Moolenaar 	} else
2083955d011SMarcel Moolenaar 		mode = "w";
209956e45f6SSimon J. Gerraty 
210dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stdout") == 0) {
211956e45f6SSimon J. Gerraty 		opts.debug_file = stdout;
212956e45f6SSimon J. Gerraty 		return;
2133955d011SMarcel Moolenaar 	}
214dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stderr") == 0) {
215956e45f6SSimon J. Gerraty 		opts.debug_file = stderr;
216956e45f6SSimon J. Gerraty 		return;
2173955d011SMarcel Moolenaar 	}
218956e45f6SSimon J. Gerraty 
219dba7b0efSSimon J. Gerraty 	len = strlen(arg);
220e1cee40dSSimon J. Gerraty 	fname = bmake_malloc(len + 20);
221dba7b0efSSimon J. Gerraty 	memcpy(fname, arg, len + 1);
222956e45f6SSimon J. Gerraty 
2239f45a3c8SSimon J. Gerraty 	/* Replace the trailing '%d' after '.%d' with the pid. */
2249f45a3c8SSimon J. Gerraty 	if (len >= 3 && memcmp(fname + len - 3, ".%d", 3) == 0)
2253955d011SMarcel Moolenaar 		snprintf(fname + len - 2, 20, "%d", getpid());
226956e45f6SSimon J. Gerraty 
227956e45f6SSimon J. Gerraty 	opts.debug_file = fopen(fname, mode);
228e2eeea75SSimon J. Gerraty 	if (opts.debug_file == NULL) {
229d5e0a182SSimon J. Gerraty 		fprintf(stderr, "Cannot open debug file \"%s\"\n", fname);
2309f45a3c8SSimon J. Gerraty 		exit(2);
2313955d011SMarcel Moolenaar 	}
2323955d011SMarcel Moolenaar 	free(fname);
233956e45f6SSimon J. Gerraty }
234956e45f6SSimon J. Gerraty 
235956e45f6SSimon J. Gerraty static void
236dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue)
237956e45f6SSimon J. Gerraty {
238956e45f6SSimon J. Gerraty 	const char *modules;
239e2eeea75SSimon J. Gerraty 	DebugFlags debug = opts.debug;
240956e45f6SSimon J. Gerraty 
241dba7b0efSSimon J. Gerraty 	for (modules = argvalue; *modules != '\0'; modules++) {
242956e45f6SSimon J. Gerraty 		switch (*modules) {
243956e45f6SSimon J. Gerraty 		case '0':	/* undocumented, only intended for tests */
2449f45a3c8SSimon J. Gerraty 			memset(&debug, 0, sizeof(debug));
245956e45f6SSimon J. Gerraty 			break;
246956e45f6SSimon J. Gerraty 		case 'A':
2479f45a3c8SSimon J. Gerraty 			memset(&debug, ~0, sizeof(debug));
248956e45f6SSimon J. Gerraty 			break;
249956e45f6SSimon J. Gerraty 		case 'a':
2509f45a3c8SSimon J. Gerraty 			debug.DEBUG_ARCH = true;
251956e45f6SSimon J. Gerraty 			break;
252956e45f6SSimon J. Gerraty 		case 'C':
2539f45a3c8SSimon J. Gerraty 			debug.DEBUG_CWD = true;
254956e45f6SSimon J. Gerraty 			break;
255956e45f6SSimon J. Gerraty 		case 'c':
2569f45a3c8SSimon J. Gerraty 			debug.DEBUG_COND = true;
257956e45f6SSimon J. Gerraty 			break;
258956e45f6SSimon J. Gerraty 		case 'd':
2599f45a3c8SSimon J. Gerraty 			debug.DEBUG_DIR = true;
260956e45f6SSimon J. Gerraty 			break;
261956e45f6SSimon J. Gerraty 		case 'e':
2629f45a3c8SSimon J. Gerraty 			debug.DEBUG_ERROR = true;
263956e45f6SSimon J. Gerraty 			break;
264956e45f6SSimon J. Gerraty 		case 'f':
2659f45a3c8SSimon J. Gerraty 			debug.DEBUG_FOR = true;
266956e45f6SSimon J. Gerraty 			break;
267956e45f6SSimon J. Gerraty 		case 'g':
268956e45f6SSimon J. Gerraty 			if (modules[1] == '1') {
2699f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH1 = true;
270e2eeea75SSimon J. Gerraty 				modules++;
271e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '2') {
2729f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH2 = true;
273e2eeea75SSimon J. Gerraty 				modules++;
274e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '3') {
2759f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH3 = true;
276e2eeea75SSimon J. Gerraty 				modules++;
277956e45f6SSimon J. Gerraty 			}
278956e45f6SSimon J. Gerraty 			break;
279956e45f6SSimon J. Gerraty 		case 'h':
2809f45a3c8SSimon J. Gerraty 			debug.DEBUG_HASH = true;
281956e45f6SSimon J. Gerraty 			break;
282956e45f6SSimon J. Gerraty 		case 'j':
2839f45a3c8SSimon J. Gerraty 			debug.DEBUG_JOB = true;
284956e45f6SSimon J. Gerraty 			break;
285956e45f6SSimon J. Gerraty 		case 'L':
286b0c40a00SSimon J. Gerraty 			opts.strict = true;
287956e45f6SSimon J. Gerraty 			break;
288956e45f6SSimon J. Gerraty 		case 'l':
2899f45a3c8SSimon J. Gerraty 			debug.DEBUG_LOUD = true;
290956e45f6SSimon J. Gerraty 			break;
291956e45f6SSimon J. Gerraty 		case 'M':
2929f45a3c8SSimon J. Gerraty 			debug.DEBUG_META = true;
293956e45f6SSimon J. Gerraty 			break;
294956e45f6SSimon J. Gerraty 		case 'm':
2959f45a3c8SSimon J. Gerraty 			debug.DEBUG_MAKE = true;
296956e45f6SSimon J. Gerraty 			break;
297956e45f6SSimon J. Gerraty 		case 'n':
2989f45a3c8SSimon J. Gerraty 			debug.DEBUG_SCRIPT = true;
299956e45f6SSimon J. Gerraty 			break;
300956e45f6SSimon J. Gerraty 		case 'p':
3019f45a3c8SSimon J. Gerraty 			debug.DEBUG_PARSE = true;
302956e45f6SSimon J. Gerraty 			break;
303956e45f6SSimon J. Gerraty 		case 's':
3049f45a3c8SSimon J. Gerraty 			debug.DEBUG_SUFF = true;
305956e45f6SSimon J. Gerraty 			break;
306956e45f6SSimon J. Gerraty 		case 't':
3079f45a3c8SSimon J. Gerraty 			debug.DEBUG_TARG = true;
308956e45f6SSimon J. Gerraty 			break;
309956e45f6SSimon J. Gerraty 		case 'V':
310b0c40a00SSimon J. Gerraty 			opts.debugVflag = true;
311956e45f6SSimon J. Gerraty 			break;
312956e45f6SSimon J. Gerraty 		case 'v':
3139f45a3c8SSimon J. Gerraty 			debug.DEBUG_VAR = true;
314956e45f6SSimon J. Gerraty 			break;
315956e45f6SSimon J. Gerraty 		case 'x':
3169f45a3c8SSimon J. Gerraty 			debug.DEBUG_SHELL = true;
317956e45f6SSimon J. Gerraty 			break;
318956e45f6SSimon J. Gerraty 		case 'F':
319dba7b0efSSimon J. Gerraty 			MainParseArgDebugFile(modules + 1);
3201d3f2ddcSSimon J. Gerraty 			goto finish;
3213955d011SMarcel Moolenaar 		default:
3223955d011SMarcel Moolenaar 			(void)fprintf(stderr,
3233955d011SMarcel Moolenaar 			    "%s: illegal argument to d option -- %c\n",
3243955d011SMarcel Moolenaar 			    progname, *modules);
3253955d011SMarcel Moolenaar 			usage();
3263955d011SMarcel Moolenaar 		}
3273955d011SMarcel Moolenaar 	}
328e2eeea75SSimon J. Gerraty 
3291d3f2ddcSSimon J. Gerraty finish:
330e2eeea75SSimon J. Gerraty 	opts.debug = debug;
331e2eeea75SSimon J. Gerraty 
332956e45f6SSimon J. Gerraty 	setvbuf(opts.debug_file, NULL, _IONBF, 0);
3331d3f2ddcSSimon J. Gerraty 	if (opts.debug_file != stdout)
3343955d011SMarcel Moolenaar 		setvbuf(stdout, NULL, _IOLBF, 0);
3353955d011SMarcel Moolenaar }
3363955d011SMarcel Moolenaar 
3371d3f2ddcSSimon J. Gerraty /* Is path relative or does it contain any relative component "." or ".."? */
338b0c40a00SSimon J. Gerraty static bool
339dba7b0efSSimon J. Gerraty IsRelativePath(const char *path)
340e1cee40dSSimon J. Gerraty {
341b0c40a00SSimon J. Gerraty 	const char *p;
342e1cee40dSSimon J. Gerraty 
343e1cee40dSSimon J. Gerraty 	if (path[0] != '/')
344b0c40a00SSimon J. Gerraty 		return true;
345b0c40a00SSimon J. Gerraty 	p = path;
346b0c40a00SSimon J. Gerraty 	while ((p = strstr(p, "/.")) != NULL) {
347b0c40a00SSimon J. Gerraty 		p += 2;
348b0c40a00SSimon J. Gerraty 		if (*p == '.')
349b0c40a00SSimon J. Gerraty 			p++;
350b0c40a00SSimon J. Gerraty 		if (*p == '/' || *p == '\0')
351b0c40a00SSimon J. Gerraty 			return true;
3522c3632d1SSimon J. Gerraty 	}
353b0c40a00SSimon J. Gerraty 	return false;
354e1cee40dSSimon J. Gerraty }
355e1cee40dSSimon J. Gerraty 
356956e45f6SSimon J. Gerraty static void
357956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue)
358956e45f6SSimon J. Gerraty {
359956e45f6SSimon J. Gerraty 	struct stat sa, sb;
360956e45f6SSimon J. Gerraty 
361956e45f6SSimon J. Gerraty 	if (chdir(argvalue) == -1) {
362956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: chdir %s: %s\n",
363956e45f6SSimon J. Gerraty 		    progname, argvalue, strerror(errno));
36406b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
365956e45f6SSimon J. Gerraty 	}
366956e45f6SSimon J. Gerraty 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
367956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
368956e45f6SSimon J. Gerraty 		exit(2);
369956e45f6SSimon J. Gerraty 	}
370dba7b0efSSimon J. Gerraty 	if (!IsRelativePath(argvalue) &&
371956e45f6SSimon J. Gerraty 	    stat(argvalue, &sa) != -1 &&
372956e45f6SSimon J. Gerraty 	    stat(curdir, &sb) != -1 &&
373956e45f6SSimon J. Gerraty 	    sa.st_ino == sb.st_ino &&
374956e45f6SSimon J. Gerraty 	    sa.st_dev == sb.st_dev)
375*8d5c8e21SSimon J. Gerraty 		snprintf(curdir, MAXPATHLEN, "%s", argvalue);
376b0c40a00SSimon J. Gerraty 	ignorePWD = true;
377956e45f6SSimon J. Gerraty }
378956e45f6SSimon J. Gerraty 
379956e45f6SSimon J. Gerraty static void
380956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue)
381956e45f6SSimon J. Gerraty {
382e2eeea75SSimon J. Gerraty 	char end;
383e2eeea75SSimon J. Gerraty 	if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
384956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
385956e45f6SSimon J. Gerraty 		    "%s: internal error -- J option malformed (%s)\n",
386956e45f6SSimon J. Gerraty 		    progname, argvalue);
387956e45f6SSimon J. Gerraty 		usage();
388956e45f6SSimon J. Gerraty 	}
389956e45f6SSimon J. Gerraty 	if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
390956e45f6SSimon J. Gerraty 	    (fcntl(jp_1, F_GETFD, 0) < 0)) {
391956e45f6SSimon J. Gerraty 		jp_0 = -1;
392956e45f6SSimon J. Gerraty 		jp_1 = -1;
393b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
394956e45f6SSimon J. Gerraty 	} else {
395dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-J");
396dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
397956e45f6SSimon J. Gerraty 	}
398956e45f6SSimon J. Gerraty }
399956e45f6SSimon J. Gerraty 
400956e45f6SSimon J. Gerraty static void
40198875883SSimon J. Gerraty MainParseArgJobs(const char *arg)
402956e45f6SSimon J. Gerraty {
40398875883SSimon J. Gerraty 	const char *p;
40498875883SSimon J. Gerraty 	char *end;
40598875883SSimon J. Gerraty 	char v[12];
406956e45f6SSimon J. Gerraty 
407b0c40a00SSimon J. Gerraty 	forceJobs = true;
40898875883SSimon J. Gerraty 	opts.maxJobs = (int)strtol(arg, &end, 0);
409d5e0a182SSimon J. Gerraty 	p = end;
41098875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
41198875883SSimon J. Gerraty 	if (*p != '\0') {
41298875883SSimon J. Gerraty 		double d;
41398875883SSimon J. Gerraty 
414d5e0a182SSimon J. Gerraty 		if (*p == 'C')
41598875883SSimon J. Gerraty 			d = (opts.maxJobs > 0) ? opts.maxJobs : 1;
416d5e0a182SSimon J. Gerraty 		else if (*p == '.') {
41798875883SSimon J. Gerraty 			d = strtod(arg, &end);
418d5e0a182SSimon J. Gerraty 			p = end;
41998875883SSimon J. Gerraty 		} else
420d5e0a182SSimon J. Gerraty 			d = 0.0;
421d5e0a182SSimon J. Gerraty 		if (d > 0.0) {
42298875883SSimon J. Gerraty 			p = "";
42398875883SSimon J. Gerraty 			opts.maxJobs = (int)sysconf(_SC_NPROCESSORS_ONLN);
42498875883SSimon J. Gerraty 			opts.maxJobs = (int)(d * (double)opts.maxJobs);
42598875883SSimon J. Gerraty 		}
42698875883SSimon J. Gerraty 	}
42798875883SSimon J. Gerraty #endif
428956e45f6SSimon J. Gerraty 	if (*p != '\0' || opts.maxJobs < 1) {
429956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
43098875883SSimon J. Gerraty 		    "%s: argument '%s' to option '-j' "
43198875883SSimon J. Gerraty 		    "must be a positive number\n",
43298875883SSimon J. Gerraty 		    progname, arg);
43306b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
434956e45f6SSimon J. Gerraty 	}
43598875883SSimon J. Gerraty 	snprintf(v, sizeof(v), "%d", opts.maxJobs);
436dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-j");
43798875883SSimon J. Gerraty 	Global_Append(MAKEFLAGS, v);
43898875883SSimon J. Gerraty 	Global_Set(".MAKE.JOBS", v);
439956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
440956e45f6SSimon J. Gerraty }
441956e45f6SSimon J. Gerraty 
442956e45f6SSimon J. Gerraty static void
443956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue)
444956e45f6SSimon J. Gerraty {
445d5e0a182SSimon J. Gerraty 	if (strncmp(argvalue, ".../", 4) == 0) {
446956e45f6SSimon J. Gerraty 		char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
447956e45f6SSimon J. Gerraty 		if (found_path == NULL)
448956e45f6SSimon J. Gerraty 			return;
449dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, found_path);
450956e45f6SSimon J. Gerraty 		free(found_path);
451956e45f6SSimon J. Gerraty 	} else {
452dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, argvalue);
453956e45f6SSimon J. Gerraty 	}
454dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-m");
455dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, argvalue);
4564fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
457956e45f6SSimon J. Gerraty }
458956e45f6SSimon J. Gerraty 
459b0c40a00SSimon J. Gerraty static bool
4608c973ee2SSimon J. Gerraty MainParseOption(char c, const char *argvalue)
461956e45f6SSimon J. Gerraty {
462956e45f6SSimon J. Gerraty 	switch (c) {
463956e45f6SSimon J. Gerraty 	case '\0':
464956e45f6SSimon J. Gerraty 		break;
465956e45f6SSimon J. Gerraty 	case 'B':
466b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
467dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-B");
4688c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.MODE", "compat");
469956e45f6SSimon J. Gerraty 		break;
470956e45f6SSimon J. Gerraty 	case 'C':
471956e45f6SSimon J. Gerraty 		MainParseArgChdir(argvalue);
472956e45f6SSimon J. Gerraty 		break;
473956e45f6SSimon J. Gerraty 	case 'D':
4749f45a3c8SSimon J. Gerraty 		if (argvalue[0] == '\0')
4759f45a3c8SSimon J. Gerraty 			return false;
4769f45a3c8SSimon J. Gerraty 		Var_SetExpand(SCOPE_GLOBAL, argvalue, "1");
477dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-D");
478dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
479956e45f6SSimon J. Gerraty 		break;
480956e45f6SSimon J. Gerraty 	case 'I':
481d5e0a182SSimon J. Gerraty 		SearchPath_Add(parseIncPath, argvalue);
482dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-I");
483dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
484956e45f6SSimon J. Gerraty 		break;
485956e45f6SSimon J. Gerraty 	case 'J':
486956e45f6SSimon J. Gerraty 		MainParseArgJobsInternal(argvalue);
487956e45f6SSimon J. Gerraty 		break;
488956e45f6SSimon J. Gerraty 	case 'N':
489b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
490b0c40a00SSimon J. Gerraty 		opts.noRecursiveExecute = true;
491dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-N");
492956e45f6SSimon J. Gerraty 		break;
493956e45f6SSimon J. Gerraty 	case 'S':
494b0c40a00SSimon J. Gerraty 		opts.keepgoing = false;
495dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-S");
496956e45f6SSimon J. Gerraty 		break;
497956e45f6SSimon J. Gerraty 	case 'T':
498956e45f6SSimon J. Gerraty 		tracefile = bmake_strdup(argvalue);
499dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-T");
500dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
501956e45f6SSimon J. Gerraty 		break;
502956e45f6SSimon J. Gerraty 	case 'V':
503956e45f6SSimon J. Gerraty 	case 'v':
504e2eeea75SSimon J. Gerraty 		opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
50506b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.variables, bmake_strdup(argvalue));
506956e45f6SSimon J. Gerraty 		/* XXX: Why always -V? */
507dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-V");
508dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
509956e45f6SSimon J. Gerraty 		break;
510956e45f6SSimon J. Gerraty 	case 'W':
511b0c40a00SSimon J. Gerraty 		opts.parseWarnFatal = true;
5129f45a3c8SSimon J. Gerraty 		/* XXX: why no Global_Append? */
513956e45f6SSimon J. Gerraty 		break;
514956e45f6SSimon J. Gerraty 	case 'X':
515b0c40a00SSimon J. Gerraty 		opts.varNoExportEnv = true;
516dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-X");
517956e45f6SSimon J. Gerraty 		break;
518956e45f6SSimon J. Gerraty 	case 'd':
519956e45f6SSimon J. Gerraty 		/* If '-d-opts' don't pass to children */
520956e45f6SSimon J. Gerraty 		if (argvalue[0] == '-')
521956e45f6SSimon J. Gerraty 			argvalue++;
522956e45f6SSimon J. Gerraty 		else {
523dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, "-d");
524dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, argvalue);
525956e45f6SSimon J. Gerraty 		}
526dba7b0efSSimon J. Gerraty 		MainParseArgDebug(argvalue);
527956e45f6SSimon J. Gerraty 		break;
528956e45f6SSimon J. Gerraty 	case 'e':
529b0c40a00SSimon J. Gerraty 		opts.checkEnvFirst = true;
530dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-e");
531956e45f6SSimon J. Gerraty 		break;
532956e45f6SSimon J. Gerraty 	case 'f':
53306b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.makefiles, bmake_strdup(argvalue));
534956e45f6SSimon J. Gerraty 		break;
535956e45f6SSimon J. Gerraty 	case 'i':
536b0c40a00SSimon J. Gerraty 		opts.ignoreErrors = true;
537dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-i");
538956e45f6SSimon J. Gerraty 		break;
539956e45f6SSimon J. Gerraty 	case 'j':
540956e45f6SSimon J. Gerraty 		MainParseArgJobs(argvalue);
541956e45f6SSimon J. Gerraty 		break;
542956e45f6SSimon J. Gerraty 	case 'k':
543b0c40a00SSimon J. Gerraty 		opts.keepgoing = true;
544dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-k");
545956e45f6SSimon J. Gerraty 		break;
546956e45f6SSimon J. Gerraty 	case 'm':
547956e45f6SSimon J. Gerraty 		MainParseArgSysInc(argvalue);
548e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
549956e45f6SSimon J. Gerraty 		break;
550956e45f6SSimon J. Gerraty 	case 'n':
551b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
552dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-n");
553956e45f6SSimon J. Gerraty 		break;
554956e45f6SSimon J. Gerraty 	case 'q':
5559f45a3c8SSimon J. Gerraty 		opts.query = true;
556956e45f6SSimon J. Gerraty 		/* Kind of nonsensical, wot? */
557dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-q");
558956e45f6SSimon J. Gerraty 		break;
559956e45f6SSimon J. Gerraty 	case 'r':
560b0c40a00SSimon J. Gerraty 		opts.noBuiltins = true;
561dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-r");
562956e45f6SSimon J. Gerraty 		break;
563956e45f6SSimon J. Gerraty 	case 's':
5649f45a3c8SSimon J. Gerraty 		opts.silent = true;
565dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-s");
566956e45f6SSimon J. Gerraty 		break;
567956e45f6SSimon J. Gerraty 	case 't':
5689f45a3c8SSimon J. Gerraty 		opts.touch = true;
569dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-t");
570956e45f6SSimon J. Gerraty 		break;
571956e45f6SSimon J. Gerraty 	case 'w':
572b0c40a00SSimon J. Gerraty 		opts.enterFlag = true;
573dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-w");
574956e45f6SSimon J. Gerraty 		break;
575956e45f6SSimon J. Gerraty 	default:
576956e45f6SSimon J. Gerraty 		usage();
577956e45f6SSimon J. Gerraty 	}
578b0c40a00SSimon J. Gerraty 	return true;
579956e45f6SSimon J. Gerraty }
580956e45f6SSimon J. Gerraty 
58106b9b3e0SSimon J. Gerraty /*
58206b9b3e0SSimon J. Gerraty  * Parse the given arguments.  Called from main() and from
5833955d011SMarcel Moolenaar  * Main_ParseArgLine() when the .MAKEFLAGS target is used.
5843955d011SMarcel Moolenaar  *
585956e45f6SSimon J. Gerraty  * The arguments must be treated as read-only and will be freed after the
586956e45f6SSimon J. Gerraty  * call.
5873955d011SMarcel Moolenaar  *
58806b9b3e0SSimon J. Gerraty  * XXX: Deal with command line overriding .MAKEFLAGS in makefile
58906b9b3e0SSimon J. Gerraty  */
5903955d011SMarcel Moolenaar static void
5913955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv)
5923955d011SMarcel Moolenaar {
593956e45f6SSimon J. Gerraty 	char c;
5943955d011SMarcel Moolenaar 	int arginc;
5953955d011SMarcel Moolenaar 	char *argvalue;
5963955d011SMarcel Moolenaar 	char *optscan;
597b0c40a00SSimon J. Gerraty 	bool inOption, dashDash = false;
5983955d011SMarcel Moolenaar 
599956e45f6SSimon J. Gerraty 	const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
6003955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */
6013955d011SMarcel Moolenaar 
6023955d011SMarcel Moolenaar rearg:
603b0c40a00SSimon J. Gerraty 	inOption = false;
6043955d011SMarcel Moolenaar 	optscan = NULL;
6053955d011SMarcel Moolenaar 	while (argc > 1) {
606956e45f6SSimon J. Gerraty 		const char *optspec;
6073955d011SMarcel Moolenaar 		if (!inOption)
6083955d011SMarcel Moolenaar 			optscan = argv[1];
6093955d011SMarcel Moolenaar 		c = *optscan++;
6103955d011SMarcel Moolenaar 		arginc = 0;
6113955d011SMarcel Moolenaar 		if (inOption) {
6123955d011SMarcel Moolenaar 			if (c == '\0') {
613e2eeea75SSimon J. Gerraty 				argv++;
614e2eeea75SSimon J. Gerraty 				argc--;
615b0c40a00SSimon J. Gerraty 				inOption = false;
6163955d011SMarcel Moolenaar 				continue;
6173955d011SMarcel Moolenaar 			}
6183955d011SMarcel Moolenaar 		} else {
6193955d011SMarcel Moolenaar 			if (c != '-' || dashDash)
6203955d011SMarcel Moolenaar 				break;
621b0c40a00SSimon J. Gerraty 			inOption = true;
6223955d011SMarcel Moolenaar 			c = *optscan++;
6233955d011SMarcel Moolenaar 		}
6243955d011SMarcel Moolenaar 		/* '-' found at some earlier point */
625956e45f6SSimon J. Gerraty 		optspec = strchr(optspecs, c);
626956e45f6SSimon J. Gerraty 		if (c != '\0' && optspec != NULL && optspec[1] == ':') {
6279f45a3c8SSimon J. Gerraty 			/*
6289f45a3c8SSimon J. Gerraty 			 * -<something> found, and <something> should have an
6299f45a3c8SSimon J. Gerraty 			 * argument
6309f45a3c8SSimon J. Gerraty 			 */
631b0c40a00SSimon J. Gerraty 			inOption = false;
6323955d011SMarcel Moolenaar 			arginc = 1;
6333955d011SMarcel Moolenaar 			argvalue = optscan;
6343955d011SMarcel Moolenaar 			if (*argvalue == '\0') {
6353955d011SMarcel Moolenaar 				if (argc < 3)
6363955d011SMarcel Moolenaar 					goto noarg;
6373955d011SMarcel Moolenaar 				argvalue = argv[2];
6383955d011SMarcel Moolenaar 				arginc = 2;
6393955d011SMarcel Moolenaar 			}
6403955d011SMarcel Moolenaar 		} else {
6413955d011SMarcel Moolenaar 			argvalue = NULL;
6423955d011SMarcel Moolenaar 		}
6433955d011SMarcel Moolenaar 		switch (c) {
6443955d011SMarcel Moolenaar 		case '\0':
6453955d011SMarcel Moolenaar 			arginc = 1;
646b0c40a00SSimon J. Gerraty 			inOption = false;
6473955d011SMarcel Moolenaar 			break;
6483955d011SMarcel Moolenaar 		case '-':
649b0c40a00SSimon J. Gerraty 			dashDash = true;
6503955d011SMarcel Moolenaar 			break;
6513955d011SMarcel Moolenaar 		default:
6528c973ee2SSimon J. Gerraty 			if (!MainParseOption(c, argvalue))
653956e45f6SSimon J. Gerraty 				goto noarg;
6543955d011SMarcel Moolenaar 		}
6553955d011SMarcel Moolenaar 		argv += arginc;
6563955d011SMarcel Moolenaar 		argc -= arginc;
6573955d011SMarcel Moolenaar 	}
6583955d011SMarcel Moolenaar 
6593955d011SMarcel Moolenaar 	/*
6603955d011SMarcel Moolenaar 	 * See if the rest of the arguments are variable assignments and
6613955d011SMarcel Moolenaar 	 * perform them if so. Else take them to be targets and stuff them
6623955d011SMarcel Moolenaar 	 * on the end of the "create" list.
6633955d011SMarcel Moolenaar 	 */
664dba7b0efSSimon J. Gerraty 	for (; argc > 1; argv++, argc--) {
6659f45a3c8SSimon J. Gerraty 		if (!Parse_VarAssign(argv[1], false, SCOPE_CMDLINE)) {
666e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '\0')
6673955d011SMarcel Moolenaar 				Punt("illegal (null) argument.");
668e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '-' && !dashDash)
6693955d011SMarcel Moolenaar 				goto rearg;
67006b9b3e0SSimon J. Gerraty 			Lst_Append(&opts.create, bmake_strdup(argv[1]));
671956e45f6SSimon J. Gerraty 		}
6723955d011SMarcel Moolenaar 	}
6733955d011SMarcel Moolenaar 
6743955d011SMarcel Moolenaar 	return;
6753955d011SMarcel Moolenaar noarg:
6763955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
6773955d011SMarcel Moolenaar 	    progname, c);
6783955d011SMarcel Moolenaar 	usage();
6793955d011SMarcel Moolenaar }
6803955d011SMarcel Moolenaar 
68106b9b3e0SSimon J. Gerraty /*
68206b9b3e0SSimon J. Gerraty  * Break a line of arguments into words and parse them.
6833955d011SMarcel Moolenaar  *
684956e45f6SSimon J. Gerraty  * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
68506b9b3e0SSimon J. Gerraty  * by main() when reading the MAKEFLAGS environment variable.
68606b9b3e0SSimon J. Gerraty  */
6873955d011SMarcel Moolenaar void
6883955d011SMarcel Moolenaar Main_ParseArgLine(const char *line)
6893955d011SMarcel Moolenaar {
6902c3632d1SSimon J. Gerraty 	Words words;
6912c3632d1SSimon J. Gerraty 	char *buf;
692d5e0a182SSimon J. Gerraty 	const char *p;
6933955d011SMarcel Moolenaar 
6943955d011SMarcel Moolenaar 	if (line == NULL)
6953955d011SMarcel Moolenaar 		return;
696d5e0a182SSimon J. Gerraty 	for (p = line; *p == ' '; p++)
6973955d011SMarcel Moolenaar 		continue;
698d5e0a182SSimon J. Gerraty 	if (p[0] == '\0')
6993955d011SMarcel Moolenaar 		return;
7003955d011SMarcel Moolenaar 
701e2eeea75SSimon J. Gerraty 	{
702dba7b0efSSimon J. Gerraty 		FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE");
703d5e0a182SSimon J. Gerraty 		buf = str_concat3(argv0.str, " ", p);
70406b9b3e0SSimon J. Gerraty 		FStr_Done(&argv0);
705e2eeea75SSimon J. Gerraty 	}
7063955d011SMarcel Moolenaar 
707b0c40a00SSimon J. Gerraty 	words = Str_Words(buf, true);
7082c3632d1SSimon J. Gerraty 	if (words.words == NULL) {
7093955d011SMarcel Moolenaar 		Error("Unterminated quoted string [%s]", buf);
7103955d011SMarcel Moolenaar 		free(buf);
7113955d011SMarcel Moolenaar 		return;
7123955d011SMarcel Moolenaar 	}
7133955d011SMarcel Moolenaar 	free(buf);
7142c3632d1SSimon J. Gerraty 	MainParseArgs((int)words.len, words.words);
7153955d011SMarcel Moolenaar 
7162c3632d1SSimon J. Gerraty 	Words_Free(words);
7173955d011SMarcel Moolenaar }
7183955d011SMarcel Moolenaar 
719b0c40a00SSimon J. Gerraty bool
720b0c40a00SSimon J. Gerraty Main_SetObjdir(bool writable, const char *fmt, ...)
7213955d011SMarcel Moolenaar {
7223955d011SMarcel Moolenaar 	struct stat sb;
723b46b9039SSimon J. Gerraty 	char *path;
724b46b9039SSimon J. Gerraty 	char buf[MAXPATHLEN + 1];
725e23f3f6eSSimon J. Gerraty 	char buf2[MAXPATHLEN + 1];
72645447996SSimon J. Gerraty 	va_list ap;
72745447996SSimon J. Gerraty 
72845447996SSimon J. Gerraty 	va_start(ap, fmt);
729b46b9039SSimon J. Gerraty 	vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
73045447996SSimon J. Gerraty 	va_end(ap);
7313955d011SMarcel Moolenaar 
7323955d011SMarcel Moolenaar 	if (path[0] != '/') {
7334fde40d9SSimon J. Gerraty 		if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN)
734e1cee40dSSimon J. Gerraty 			path = buf2;
7354fde40d9SSimon J. Gerraty 		else
7364fde40d9SSimon J. Gerraty 			return false;
7373955d011SMarcel Moolenaar 	}
7383955d011SMarcel Moolenaar 
7393955d011SMarcel Moolenaar 	/* look for the directory and try to chdir there */
7409f45a3c8SSimon J. Gerraty 	if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))
7419f45a3c8SSimon J. Gerraty 		return false;
7429f45a3c8SSimon J. Gerraty 
7439f45a3c8SSimon J. Gerraty 	if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
7441d3f2ddcSSimon J. Gerraty 		(void)fprintf(stderr, "%s: warning: %s: %s.\n",
745e2eeea75SSimon J. Gerraty 		    progname, path, strerror(errno));
746*8d5c8e21SSimon J. Gerraty 		/* Allow debugging how we got here - not always obvious */
747*8d5c8e21SSimon J. Gerraty 		if (GetBooleanExpr("${MAKE_DEBUG_OBJDIR_CHECK_WRITABLE}",
748*8d5c8e21SSimon J. Gerraty 			false))
749*8d5c8e21SSimon J. Gerraty 			PrintOnError(NULL, "");
7509f45a3c8SSimon J. Gerraty 		return false;
7519f45a3c8SSimon J. Gerraty 	}
7529f45a3c8SSimon J. Gerraty 
7532c3632d1SSimon J. Gerraty 	snprintf(objdir, sizeof objdir, "%s", path);
754dba7b0efSSimon J. Gerraty 	Global_Set(".OBJDIR", objdir);
7553955d011SMarcel Moolenaar 	setenv("PWD", objdir, 1);
7563955d011SMarcel Moolenaar 	Dir_InitDot();
757e2eeea75SSimon J. Gerraty 	purge_relative_cached_realpaths();
758956e45f6SSimon J. Gerraty 	if (opts.enterFlag && strcmp(objdir, curdir) != 0)
759b0c40a00SSimon J. Gerraty 		enterFlagObj = true;
7609f45a3c8SSimon J. Gerraty 	return true;
7613955d011SMarcel Moolenaar }
7623955d011SMarcel Moolenaar 
763b0c40a00SSimon J. Gerraty static bool
764b0c40a00SSimon J. Gerraty SetVarObjdir(bool writable, const char *var, const char *suffix)
76545447996SSimon J. Gerraty {
766dba7b0efSSimon J. Gerraty 	FStr path = Var_Value(SCOPE_CMDLINE, var);
767b46b9039SSimon J. Gerraty 
76806b9b3e0SSimon J. Gerraty 	if (path.str == NULL || path.str[0] == '\0') {
76906b9b3e0SSimon J. Gerraty 		FStr_Done(&path);
770b0c40a00SSimon J. Gerraty 		return false;
7712c3632d1SSimon J. Gerraty 	}
77245447996SSimon J. Gerraty 
773*8d5c8e21SSimon J. Gerraty 	Var_Expand(&path, SCOPE_GLOBAL, VARE_EVAL);
774b46b9039SSimon J. Gerraty 
7759f45a3c8SSimon J. Gerraty 	(void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
776b46b9039SSimon J. Gerraty 
77706b9b3e0SSimon J. Gerraty 	FStr_Done(&path);
778b0c40a00SSimon J. Gerraty 	return true;
77945447996SSimon J. Gerraty }
78045447996SSimon J. Gerraty 
78106b9b3e0SSimon J. Gerraty /*
782d5e0a182SSimon J. Gerraty  * Splits str into words (in-place, modifying it), adding them to the list.
78306b9b3e0SSimon J. Gerraty  * The string must be kept alive as long as the list.
78406b9b3e0SSimon J. Gerraty  */
785d5e0a182SSimon J. Gerraty void
786d5e0a182SSimon J. Gerraty AppendWords(StringList *lp, char *str)
7873955d011SMarcel Moolenaar {
788d5e0a182SSimon J. Gerraty 	char *p;
789e2eeea75SSimon J. Gerraty 	const char *sep = " \t";
7903955d011SMarcel Moolenaar 
791d5e0a182SSimon J. Gerraty 	for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep))
792d5e0a182SSimon J. Gerraty 		Lst_Append(lp, p);
7933955d011SMarcel Moolenaar }
7943955d011SMarcel Moolenaar 
7953955d011SMarcel Moolenaar #ifdef SIGINFO
7963955d011SMarcel Moolenaar /*ARGSUSED*/
7973955d011SMarcel Moolenaar static void
7983955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED)
7993955d011SMarcel Moolenaar {
8003955d011SMarcel Moolenaar 	char dir[MAXPATHLEN];
8013955d011SMarcel Moolenaar 	char str[2 * MAXPATHLEN];
8023955d011SMarcel Moolenaar 	int len;
803e2eeea75SSimon J. Gerraty 	if (getcwd(dir, sizeof dir) == NULL)
8043955d011SMarcel Moolenaar 		return;
805e2eeea75SSimon J. Gerraty 	len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir);
8063955d011SMarcel Moolenaar 	if (len > 0)
8073955d011SMarcel Moolenaar 		(void)write(STDERR_FILENO, str, (size_t)len);
8083955d011SMarcel Moolenaar }
8093955d011SMarcel Moolenaar #endif
8103955d011SMarcel Moolenaar 
81106b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */
81206b9b3e0SSimon J. Gerraty static void
81306b9b3e0SSimon J. Gerraty MakeMode(void)
8143955d011SMarcel Moolenaar {
815*8d5c8e21SSimon J. Gerraty 	char *mode = Var_Subst("${.MAKE.MODE:tl}", SCOPE_GLOBAL, VARE_EVAL);
816956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
8173955d011SMarcel Moolenaar 
818dba7b0efSSimon J. Gerraty 	if (mode[0] != '\0') {
819dba7b0efSSimon J. Gerraty 		if (strstr(mode, "compat") != NULL) {
820b0c40a00SSimon J. Gerraty 			opts.compatMake = true;
821b0c40a00SSimon J. Gerraty 			forceJobs = false;
8223955d011SMarcel Moolenaar 		}
8233955d011SMarcel Moolenaar #if USE_META
824dba7b0efSSimon J. Gerraty 		if (strstr(mode, "meta") != NULL)
825dba7b0efSSimon J. Gerraty 			meta_mode_init(mode);
8263955d011SMarcel Moolenaar #endif
827954401e6SSimon J. Gerraty 		if (strstr(mode, "randomize-targets") != NULL)
828954401e6SSimon J. Gerraty 			opts.randomizeTargets = true;
8293955d011SMarcel Moolenaar 	}
830be19d90bSSimon J. Gerraty 
831dba7b0efSSimon J. Gerraty 	free(mode);
8323955d011SMarcel Moolenaar }
8333955d011SMarcel Moolenaar 
8348695518cSSimon J. Gerraty static void
835b0c40a00SSimon J. Gerraty PrintVar(const char *varname, bool expandVars)
836956e45f6SSimon J. Gerraty {
83706b9b3e0SSimon J. Gerraty 	if (strchr(varname, '$') != NULL) {
838*8d5c8e21SSimon J. Gerraty 		char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_EVAL);
839956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
840956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8419f45a3c8SSimon J. Gerraty 		free(evalue);
842956e45f6SSimon J. Gerraty 
843956e45f6SSimon J. Gerraty 	} else if (expandVars) {
844956e45f6SSimon J. Gerraty 		char *expr = str_concat3("${", varname, "}");
845*8d5c8e21SSimon J. Gerraty 		char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
846956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
847956e45f6SSimon J. Gerraty 		free(expr);
848956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8499f45a3c8SSimon J. Gerraty 		free(evalue);
850956e45f6SSimon J. Gerraty 
851956e45f6SSimon J. Gerraty 	} else {
852dba7b0efSSimon J. Gerraty 		FStr value = Var_Value(SCOPE_GLOBAL, varname);
85306b9b3e0SSimon J. Gerraty 		printf("%s\n", value.str != NULL ? value.str : "");
85406b9b3e0SSimon J. Gerraty 		FStr_Done(&value);
855956e45f6SSimon J. Gerraty 	}
856956e45f6SSimon J. Gerraty }
857956e45f6SSimon J. Gerraty 
858e2eeea75SSimon J. Gerraty /*
859b0c40a00SSimon J. Gerraty  * Return a bool based on a variable.
860e2eeea75SSimon J. Gerraty  *
861e2eeea75SSimon J. Gerraty  * If the knob is not set, return the fallback.
862e2eeea75SSimon J. Gerraty  * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
863b0c40a00SSimon J. Gerraty  * is false, otherwise true.
864e2eeea75SSimon J. Gerraty  */
865b0c40a00SSimon J. Gerraty bool
866b0c40a00SSimon J. Gerraty GetBooleanExpr(const char *expr, bool fallback)
867e2eeea75SSimon J. Gerraty {
868e2eeea75SSimon J. Gerraty 	char *value;
869b0c40a00SSimon J. Gerraty 	bool res;
870e2eeea75SSimon J. Gerraty 
871*8d5c8e21SSimon J. Gerraty 	value = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
872e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
873e2eeea75SSimon J. Gerraty 	res = ParseBoolean(value, fallback);
874e2eeea75SSimon J. Gerraty 	free(value);
875e2eeea75SSimon J. Gerraty 	return res;
876e2eeea75SSimon J. Gerraty }
877e2eeea75SSimon J. Gerraty 
878956e45f6SSimon J. Gerraty static void
8798695518cSSimon J. Gerraty doPrintVars(void)
8808695518cSSimon J. Gerraty {
881956e45f6SSimon J. Gerraty 	StringListNode *ln;
882b0c40a00SSimon J. Gerraty 	bool expandVars;
8838695518cSSimon J. Gerraty 
884e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_EXPANDED)
885b0c40a00SSimon J. Gerraty 		expandVars = true;
886956e45f6SSimon J. Gerraty 	else if (opts.debugVflag)
887b0c40a00SSimon J. Gerraty 		expandVars = false;
8888695518cSSimon J. Gerraty 	else
889b0c40a00SSimon J. Gerraty 		expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}",
890b0c40a00SSimon J. Gerraty 		    false);
8918695518cSSimon J. Gerraty 
89206b9b3e0SSimon J. Gerraty 	for (ln = opts.variables.first; ln != NULL; ln = ln->next) {
893956e45f6SSimon J. Gerraty 		const char *varname = ln->datum;
894956e45f6SSimon J. Gerraty 		PrintVar(varname, expandVars);
8958695518cSSimon J. Gerraty 	}
8968695518cSSimon J. Gerraty }
8978695518cSSimon J. Gerraty 
898b0c40a00SSimon J. Gerraty static bool
8998695518cSSimon J. Gerraty runTargets(void)
9008695518cSSimon J. Gerraty {
90106b9b3e0SSimon J. Gerraty 	GNodeList targs = LST_INIT;	/* target nodes to create */
902b0c40a00SSimon J. Gerraty 	bool outOfDate;		/* false if all targets up to date */
9038695518cSSimon J. Gerraty 
9048695518cSSimon J. Gerraty 	/*
9058695518cSSimon J. Gerraty 	 * Have now read the entire graph and need to make a list of
9068695518cSSimon J. Gerraty 	 * targets to create. If none was given on the command line,
9078695518cSSimon J. Gerraty 	 * we consult the parsing module to find the main target(s)
9088695518cSSimon J. Gerraty 	 * to create.
9098695518cSSimon J. Gerraty 	 */
91006b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create))
91106b9b3e0SSimon J. Gerraty 		Parse_MainName(&targs);
9128695518cSSimon J. Gerraty 	else
91306b9b3e0SSimon J. Gerraty 		Targ_FindList(&targs, &opts.create);
9148695518cSSimon J. Gerraty 
915956e45f6SSimon J. Gerraty 	if (!opts.compatMake) {
9168695518cSSimon J. Gerraty 		/*
9178695518cSSimon J. Gerraty 		 * Initialize job module before traversing the graph
9188695518cSSimon J. Gerraty 		 * now that any .BEGIN and .END targets have been read.
9198695518cSSimon J. Gerraty 		 * This is done only if the -q flag wasn't given
9208695518cSSimon J. Gerraty 		 * (to prevent the .BEGIN from being executed should
9218695518cSSimon J. Gerraty 		 * it exist).
9228695518cSSimon J. Gerraty 		 */
9239f45a3c8SSimon J. Gerraty 		if (!opts.query) {
9248695518cSSimon J. Gerraty 			Job_Init();
925b0c40a00SSimon J. Gerraty 			jobsRunning = true;
9268695518cSSimon J. Gerraty 		}
9278695518cSSimon J. Gerraty 
9288695518cSSimon J. Gerraty 		/* Traverse the graph, checking on all the targets */
92906b9b3e0SSimon J. Gerraty 		outOfDate = Make_Run(&targs);
9308695518cSSimon J. Gerraty 	} else {
931954401e6SSimon J. Gerraty 		Compat_MakeAll(&targs);
932b0c40a00SSimon J. Gerraty 		outOfDate = false;
9338695518cSSimon J. Gerraty 	}
934dba7b0efSSimon J. Gerraty 	Lst_Done(&targs);	/* Don't free the targets themselves. */
9358695518cSSimon J. Gerraty 	return outOfDate;
9368695518cSSimon J. Gerraty }
9378695518cSSimon J. Gerraty 
938956e45f6SSimon J. Gerraty /*
9399f45a3c8SSimon J. Gerraty  * Set up the .TARGETS variable to contain the list of targets to be created.
9409f45a3c8SSimon J. Gerraty  * If none specified, make the variable empty for now, the parser will fill
9419f45a3c8SSimon J. Gerraty  * in the default or .MAIN target later.
942956e45f6SSimon J. Gerraty  */
943956e45f6SSimon J. Gerraty static void
944956e45f6SSimon J. Gerraty InitVarTargets(void)
945956e45f6SSimon J. Gerraty {
946956e45f6SSimon J. Gerraty 	StringListNode *ln;
947956e45f6SSimon J. Gerraty 
94806b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create)) {
949dba7b0efSSimon J. Gerraty 		Global_Set(".TARGETS", "");
950956e45f6SSimon J. Gerraty 		return;
951956e45f6SSimon J. Gerraty 	}
952956e45f6SSimon J. Gerraty 
95306b9b3e0SSimon J. Gerraty 	for (ln = opts.create.first; ln != NULL; ln = ln->next) {
954dba7b0efSSimon J. Gerraty 		const char *name = ln->datum;
955dba7b0efSSimon J. Gerraty 		Global_Append(".TARGETS", name);
956956e45f6SSimon J. Gerraty 	}
957956e45f6SSimon J. Gerraty }
958956e45f6SSimon J. Gerraty 
959956e45f6SSimon J. Gerraty static void
960956e45f6SSimon J. Gerraty InitRandom(void)
961956e45f6SSimon J. Gerraty {
962956e45f6SSimon J. Gerraty 	struct timeval tv;
963956e45f6SSimon J. Gerraty 
964956e45f6SSimon J. Gerraty 	gettimeofday(&tv, NULL);
965956e45f6SSimon J. Gerraty 	srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
966956e45f6SSimon J. Gerraty }
967956e45f6SSimon J. Gerraty 
968956e45f6SSimon J. Gerraty static const char *
969dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED)
970956e45f6SSimon J. Gerraty {
971956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE
972e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE;
973956e45f6SSimon J. Gerraty #else
974956e45f6SSimon J. Gerraty     	const char *machine = getenv("MACHINE");
975e2eeea75SSimon J. Gerraty 
976956e45f6SSimon J. Gerraty 	if (machine != NULL)
977956e45f6SSimon J. Gerraty 		return machine;
978956e45f6SSimon J. Gerraty 
979e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE)
980956e45f6SSimon J. Gerraty 	return utsname->machine;
981e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE)
982956e45f6SSimon J. Gerraty 	return MAKE_MACHINE;
983956e45f6SSimon J. Gerraty #else
984956e45f6SSimon J. Gerraty 	return "unknown";
985956e45f6SSimon J. Gerraty #endif
986956e45f6SSimon J. Gerraty #endif
987956e45f6SSimon J. Gerraty }
988956e45f6SSimon J. Gerraty 
989956e45f6SSimon J. Gerraty static const char *
990e2eeea75SSimon J. Gerraty InitVarMachineArch(void)
991956e45f6SSimon J. Gerraty {
992e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH
993e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE_ARCH;
994e2eeea75SSimon J. Gerraty #else
995956e45f6SSimon J. Gerraty 	const char *env = getenv("MACHINE_ARCH");
996956e45f6SSimon J. Gerraty 	if (env != NULL)
997956e45f6SSimon J. Gerraty 		return env;
998956e45f6SSimon J. Gerraty 
999956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW)
1000956e45f6SSimon J. Gerraty 	{
1001956e45f6SSimon J. Gerraty 		struct utsname utsname;
1002e2eeea75SSimon J. Gerraty 		static char machine_arch_buf[sizeof utsname.machine];
1003956e45f6SSimon J. Gerraty 		const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
1004e2eeea75SSimon J. Gerraty 		size_t len = sizeof machine_arch_buf;
1005956e45f6SSimon J. Gerraty 
100606b9b3e0SSimon J. Gerraty 		if (sysctl(mib, (unsigned int)__arraycount(mib),
100706b9b3e0SSimon J. Gerraty 		    machine_arch_buf, &len, NULL, 0) < 0) {
100806b9b3e0SSimon J. Gerraty 			(void)fprintf(stderr, "%s: sysctl failed (%s).\n",
100906b9b3e0SSimon J. Gerraty 			    progname, strerror(errno));
1010956e45f6SSimon J. Gerraty 			exit(2);
1011956e45f6SSimon J. Gerraty 		}
1012956e45f6SSimon J. Gerraty 
1013956e45f6SSimon J. Gerraty 		return machine_arch_buf;
1014956e45f6SSimon J. Gerraty 	}
1015e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH)
1016e2eeea75SSimon J. Gerraty 	return MACHINE_ARCH;
1017e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH)
1018956e45f6SSimon J. Gerraty 	return MAKE_MACHINE_ARCH;
1019956e45f6SSimon J. Gerraty #else
1020956e45f6SSimon J. Gerraty 	return "unknown";
1021956e45f6SSimon J. Gerraty #endif
1022956e45f6SSimon J. Gerraty #endif
1023956e45f6SSimon J. Gerraty }
1024956e45f6SSimon J. Gerraty 
1025956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE
1026956e45f6SSimon J. Gerraty /*
1027956e45f6SSimon J. Gerraty  * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1028956e45f6SSimon J. Gerraty  * since the value of curdir can vary depending on how we got
1029d5e0a182SSimon J. Gerraty  * here.  That is, sitting at a shell prompt (shell that provides $PWD)
1030d5e0a182SSimon J. Gerraty  * or via subdir.mk, in which case it's likely a shell which does
1031956e45f6SSimon J. Gerraty  * not provide it.
1032956e45f6SSimon J. Gerraty  *
1033956e45f6SSimon J. Gerraty  * So, to stop it breaking this case only, we ignore PWD if
1034d5e0a182SSimon J. Gerraty  * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression.
1035956e45f6SSimon J. Gerraty  */
1036956e45f6SSimon J. Gerraty static void
1037956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st)
1038956e45f6SSimon J. Gerraty {
1039956e45f6SSimon J. Gerraty 	char *pwd;
10409f45a3c8SSimon J. Gerraty 	FStr makeobjdir;
1041956e45f6SSimon J. Gerraty 	struct stat pwd_st;
1042956e45f6SSimon J. Gerraty 
1043956e45f6SSimon J. Gerraty 	if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1044956e45f6SSimon J. Gerraty 		return;
1045956e45f6SSimon J. Gerraty 
10469f45a3c8SSimon J. Gerraty 	if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"))
1047956e45f6SSimon J. Gerraty 		return;
1048956e45f6SSimon J. Gerraty 
1049dba7b0efSSimon J. Gerraty 	makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR");
105006b9b3e0SSimon J. Gerraty 	if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
1051956e45f6SSimon J. Gerraty 		goto ignore_pwd;
1052956e45f6SSimon J. Gerraty 
1053956e45f6SSimon J. Gerraty 	if (stat(pwd, &pwd_st) == 0 &&
1054956e45f6SSimon J. Gerraty 	    curdir_st->st_ino == pwd_st.st_ino &&
1055956e45f6SSimon J. Gerraty 	    curdir_st->st_dev == pwd_st.st_dev)
1056*8d5c8e21SSimon J. Gerraty 		snprintf(curdir, MAXPATHLEN, "%s", pwd);
1057956e45f6SSimon J. Gerraty 
1058956e45f6SSimon J. Gerraty ignore_pwd:
105906b9b3e0SSimon J. Gerraty 	FStr_Done(&makeobjdir);
1060956e45f6SSimon J. Gerraty }
1061956e45f6SSimon J. Gerraty #endif
1062956e45f6SSimon J. Gerraty 
1063956e45f6SSimon J. Gerraty /*
10649f45a3c8SSimon J. Gerraty  * Find the .OBJDIR.  If MAKEOBJDIRPREFIX, or failing that, MAKEOBJDIR is set
10659f45a3c8SSimon J. Gerraty  * in the environment, try only that value and fall back to .CURDIR if it
10669f45a3c8SSimon J. Gerraty  * does not exist.
1067956e45f6SSimon J. Gerraty  *
1068956e45f6SSimon J. Gerraty  * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
10699f45a3c8SSimon J. Gerraty  * and finally _PATH_OBJDIRPREFIX`pwd`, in that order.  If none of these
10709f45a3c8SSimon J. Gerraty  * paths exist, just use .CURDIR.
1071956e45f6SSimon J. Gerraty  */
1072956e45f6SSimon J. Gerraty static void
1073956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch)
1074956e45f6SSimon J. Gerraty {
1075b0c40a00SSimon J. Gerraty 	bool writable;
1076956e45f6SSimon J. Gerraty 
107706b9b3e0SSimon J. Gerraty 	Dir_InitCur(curdir);
1078b0c40a00SSimon J. Gerraty 	writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true);
1079b0c40a00SSimon J. Gerraty 	(void)Main_SetObjdir(false, "%s", curdir);
1080e2eeea75SSimon J. Gerraty 
1081e2eeea75SSimon J. Gerraty 	if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
1082e2eeea75SSimon J. Gerraty 	    !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
1083e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1084e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
1085e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
1086e2eeea75SSimon J. Gerraty 		(void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
1087956e45f6SSimon J. Gerraty }
1088956e45f6SSimon J. Gerraty 
1089956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */
1090956e45f6SSimon J. Gerraty static void
1091956e45f6SSimon J. Gerraty UnlimitFiles(void)
1092956e45f6SSimon J. Gerraty {
109312904384SSimon J. Gerraty #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
1094956e45f6SSimon J. Gerraty 	struct rlimit rl;
1095956e45f6SSimon J. Gerraty 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1096956e45f6SSimon J. Gerraty 	    rl.rlim_cur != rl.rlim_max) {
10978c973ee2SSimon J. Gerraty #ifdef BMAKE_NOFILE_MAX
10988c973ee2SSimon J. Gerraty 		if (BMAKE_NOFILE_MAX < rl.rlim_max)
10998c973ee2SSimon J. Gerraty 			rl.rlim_cur = BMAKE_NOFILE_MAX;
11008c973ee2SSimon J. Gerraty 		else
11018c973ee2SSimon J. Gerraty #endif
1102956e45f6SSimon J. Gerraty 		rl.rlim_cur = rl.rlim_max;
1103956e45f6SSimon J. Gerraty 		(void)setrlimit(RLIMIT_NOFILE, &rl);
1104956e45f6SSimon J. Gerraty 	}
1105956e45f6SSimon J. Gerraty #endif
1106956e45f6SSimon J. Gerraty }
1107956e45f6SSimon J. Gerraty 
1108956e45f6SSimon J. Gerraty static void
1109956e45f6SSimon J. Gerraty CmdOpts_Init(void)
1110956e45f6SSimon J. Gerraty {
1111b0c40a00SSimon J. Gerraty 	opts.compatMake = false;
11129f45a3c8SSimon J. Gerraty 	memset(&opts.debug, 0, sizeof(opts.debug));
1113dba7b0efSSimon J. Gerraty 	/* opts.debug_file has already been initialized earlier */
1114b0c40a00SSimon J. Gerraty 	opts.strict = false;
1115b0c40a00SSimon J. Gerraty 	opts.debugVflag = false;
1116b0c40a00SSimon J. Gerraty 	opts.checkEnvFirst = false;
111706b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.makefiles);
1118b0c40a00SSimon J. Gerraty 	opts.ignoreErrors = false;	/* Pay attention to non-zero returns */
111906b9b3e0SSimon J. Gerraty 	opts.maxJobs = 1;
1120b0c40a00SSimon J. Gerraty 	opts.keepgoing = false;		/* Stop on error */
1121b0c40a00SSimon J. Gerraty 	opts.noRecursiveExecute = false; /* Execute all .MAKE targets */
1122b0c40a00SSimon J. Gerraty 	opts.noExecute = false;		/* Execute all commands */
11239f45a3c8SSimon J. Gerraty 	opts.query = false;
1124b0c40a00SSimon J. Gerraty 	opts.noBuiltins = false;	/* Read the built-in rules */
11259f45a3c8SSimon J. Gerraty 	opts.silent = false;		/* Print commands as executed */
11269f45a3c8SSimon J. Gerraty 	opts.touch = false;
1127e2eeea75SSimon J. Gerraty 	opts.printVars = PVM_NONE;
112806b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.variables);
1129b0c40a00SSimon J. Gerraty 	opts.parseWarnFatal = false;
1130b0c40a00SSimon J. Gerraty 	opts.enterFlag = false;
1131b0c40a00SSimon J. Gerraty 	opts.varNoExportEnv = false;
113206b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.create);
1133956e45f6SSimon J. Gerraty }
1134956e45f6SSimon J. Gerraty 
113506b9b3e0SSimon J. Gerraty /*
113606b9b3e0SSimon J. Gerraty  * Initialize MAKE and .MAKE to the path of the executable, so that it can be
1137956e45f6SSimon J. Gerraty  * found by execvp(3) and the shells, even after a chdir.
1138956e45f6SSimon J. Gerraty  *
1139956e45f6SSimon J. Gerraty  * If it's a relative path and contains a '/', resolve it to an absolute path.
114006b9b3e0SSimon J. Gerraty  * Otherwise keep it as is, assuming it will be found in the PATH.
114106b9b3e0SSimon J. Gerraty  */
1142956e45f6SSimon J. Gerraty static void
1143956e45f6SSimon J. Gerraty InitVarMake(const char *argv0)
1144956e45f6SSimon J. Gerraty {
1145956e45f6SSimon J. Gerraty 	const char *make = argv0;
1146*8d5c8e21SSimon J. Gerraty 	char pathbuf[MAXPATHLEN];
1147956e45f6SSimon J. Gerraty 
1148956e45f6SSimon J. Gerraty 	if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
114906b9b3e0SSimon J. Gerraty 		const char *abspath = cached_realpath(argv0, pathbuf);
1150956e45f6SSimon J. Gerraty 		struct stat st;
115106b9b3e0SSimon J. Gerraty 		if (abspath != NULL && abspath[0] == '/' &&
115206b9b3e0SSimon J. Gerraty 		    stat(make, &st) == 0)
115306b9b3e0SSimon J. Gerraty 			make = abspath;
1154956e45f6SSimon J. Gerraty 	}
1155956e45f6SSimon J. Gerraty 
1156dba7b0efSSimon J. Gerraty 	Global_Set("MAKE", make);
1157dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE", make);
1158956e45f6SSimon J. Gerraty }
1159956e45f6SSimon J. Gerraty 
116006b9b3e0SSimon J. Gerraty /*
116106b9b3e0SSimon J. Gerraty  * Add the directories from the colon-separated syspath to defSysIncPath.
116206b9b3e0SSimon J. Gerraty  * After returning, the contents of syspath is unspecified.
116306b9b3e0SSimon J. Gerraty  */
1164956e45f6SSimon J. Gerraty static void
1165956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath)
1166956e45f6SSimon J. Gerraty {
1167956e45f6SSimon J. Gerraty 	static char defsyspath[] = _PATH_DEFSYSPATH;
1168d5e0a182SSimon J. Gerraty 	char *start, *p;
1169956e45f6SSimon J. Gerraty 
1170956e45f6SSimon J. Gerraty 	/*
1171956e45f6SSimon J. Gerraty 	 * If no user-supplied system path was given (through the -m option)
1172956e45f6SSimon J. Gerraty 	 * add the directories from the DEFSYSPATH (more than one may be given
1173956e45f6SSimon J. Gerraty 	 * as dir1:...:dirn) to the system include path.
1174956e45f6SSimon J. Gerraty 	 */
1175956e45f6SSimon J. Gerraty 	if (syspath == NULL || syspath[0] == '\0')
1176956e45f6SSimon J. Gerraty 		syspath = defsyspath;
1177956e45f6SSimon J. Gerraty 	else
1178956e45f6SSimon J. Gerraty 		syspath = bmake_strdup(syspath);
1179956e45f6SSimon J. Gerraty 
1180d5e0a182SSimon J. Gerraty 	for (start = syspath; *start != '\0'; start = p) {
1181d5e0a182SSimon J. Gerraty 		for (p = start; *p != '\0' && *p != ':'; p++)
1182956e45f6SSimon J. Gerraty 			continue;
1183d5e0a182SSimon J. Gerraty 		if (*p == ':')
1184d5e0a182SSimon J. Gerraty 			*p++ = '\0';
1185e2eeea75SSimon J. Gerraty 
1186956e45f6SSimon J. Gerraty 		/* look for magic parent directory search string */
1187e2eeea75SSimon J. Gerraty 		if (strncmp(start, ".../", 4) == 0) {
1188956e45f6SSimon J. Gerraty 			char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1189956e45f6SSimon J. Gerraty 			if (dir != NULL) {
1190dba7b0efSSimon J. Gerraty 				(void)SearchPath_Add(defSysIncPath, dir);
1191956e45f6SSimon J. Gerraty 				free(dir);
1192956e45f6SSimon J. Gerraty 			}
1193e2eeea75SSimon J. Gerraty 		} else {
1194dba7b0efSSimon J. Gerraty 			(void)SearchPath_Add(defSysIncPath, start);
1195956e45f6SSimon J. Gerraty 		}
1196956e45f6SSimon J. Gerraty 	}
1197956e45f6SSimon J. Gerraty 
1198956e45f6SSimon J. Gerraty 	if (syspath != defsyspath)
1199956e45f6SSimon J. Gerraty 		free(syspath);
1200956e45f6SSimon J. Gerraty }
1201956e45f6SSimon J. Gerraty 
1202956e45f6SSimon J. Gerraty static void
1203956e45f6SSimon J. Gerraty ReadBuiltinRules(void)
1204956e45f6SSimon J. Gerraty {
1205e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1206dba7b0efSSimon J. Gerraty 	StringList sysMkFiles = LST_INIT;
1207e2eeea75SSimon J. Gerraty 
1208dba7b0efSSimon J. Gerraty 	SearchPath_Expand(
1209dba7b0efSSimon J. Gerraty 	    Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath,
1210dba7b0efSSimon J. Gerraty 	    _PATH_DEFSYSMK,
1211dba7b0efSSimon J. Gerraty 	    &sysMkFiles);
1212dba7b0efSSimon J. Gerraty 	if (Lst_IsEmpty(&sysMkFiles))
1213956e45f6SSimon J. Gerraty 		Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1214e2eeea75SSimon J. Gerraty 
1215dba7b0efSSimon J. Gerraty 	for (ln = sysMkFiles.first; ln != NULL; ln = ln->next)
12169f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1217e2eeea75SSimon J. Gerraty 			break;
1218e2eeea75SSimon J. Gerraty 
1219e2eeea75SSimon J. Gerraty 	if (ln == NULL)
1220e2eeea75SSimon J. Gerraty 		Fatal("%s: cannot open %s.",
1221dba7b0efSSimon J. Gerraty 		    progname, (const char *)sysMkFiles.first->datum);
1222e2eeea75SSimon J. Gerraty 
1223548bfc56SSimon J. Gerraty 	Lst_DoneFree(&sysMkFiles);
1224956e45f6SSimon J. Gerraty }
1225956e45f6SSimon J. Gerraty 
1226956e45f6SSimon J. Gerraty static void
1227956e45f6SSimon J. Gerraty InitMaxJobs(void)
1228956e45f6SSimon J. Gerraty {
1229956e45f6SSimon J. Gerraty 	char *value;
1230956e45f6SSimon J. Gerraty 	int n;
1231956e45f6SSimon J. Gerraty 
1232956e45f6SSimon J. Gerraty 	if (forceJobs || opts.compatMake ||
1233dba7b0efSSimon J. Gerraty 	    !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
1234956e45f6SSimon J. Gerraty 		return;
1235956e45f6SSimon J. Gerraty 
1236*8d5c8e21SSimon J. Gerraty 	value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_EVAL);
1237956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1238956e45f6SSimon J. Gerraty 	n = (int)strtol(value, NULL, 0);
1239956e45f6SSimon J. Gerraty 	if (n < 1) {
1240956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
1241956e45f6SSimon J. Gerraty 		    "%s: illegal value for .MAKE.JOBS "
1242956e45f6SSimon J. Gerraty 		    "-- must be positive integer!\n",
1243956e45f6SSimon J. Gerraty 		    progname);
124406b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
1245956e45f6SSimon J. Gerraty 	}
1246956e45f6SSimon J. Gerraty 
1247956e45f6SSimon J. Gerraty 	if (n != opts.maxJobs) {
1248dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-j");
1249dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, value);
1250956e45f6SSimon J. Gerraty 	}
1251956e45f6SSimon J. Gerraty 
1252956e45f6SSimon J. Gerraty 	opts.maxJobs = n;
1253956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1254b0c40a00SSimon J. Gerraty 	forceJobs = true;
1255956e45f6SSimon J. Gerraty 	free(value);
1256956e45f6SSimon J. Gerraty }
1257956e45f6SSimon J. Gerraty 
1258956e45f6SSimon J. Gerraty /*
1259956e45f6SSimon J. Gerraty  * For compatibility, look at the directories in the VPATH variable
1260956e45f6SSimon J. Gerraty  * and add them to the search path, if the variable is defined. The
1261956e45f6SSimon J. Gerraty  * variable's value is in the same format as the PATH environment
1262956e45f6SSimon J. Gerraty  * variable, i.e. <directory>:<directory>:<directory>...
1263956e45f6SSimon J. Gerraty  */
1264956e45f6SSimon J. Gerraty static void
1265956e45f6SSimon J. Gerraty InitVpath(void)
1266956e45f6SSimon J. Gerraty {
1267956e45f6SSimon J. Gerraty 	char *vpath, savec, *path;
1268dba7b0efSSimon J. Gerraty 	if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
1269956e45f6SSimon J. Gerraty 		return;
1270956e45f6SSimon J. Gerraty 
1271*8d5c8e21SSimon J. Gerraty 	vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_EVAL);
1272956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1273956e45f6SSimon J. Gerraty 	path = vpath;
1274956e45f6SSimon J. Gerraty 	do {
1275d5e0a182SSimon J. Gerraty 		char *p;
1276956e45f6SSimon J. Gerraty 		/* skip to end of directory */
1277d5e0a182SSimon J. Gerraty 		for (p = path; *p != ':' && *p != '\0'; p++)
1278956e45f6SSimon J. Gerraty 			continue;
1279956e45f6SSimon J. Gerraty 		/* Save terminator character so know when to stop */
1280d5e0a182SSimon J. Gerraty 		savec = *p;
1281d5e0a182SSimon J. Gerraty 		*p = '\0';
1282956e45f6SSimon J. Gerraty 		/* Add directory to search path */
1283dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(&dirSearchPath, path);
1284d5e0a182SSimon J. Gerraty 		*p = savec;
1285d5e0a182SSimon J. Gerraty 		path = p + 1;
1286956e45f6SSimon J. Gerraty 	} while (savec == ':');
1287956e45f6SSimon J. Gerraty 	free(vpath);
1288956e45f6SSimon J. Gerraty }
1289956e45f6SSimon J. Gerraty 
1290956e45f6SSimon J. Gerraty static void
12919f45a3c8SSimon J. Gerraty ReadAllMakefiles(const StringList *makefiles)
1292956e45f6SSimon J. Gerraty {
1293956e45f6SSimon J. Gerraty 	StringListNode *ln;
1294956e45f6SSimon J. Gerraty 
1295e2eeea75SSimon J. Gerraty 	for (ln = makefiles->first; ln != NULL; ln = ln->next) {
1296e2eeea75SSimon J. Gerraty 		const char *fname = ln->datum;
12979f45a3c8SSimon J. Gerraty 		if (!ReadMakefile(fname))
1298e2eeea75SSimon J. Gerraty 			Fatal("%s: cannot open %s.", progname, fname);
1299956e45f6SSimon J. Gerraty 	}
1300956e45f6SSimon J. Gerraty }
1301956e45f6SSimon J. Gerraty 
1302956e45f6SSimon J. Gerraty static void
1303e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void)
1304956e45f6SSimon J. Gerraty {
13059f45a3c8SSimon J. Gerraty 	StringList makefiles = LST_INIT;
1306e2eeea75SSimon J. Gerraty 	StringListNode *ln;
13078c973ee2SSimon J. Gerraty 	char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
1308*8d5c8e21SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_EVAL);
1309e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
1310956e45f6SSimon J. Gerraty 
1311d5e0a182SSimon J. Gerraty 	AppendWords(&makefiles, prefs);
1312956e45f6SSimon J. Gerraty 
13139f45a3c8SSimon J. Gerraty 	for (ln = makefiles.first; ln != NULL; ln = ln->next)
13149f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1315e2eeea75SSimon J. Gerraty 			break;
1316956e45f6SSimon J. Gerraty 
13179f45a3c8SSimon J. Gerraty 	Lst_Done(&makefiles);
1318e2eeea75SSimon J. Gerraty 	free(prefs);
1319956e45f6SSimon J. Gerraty }
1320956e45f6SSimon J. Gerraty 
132106b9b3e0SSimon J. Gerraty /*
132206b9b3e0SSimon J. Gerraty  * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
1323e2eeea75SSimon J. Gerraty  * Initialize a few modules.
132406b9b3e0SSimon J. Gerraty  * Parse the arguments from MAKEFLAGS and the command line.
132506b9b3e0SSimon J. Gerraty  */
1326e2eeea75SSimon J. Gerraty static void
1327e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv)
13283955d011SMarcel Moolenaar {
1329956e45f6SSimon J. Gerraty 	struct stat sa;
1330956e45f6SSimon J. Gerraty 	const char *machine;
1331956e45f6SSimon J. Gerraty 	const char *machine_arch;
13323955d011SMarcel Moolenaar 	char *syspath = getenv("MAKESYSPATH");
13333955d011SMarcel Moolenaar 	struct utsname utsname;
13343955d011SMarcel Moolenaar 
13353955d011SMarcel Moolenaar 	/* default to writing debug to stderr */
1336956e45f6SSimon J. Gerraty 	opts.debug_file = stderr;
13373955d011SMarcel Moolenaar 
13389f45a3c8SSimon J. Gerraty 	Str_Intern_Init();
1339e2eeea75SSimon J. Gerraty 	HashTable_Init(&cached_realpaths);
1340e2eeea75SSimon J. Gerraty 
13413955d011SMarcel Moolenaar #ifdef SIGINFO
13423955d011SMarcel Moolenaar 	(void)bmake_signal(SIGINFO, siginfo);
13433955d011SMarcel Moolenaar #endif
1344956e45f6SSimon J. Gerraty 
1345956e45f6SSimon J. Gerraty 	InitRandom();
13463955d011SMarcel Moolenaar 
134706b9b3e0SSimon J. Gerraty 	progname = str_basename(argv[0]);
1348956e45f6SSimon J. Gerraty 
1349956e45f6SSimon J. Gerraty 	UnlimitFiles();
13503955d011SMarcel Moolenaar 
13511748de26SSimon J. Gerraty 	if (uname(&utsname) == -1) {
13521748de26SSimon J. Gerraty 		(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
13531748de26SSimon J. Gerraty 		    strerror(errno));
13541748de26SSimon J. Gerraty 		exit(2);
13551748de26SSimon J. Gerraty 	}
13561748de26SSimon J. Gerraty 
1357e2eeea75SSimon J. Gerraty 	machine = InitVarMachine(&utsname);
1358e2eeea75SSimon J. Gerraty 	machine_arch = InitVarMachineArch();
13593955d011SMarcel Moolenaar 
13603955d011SMarcel Moolenaar 	myPid = getpid();	/* remember this for vFork() */
13613955d011SMarcel Moolenaar 
1362d5e0a182SSimon J. Gerraty 	/* Just in case MAKEOBJDIR wants us to do something tricky. */
1363e2eeea75SSimon J. Gerraty 	Targ_Init();
1364e2eeea75SSimon J. Gerraty 	Var_Init();
1365548bfc56SSimon J. Gerraty #ifdef FORCE_MAKE_OS
1366548bfc56SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.OS", FORCE_MAKE_OS);
1367548bfc56SSimon J. Gerraty #else
13684fde40d9SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.OS", utsname.sysname);
1369548bfc56SSimon J. Gerraty #endif
1370dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE", machine);
1371dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE_ARCH", machine_arch);
13723955d011SMarcel Moolenaar #ifdef MAKE_VERSION
1373dba7b0efSSimon J. Gerraty 	Global_Set("MAKE_VERSION", MAKE_VERSION);
13743955d011SMarcel Moolenaar #endif
1375d5e0a182SSimon J. Gerraty 	Global_Set_ReadOnly(".newline", "\n");
13763955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST
13779f45a3c8SSimon J. Gerraty 	/* This is the traditional preference for makefiles. */
13783955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
13793955d011SMarcel Moolenaar #endif
13808c973ee2SSimon J. Gerraty 	Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST);
13814fde40d9SSimon J. Gerraty 	Global_Set(".MAKE.DEPENDFILE", ".depend");
138298875883SSimon J. Gerraty 	/* Tell makefiles like jobs.mk whether we support -jC */
138398875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
138498875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "yes");
138598875883SSimon J. Gerraty #else
138698875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "no");
138798875883SSimon J. Gerraty #endif
13883955d011SMarcel Moolenaar 
1389956e45f6SSimon J. Gerraty 	CmdOpts_Init();
1390b0c40a00SSimon J. Gerraty 	allPrecious = false;	/* Remove targets when interrupted */
1391b0c40a00SSimon J. Gerraty 	deleteOnError = false;	/* Historical default behavior */
1392b0c40a00SSimon J. Gerraty 	jobsRunning = false;
13933955d011SMarcel Moolenaar 
1394956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1395b0c40a00SSimon J. Gerraty 	ignorePWD = false;
13963955d011SMarcel Moolenaar 
13973955d011SMarcel Moolenaar 	/*
13983955d011SMarcel Moolenaar 	 * Initialize the parsing, directory and variable modules to prepare
13993955d011SMarcel Moolenaar 	 * for the reading of inclusion paths and variable settings on the
14003955d011SMarcel Moolenaar 	 * command line
14013955d011SMarcel Moolenaar 	 */
14023955d011SMarcel Moolenaar 
14033955d011SMarcel Moolenaar 	/*
14043955d011SMarcel Moolenaar 	 * Initialize various variables.
14053955d011SMarcel Moolenaar 	 *	MAKE also gets this name, for compatibility
14063955d011SMarcel Moolenaar 	 *	.MAKEFLAGS gets set to the empty string just in case.
14073955d011SMarcel Moolenaar 	 *	MFLAGS also gets initialized empty, for compatibility.
14083955d011SMarcel Moolenaar 	 */
14093955d011SMarcel Moolenaar 	Parse_Init();
1410956e45f6SSimon J. Gerraty 	InitVarMake(argv[0]);
1411dba7b0efSSimon J. Gerraty 	Global_Set(MAKEFLAGS, "");
14128c973ee2SSimon J. Gerraty 	Global_Set(".MAKEOVERRIDES", "");
1413dba7b0efSSimon J. Gerraty 	Global_Set("MFLAGS", "");
1414dba7b0efSSimon J. Gerraty 	Global_Set(".ALLTARGETS", "");
1415c9f4001fSSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV);
14163955d011SMarcel Moolenaar 
1417e2eeea75SSimon J. Gerraty 	/* Set some other useful variables. */
14183955d011SMarcel Moolenaar 	{
14199f45a3c8SSimon J. Gerraty 		char buf[64], *ep = getenv(MAKE_LEVEL_ENV);
14203955d011SMarcel Moolenaar 
1421e2eeea75SSimon J. Gerraty 		makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
142251ee2c1cSSimon J. Gerraty 		if (makelevel < 0)
142351ee2c1cSSimon J. Gerraty 			makelevel = 0;
14249f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%d", makelevel);
14258c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.LEVEL", buf);
14269f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", myPid);
14274fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PID", buf);
14289f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getppid());
14294fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PPID", buf);
14309f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getuid());
14314fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.UID", buf);
14329f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getgid());
14334fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.GID", buf);
14343955d011SMarcel Moolenaar 	}
143551ee2c1cSSimon J. Gerraty 	if (makelevel > 0) {
143651ee2c1cSSimon J. Gerraty 		char pn[1024];
1437e2eeea75SSimon J. Gerraty 		snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
143851ee2c1cSSimon J. Gerraty 		progname = bmake_strdup(pn);
143951ee2c1cSSimon J. Gerraty 	}
14403955d011SMarcel Moolenaar 
14411748de26SSimon J. Gerraty #ifdef USE_META
14421748de26SSimon J. Gerraty 	meta_init();
14431748de26SSimon J. Gerraty #endif
14442c3632d1SSimon J. Gerraty 	Dir_Init();
14451ce939a7SSimon J. Gerraty 
14469f45a3c8SSimon J. Gerraty 	{
14479f45a3c8SSimon J. Gerraty 		char *makeflags = explode(getenv("MAKEFLAGS"));
14489f45a3c8SSimon J. Gerraty 		Main_ParseArgLine(makeflags);
14499f45a3c8SSimon J. Gerraty 		free(makeflags);
14509f45a3c8SSimon J. Gerraty 	}
14513955d011SMarcel Moolenaar 
14523955d011SMarcel Moolenaar 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
14533955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: getcwd: %s.\n",
14543955d011SMarcel Moolenaar 		    progname, strerror(errno));
14553955d011SMarcel Moolenaar 		exit(2);
14563955d011SMarcel Moolenaar 	}
14573955d011SMarcel Moolenaar 
14583955d011SMarcel Moolenaar 	MainParseArgs(argc, argv);
14593955d011SMarcel Moolenaar 
1460956e45f6SSimon J. Gerraty 	if (opts.enterFlag)
146151ee2c1cSSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, curdir);
146251ee2c1cSSimon J. Gerraty 
14633955d011SMarcel Moolenaar 	if (stat(curdir, &sa) == -1) {
14643955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: %s: %s.\n",
14653955d011SMarcel Moolenaar 		    progname, curdir, strerror(errno));
14663955d011SMarcel Moolenaar 		exit(2);
14673955d011SMarcel Moolenaar 	}
14683955d011SMarcel Moolenaar 
14693955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE
1470956e45f6SSimon J. Gerraty 	HandlePWD(&sa);
14713955d011SMarcel Moolenaar #endif
1472dba7b0efSSimon J. Gerraty 	Global_Set(".CURDIR", curdir);
14733955d011SMarcel Moolenaar 
1474956e45f6SSimon J. Gerraty 	InitObjdir(machine, machine_arch);
14753955d011SMarcel Moolenaar 
14763955d011SMarcel Moolenaar 	Arch_Init();
14773955d011SMarcel Moolenaar 	Suff_Init();
14783955d011SMarcel Moolenaar 	Trace_Init(tracefile);
14793955d011SMarcel Moolenaar 
1480e2eeea75SSimon J. Gerraty 	defaultNode = NULL;
14813955d011SMarcel Moolenaar 	(void)time(&now);
14823955d011SMarcel Moolenaar 
14833955d011SMarcel Moolenaar 	Trace_Log(MAKESTART, NULL);
14843955d011SMarcel Moolenaar 
1485956e45f6SSimon J. Gerraty 	InitVarTargets();
14863955d011SMarcel Moolenaar 
1487956e45f6SSimon J. Gerraty 	InitDefSysIncPath(syspath);
1488e2eeea75SSimon J. Gerraty }
14893955d011SMarcel Moolenaar 
149006b9b3e0SSimon J. Gerraty /*
149106b9b3e0SSimon J. Gerraty  * Read the system makefile followed by either makefile, Makefile or the
149206b9b3e0SSimon J. Gerraty  * files given by the -f option. Exit on parse errors.
149306b9b3e0SSimon J. Gerraty  */
1494e2eeea75SSimon J. Gerraty static void
1495e2eeea75SSimon J. Gerraty main_ReadFiles(void)
1496e2eeea75SSimon J. Gerraty {
1497e2eeea75SSimon J. Gerraty 
14984fde40d9SSimon J. Gerraty 	if (Lst_IsEmpty(&sysIncPath->dirs))
14994fde40d9SSimon J. Gerraty 		SearchPath_AddAll(sysIncPath, defSysIncPath);
15004fde40d9SSimon J. Gerraty 
15014fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
1502956e45f6SSimon J. Gerraty 	if (!opts.noBuiltins)
1503956e45f6SSimon J. Gerraty 		ReadBuiltinRules();
15043955d011SMarcel Moolenaar 
15052f2a5ecdSSimon J. Gerraty 	posix_state = PS_MAYBE_NEXT_LINE;
150606b9b3e0SSimon J. Gerraty 	if (!Lst_IsEmpty(&opts.makefiles))
150706b9b3e0SSimon J. Gerraty 		ReadAllMakefiles(&opts.makefiles);
1508e2eeea75SSimon J. Gerraty 	else
1509e2eeea75SSimon J. Gerraty 		ReadFirstDefaultMakefile();
1510e2eeea75SSimon J. Gerraty }
1511e2eeea75SSimon J. Gerraty 
1512e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */
1513e2eeea75SSimon J. Gerraty static void
1514e2eeea75SSimon J. Gerraty main_PrepareMaking(void)
1515e2eeea75SSimon J. Gerraty {
15163955d011SMarcel Moolenaar 	/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1517e2eeea75SSimon J. Gerraty 	if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
15188c973ee2SSimon J. Gerraty 		makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
1519*8d5c8e21SSimon J. Gerraty 		    SCOPE_CMDLINE, VARE_EVAL);
1520956e45f6SSimon J. Gerraty 		if (makeDependfile[0] != '\0') {
1521956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
1522b0c40a00SSimon J. Gerraty 			doing_depend = true;
15232c3632d1SSimon J. Gerraty 			(void)ReadMakefile(makeDependfile);
1524b0c40a00SSimon J. Gerraty 			doing_depend = false;
15253955d011SMarcel Moolenaar 		}
1526956e45f6SSimon J. Gerraty 	}
15273955d011SMarcel Moolenaar 
15284c620fe5SSimon J. Gerraty 	if (enterFlagObj)
15294c620fe5SSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, objdir);
15304c620fe5SSimon J. Gerraty 
153106b9b3e0SSimon J. Gerraty 	MakeMode();
15323955d011SMarcel Moolenaar 
1533956e45f6SSimon J. Gerraty 	{
1534dba7b0efSSimon J. Gerraty 		FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS);
1535dba7b0efSSimon J. Gerraty 		Global_Append("MFLAGS", makeflags.str);
153606b9b3e0SSimon J. Gerraty 		FStr_Done(&makeflags);
1537956e45f6SSimon J. Gerraty 	}
1538e48f47ddSSimon J. Gerraty 
1539956e45f6SSimon J. Gerraty 	InitMaxJobs();
1540e48f47ddSSimon J. Gerraty 
1541e2eeea75SSimon J. Gerraty 	if (!opts.compatMake && !forceJobs)
1542b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
1543e48f47ddSSimon J. Gerraty 
1544956e45f6SSimon J. Gerraty 	if (!opts.compatMake)
15453955d011SMarcel Moolenaar 		Job_ServerStart(maxJobTokens, jp_0, jp_1);
1546956e45f6SSimon J. Gerraty 	DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1547956e45f6SSimon J. Gerraty 	    jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
15483955d011SMarcel Moolenaar 
1549e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_NONE)
1550b0c40a00SSimon J. Gerraty 		Main_ExportMAKEFLAGS(true);	/* initial export */
15513955d011SMarcel Moolenaar 
1552956e45f6SSimon J. Gerraty 	InitVpath();
15533955d011SMarcel Moolenaar 
15543955d011SMarcel Moolenaar 	/*
15553955d011SMarcel Moolenaar 	 * Now that all search paths have been read for suffixes et al, it's
15563955d011SMarcel Moolenaar 	 * time to add the default search path to their lists...
15573955d011SMarcel Moolenaar 	 */
1558b0c40a00SSimon J. Gerraty 	Suff_ExtendPaths();
15593955d011SMarcel Moolenaar 
15603955d011SMarcel Moolenaar 	/*
15613955d011SMarcel Moolenaar 	 * Propagate attributes through :: dependency lists.
15623955d011SMarcel Moolenaar 	 */
15633955d011SMarcel Moolenaar 	Targ_Propagate();
15643955d011SMarcel Moolenaar 
15653955d011SMarcel Moolenaar 	/* print the initial graph, if the user requested it */
15663955d011SMarcel Moolenaar 	if (DEBUG(GRAPH1))
15673955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
15683955d011SMarcel Moolenaar }
15693955d011SMarcel Moolenaar 
157006b9b3e0SSimon J. Gerraty /*
157106b9b3e0SSimon J. Gerraty  * Make the targets.
1572e2eeea75SSimon J. Gerraty  * If the -v or -V options are given, print variables instead.
157306b9b3e0SSimon J. Gerraty  * Return whether any of the targets is out-of-date.
157406b9b3e0SSimon J. Gerraty  */
1575b0c40a00SSimon J. Gerraty static bool
1576e2eeea75SSimon J. Gerraty main_Run(void)
1577e2eeea75SSimon J. Gerraty {
1578e2eeea75SSimon J. Gerraty 	if (opts.printVars != PVM_NONE) {
1579e2eeea75SSimon J. Gerraty 		/* print the values of any variables requested by the user */
1580e2eeea75SSimon J. Gerraty 		doPrintVars();
1581b0c40a00SSimon J. Gerraty 		return false;
1582e2eeea75SSimon J. Gerraty 	} else {
1583e2eeea75SSimon J. Gerraty 		return runTargets();
1584e2eeea75SSimon J. Gerraty 	}
1585e2eeea75SSimon J. Gerraty }
15863955d011SMarcel Moolenaar 
1587e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */
1588e2eeea75SSimon J. Gerraty static void
1589e2eeea75SSimon J. Gerraty main_CleanUp(void)
1590e2eeea75SSimon J. Gerraty {
1591e2eeea75SSimon J. Gerraty #ifdef CLEANUP
1592548bfc56SSimon J. Gerraty 	Lst_DoneFree(&opts.variables);
1593548bfc56SSimon J. Gerraty 	Lst_DoneFree(&opts.makefiles);
1594548bfc56SSimon J. Gerraty 	Lst_DoneFree(&opts.create);
1595e2eeea75SSimon J. Gerraty #endif
1596e2eeea75SSimon J. Gerraty 
1597e2eeea75SSimon J. Gerraty 	if (DEBUG(GRAPH2))
1598e2eeea75SSimon J. Gerraty 		Targ_PrintGraph(2);
1599e2eeea75SSimon J. Gerraty 
1600e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEEND, NULL);
1601e2eeea75SSimon J. Gerraty 
1602e2eeea75SSimon J. Gerraty 	if (enterFlagObj)
1603e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, objdir);
1604e2eeea75SSimon J. Gerraty 	if (opts.enterFlag)
1605e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, curdir);
1606e2eeea75SSimon J. Gerraty 
1607e2eeea75SSimon J. Gerraty #ifdef USE_META
1608e2eeea75SSimon J. Gerraty 	meta_finish();
1609e2eeea75SSimon J. Gerraty #endif
1610e2eeea75SSimon J. Gerraty 	Suff_End();
1611*8d5c8e21SSimon J. Gerraty 	Var_End();
1612e2eeea75SSimon J. Gerraty 	Targ_End();
1613e2eeea75SSimon J. Gerraty 	Arch_End();
1614e2eeea75SSimon J. Gerraty 	Parse_End();
1615e2eeea75SSimon J. Gerraty 	Dir_End();
1616e2eeea75SSimon J. Gerraty 	Job_End();
1617e2eeea75SSimon J. Gerraty 	Trace_End();
16189f45a3c8SSimon J. Gerraty 	Str_Intern_End();
1619e2eeea75SSimon J. Gerraty }
1620e2eeea75SSimon J. Gerraty 
1621e2eeea75SSimon J. Gerraty /* Determine the exit code. */
1622e2eeea75SSimon J. Gerraty static int
1623b0c40a00SSimon J. Gerraty main_Exit(bool outOfDate)
1624e2eeea75SSimon J. Gerraty {
162512904384SSimon J. Gerraty 	if (opts.strict && (main_errors > 0 || Parse_NumErrors() > 0))
1626956e45f6SSimon J. Gerraty 		return 2;	/* Not 1 so -q can distinguish error */
16273955d011SMarcel Moolenaar 	return outOfDate ? 1 : 0;
16283955d011SMarcel Moolenaar }
16293955d011SMarcel Moolenaar 
1630e2eeea75SSimon J. Gerraty int
1631e2eeea75SSimon J. Gerraty main(int argc, char **argv)
1632e2eeea75SSimon J. Gerraty {
1633b0c40a00SSimon J. Gerraty 	bool outOfDate;
1634e2eeea75SSimon J. Gerraty 
1635e2eeea75SSimon J. Gerraty 	main_Init(argc, argv);
1636e2eeea75SSimon J. Gerraty 	main_ReadFiles();
1637e2eeea75SSimon J. Gerraty 	main_PrepareMaking();
1638e2eeea75SSimon J. Gerraty 	outOfDate = main_Run();
1639e2eeea75SSimon J. Gerraty 	main_CleanUp();
1640e2eeea75SSimon J. Gerraty 	return main_Exit(outOfDate);
1641e2eeea75SSimon J. Gerraty }
1642e2eeea75SSimon J. Gerraty 
164306b9b3e0SSimon J. Gerraty /*
164406b9b3e0SSimon J. Gerraty  * Open and parse the given makefile, with all its side effects.
16459f45a3c8SSimon J. Gerraty  * Return false if the file could not be opened.
16463955d011SMarcel Moolenaar  */
16479f45a3c8SSimon J. Gerraty static bool
16482c3632d1SSimon J. Gerraty ReadMakefile(const char *fname)
16493955d011SMarcel Moolenaar {
16503955d011SMarcel Moolenaar 	int fd;
16512c3632d1SSimon J. Gerraty 	char *name, *path = NULL;
16523955d011SMarcel Moolenaar 
1653e2eeea75SSimon J. Gerraty 	if (strcmp(fname, "-") == 0) {
16549f45a3c8SSimon J. Gerraty 		Parse_File("(stdin)", -1);
1655dba7b0efSSimon J. Gerraty 		Var_Set(SCOPE_INTERNAL, "MAKEFILE", "");
16563955d011SMarcel Moolenaar 	} else {
16573955d011SMarcel Moolenaar 		/* if we've chdir'd, rebuild the path name */
1658e2eeea75SSimon J. Gerraty 		if (strcmp(curdir, objdir) != 0 && *fname != '/') {
16592c3632d1SSimon J. Gerraty 			path = str_concat3(curdir, "/", fname);
16603955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16613955d011SMarcel Moolenaar 			if (fd != -1) {
16623955d011SMarcel Moolenaar 				fname = path;
16633955d011SMarcel Moolenaar 				goto found;
16643955d011SMarcel Moolenaar 			}
16652c3632d1SSimon J. Gerraty 			free(path);
16663955d011SMarcel Moolenaar 
16673955d011SMarcel Moolenaar 			/* If curdir failed, try objdir (ala .depend) */
16682c3632d1SSimon J. Gerraty 			path = str_concat3(objdir, "/", fname);
16693955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16703955d011SMarcel Moolenaar 			if (fd != -1) {
16713955d011SMarcel Moolenaar 				fname = path;
16723955d011SMarcel Moolenaar 				goto found;
16733955d011SMarcel Moolenaar 			}
16743955d011SMarcel Moolenaar 		} else {
16753955d011SMarcel Moolenaar 			fd = open(fname, O_RDONLY);
16763955d011SMarcel Moolenaar 			if (fd != -1)
16773955d011SMarcel Moolenaar 				goto found;
16783955d011SMarcel Moolenaar 		}
16793955d011SMarcel Moolenaar 		/* look in -I and system include directories. */
16803955d011SMarcel Moolenaar 		name = Dir_FindFile(fname, parseIncPath);
1681e2eeea75SSimon J. Gerraty 		if (name == NULL) {
1682dba7b0efSSimon J. Gerraty 			SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs)
1683956e45f6SSimon J. Gerraty 			    ? defSysIncPath : sysIncPath;
1684956e45f6SSimon J. Gerraty 			name = Dir_FindFile(fname, sysInc);
1685956e45f6SSimon J. Gerraty 		}
1686e2eeea75SSimon J. Gerraty 		if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
16873955d011SMarcel Moolenaar 			free(name);
16883955d011SMarcel Moolenaar 			free(path);
16899f45a3c8SSimon J. Gerraty 			return false;
16903955d011SMarcel Moolenaar 		}
16913955d011SMarcel Moolenaar 		fname = name;
16923955d011SMarcel Moolenaar 		/*
16933955d011SMarcel Moolenaar 		 * set the MAKEFILE variable desired by System V fans -- the
16943955d011SMarcel Moolenaar 		 * placement of the setting here means it gets set to the last
16953955d011SMarcel Moolenaar 		 * makefile specified, as it is set by SysV make.
16963955d011SMarcel Moolenaar 		 */
16973955d011SMarcel Moolenaar found:
16983955d011SMarcel Moolenaar 		if (!doing_depend)
1699dba7b0efSSimon J. Gerraty 			Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname);
17003955d011SMarcel Moolenaar 		Parse_File(fname, fd);
17013955d011SMarcel Moolenaar 	}
17023955d011SMarcel Moolenaar 	free(path);
17039f45a3c8SSimon J. Gerraty 	return true;
17043955d011SMarcel Moolenaar }
17053955d011SMarcel Moolenaar 
1706dba7b0efSSimon J. Gerraty /*
17079f45a3c8SSimon J. Gerraty  * Execute the command in cmd, and return its output (only stdout, not
17089f45a3c8SSimon J. Gerraty  * stderr, possibly empty).  In the output, replace newlines with spaces.
17093955d011SMarcel Moolenaar  */
17103955d011SMarcel Moolenaar char *
17119f45a3c8SSimon J. Gerraty Cmd_Exec(const char *cmd, char **error)
17123955d011SMarcel Moolenaar {
17139f45a3c8SSimon J. Gerraty 	const char *args[4];	/* Arguments for invoking the shell */
171406b9b3e0SSimon J. Gerraty 	int pipefds[2];
17153955d011SMarcel Moolenaar 	int cpid;		/* Child PID */
17163955d011SMarcel Moolenaar 	int pid;		/* PID from wait() */
1717e2eeea75SSimon J. Gerraty 	int status;		/* command exit status */
17183955d011SMarcel Moolenaar 	Buffer buf;		/* buffer to store the result */
17192c3632d1SSimon J. Gerraty 	ssize_t bytes_read;
17209f45a3c8SSimon J. Gerraty 	char *output;
1721d5e0a182SSimon J. Gerraty 	char *p;
17229f45a3c8SSimon J. Gerraty 	int saved_errno;
1723d5e0a182SSimon J. Gerraty 	char cmd_file[MAXPATHLEN];
1724d5e0a182SSimon J. Gerraty 	size_t cmd_len;
1725d5e0a182SSimon J. Gerraty 	int cmd_fd = -1;
17263955d011SMarcel Moolenaar 
1727d5e0a182SSimon J. Gerraty 	if (shellPath == NULL)
17283955d011SMarcel Moolenaar 		Shell_Init();
17299f45a3c8SSimon J. Gerraty 
1730d5e0a182SSimon J. Gerraty 	cmd_len = strlen(cmd);
1731d5e0a182SSimon J. Gerraty 	if (cmd_len > 1000) {
1732d5e0a182SSimon J. Gerraty 		cmd_fd = mkTempFile(NULL, cmd_file, sizeof(cmd_file));
1733d5e0a182SSimon J. Gerraty 		if (cmd_fd >= 0) {
1734d5e0a182SSimon J. Gerraty 			ssize_t n;
1735d5e0a182SSimon J. Gerraty 
1736d5e0a182SSimon J. Gerraty 			n = write(cmd_fd, cmd, cmd_len);
1737d5e0a182SSimon J. Gerraty 			close(cmd_fd);
1738d5e0a182SSimon J. Gerraty 			if (n < (ssize_t)cmd_len) {
1739d5e0a182SSimon J. Gerraty 				unlink(cmd_file);
1740d5e0a182SSimon J. Gerraty 				cmd_fd = -1;
1741d5e0a182SSimon J. Gerraty 			}
1742d5e0a182SSimon J. Gerraty 		}
1743d5e0a182SSimon J. Gerraty 	}
1744d5e0a182SSimon J. Gerraty 
17453955d011SMarcel Moolenaar 	args[0] = shellName;
1746d5e0a182SSimon J. Gerraty 	if (cmd_fd >= 0) {
1747d5e0a182SSimon J. Gerraty 		args[1] = cmd_file;
1748d5e0a182SSimon J. Gerraty 		args[2] = NULL;
1749d5e0a182SSimon J. Gerraty 	} else {
1750d5e0a182SSimon J. Gerraty 		cmd_file[0] = '\0';
17513955d011SMarcel Moolenaar 		args[1] = "-c";
17523955d011SMarcel Moolenaar 		args[2] = cmd;
17533955d011SMarcel Moolenaar 		args[3] = NULL;
1754d5e0a182SSimon J. Gerraty 	}
17559f45a3c8SSimon J. Gerraty 	DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
17563955d011SMarcel Moolenaar 
175706b9b3e0SSimon J. Gerraty 	if (pipe(pipefds) == -1) {
17589f45a3c8SSimon J. Gerraty 		*error = str_concat3(
17599f45a3c8SSimon J. Gerraty 		    "Couldn't create pipe for \"", cmd, "\"");
17609f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17613955d011SMarcel Moolenaar 	}
17623955d011SMarcel Moolenaar 
1763c59c3bf3SSimon J. Gerraty 	Var_ReexportVars(SCOPE_GLOBAL);
176406b9b3e0SSimon J. Gerraty 
1765dba7b0efSSimon J. Gerraty 	switch (cpid = vfork()) {
17663955d011SMarcel Moolenaar 	case 0:
17679f45a3c8SSimon J. Gerraty 		(void)close(pipefds[0]);
17689f45a3c8SSimon J. Gerraty 		(void)dup2(pipefds[1], STDOUT_FILENO);
176906b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]);
17703955d011SMarcel Moolenaar 
17713955d011SMarcel Moolenaar 		(void)execv(shellPath, UNCONST(args));
17723955d011SMarcel Moolenaar 		_exit(1);
17733955d011SMarcel Moolenaar 		/* NOTREACHED */
17743955d011SMarcel Moolenaar 
17753955d011SMarcel Moolenaar 	case -1:
17769f45a3c8SSimon J. Gerraty 		*error = str_concat3("Couldn't exec \"", cmd, "\"");
17779f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17789f45a3c8SSimon J. Gerraty 	}
17793955d011SMarcel Moolenaar 
178006b9b3e0SSimon J. Gerraty 	(void)close(pipefds[1]);	/* No need for the writing half */
17813955d011SMarcel Moolenaar 
17829f45a3c8SSimon J. Gerraty 	saved_errno = 0;
1783e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
17843955d011SMarcel Moolenaar 
17853955d011SMarcel Moolenaar 	do {
17863955d011SMarcel Moolenaar 		char result[BUFSIZ];
178706b9b3e0SSimon J. Gerraty 		bytes_read = read(pipefds[0], result, sizeof result);
17882c3632d1SSimon J. Gerraty 		if (bytes_read > 0)
17892c3632d1SSimon J. Gerraty 			Buf_AddBytes(&buf, result, (size_t)bytes_read);
17909f45a3c8SSimon J. Gerraty 	} while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
17912c3632d1SSimon J. Gerraty 	if (bytes_read == -1)
17929f45a3c8SSimon J. Gerraty 		saved_errno = errno;
17933955d011SMarcel Moolenaar 
179406b9b3e0SSimon J. Gerraty 	(void)close(pipefds[0]); /* Close the input side of the pipe. */
17953955d011SMarcel Moolenaar 
1796e2eeea75SSimon J. Gerraty 	while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
1797b0c40a00SSimon J. Gerraty 		JobReapChild(pid, status, false);
1798e2eeea75SSimon J. Gerraty 
17999f45a3c8SSimon J. Gerraty 	if (Buf_EndsWith(&buf, '\n'))
18009f45a3c8SSimon J. Gerraty 		buf.data[buf.len - 1] = '\0';
18013955d011SMarcel Moolenaar 
18029f45a3c8SSimon J. Gerraty 	output = Buf_DoneData(&buf);
1803d5e0a182SSimon J. Gerraty 	for (p = output; *p != '\0'; p++)
1804d5e0a182SSimon J. Gerraty 		if (*p == '\n')
1805d5e0a182SSimon J. Gerraty 			*p = ' ';
18069f45a3c8SSimon J. Gerraty 
18079f45a3c8SSimon J. Gerraty 	if (WIFSIGNALED(status))
18089f45a3c8SSimon J. Gerraty 		*error = str_concat3("\"", cmd, "\" exited on a signal");
18099f45a3c8SSimon J. Gerraty 	else if (WEXITSTATUS(status) != 0)
18109f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18119f45a3c8SSimon J. Gerraty 		    "\"", cmd, "\" returned non-zero status");
18129f45a3c8SSimon J. Gerraty 	else if (saved_errno != 0)
18139f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18149f45a3c8SSimon J. Gerraty 		    "Couldn't read shell's output for \"", cmd, "\"");
18159f45a3c8SSimon J. Gerraty 	else
18169f45a3c8SSimon J. Gerraty 		*error = NULL;
1817d5e0a182SSimon J. Gerraty 	if (cmd_file[0] != '\0')
1818d5e0a182SSimon J. Gerraty 		unlink(cmd_file);
18199f45a3c8SSimon J. Gerraty 	return output;
18203955d011SMarcel Moolenaar }
18213955d011SMarcel Moolenaar 
182206b9b3e0SSimon J. Gerraty /*
182306b9b3e0SSimon J. Gerraty  * Print a printf-style error message.
18243955d011SMarcel Moolenaar  *
18259f45a3c8SSimon J. Gerraty  * In default mode, this error message has no consequences, for compatibility
18269f45a3c8SSimon J. Gerraty  * reasons, in particular it does not affect the exit status.  Only in lint
18279f45a3c8SSimon J. Gerraty  * mode (-dL) it does.
182806b9b3e0SSimon J. Gerraty  */
18293955d011SMarcel Moolenaar void
18303955d011SMarcel Moolenaar Error(const char *fmt, ...)
18313955d011SMarcel Moolenaar {
18323955d011SMarcel Moolenaar 	va_list ap;
18339f45a3c8SSimon J. Gerraty 	FILE *f;
18343955d011SMarcel Moolenaar 
18359f45a3c8SSimon J. Gerraty 	f = opts.debug_file;
18369f45a3c8SSimon J. Gerraty 	if (f == stdout)
18379f45a3c8SSimon J. Gerraty 		f = stderr;
18383955d011SMarcel Moolenaar 	(void)fflush(stdout);
18399f45a3c8SSimon J. Gerraty 
18403955d011SMarcel Moolenaar 	for (;;) {
18419f45a3c8SSimon J. Gerraty 		fprintf(f, "%s: ", progname);
18423955d011SMarcel Moolenaar 		va_start(ap, fmt);
18439f45a3c8SSimon J. Gerraty 		(void)vfprintf(f, fmt, ap);
18443955d011SMarcel Moolenaar 		va_end(ap);
18459f45a3c8SSimon J. Gerraty 		(void)fprintf(f, "\n");
18469f45a3c8SSimon J. Gerraty 		(void)fflush(f);
18479f45a3c8SSimon J. Gerraty 		if (f == stderr)
18483955d011SMarcel Moolenaar 			break;
18499f45a3c8SSimon J. Gerraty 		f = stderr;
18503955d011SMarcel Moolenaar 	}
185106b9b3e0SSimon J. Gerraty 	main_errors++;
18523955d011SMarcel Moolenaar }
18533955d011SMarcel Moolenaar 
185406b9b3e0SSimon J. Gerraty /*
185506b9b3e0SSimon J. Gerraty  * Wait for any running jobs to finish, then produce an error message,
1856e2eeea75SSimon J. Gerraty  * finally exit immediately.
18573955d011SMarcel Moolenaar  *
1858e2eeea75SSimon J. Gerraty  * Exiting immediately differs from Parse_Error, which exits only after the
185906b9b3e0SSimon J. Gerraty  * current top-level makefile has been parsed completely.
186006b9b3e0SSimon J. Gerraty  */
18613955d011SMarcel Moolenaar void
18623955d011SMarcel Moolenaar Fatal(const char *fmt, ...)
18633955d011SMarcel Moolenaar {
18643955d011SMarcel Moolenaar 	va_list ap;
18653955d011SMarcel Moolenaar 
18663955d011SMarcel Moolenaar 	if (jobsRunning)
18673955d011SMarcel Moolenaar 		Job_Wait();
18683955d011SMarcel Moolenaar 
18693955d011SMarcel Moolenaar 	(void)fflush(stdout);
1870d5e0a182SSimon J. Gerraty 	fprintf(stderr, "%s: ", progname);
1871e2eeea75SSimon J. Gerraty 	va_start(ap, fmt);
18723955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
18733955d011SMarcel Moolenaar 	va_end(ap);
18743955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
18753955d011SMarcel Moolenaar 	(void)fflush(stderr);
18769f45a3c8SSimon J. Gerraty 	PrintStackTrace(true);
18773955d011SMarcel Moolenaar 
18789f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
18793955d011SMarcel Moolenaar 
18803955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
18813955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1882e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
18833955d011SMarcel Moolenaar 	exit(2);		/* Not 1 so -q can distinguish error */
18843955d011SMarcel Moolenaar }
18853955d011SMarcel Moolenaar 
188606b9b3e0SSimon J. Gerraty /*
188706b9b3e0SSimon J. Gerraty  * Major exception once jobs are being created.
188806b9b3e0SSimon J. Gerraty  * Kills all jobs, prints a message and exits.
188906b9b3e0SSimon J. Gerraty  */
18903955d011SMarcel Moolenaar void
18913955d011SMarcel Moolenaar Punt(const char *fmt, ...)
18923955d011SMarcel Moolenaar {
18933955d011SMarcel Moolenaar 	va_list ap;
18943955d011SMarcel Moolenaar 
18953955d011SMarcel Moolenaar 	(void)fflush(stdout);
18963955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: ", progname);
18979f45a3c8SSimon J. Gerraty 	va_start(ap, fmt);
18983955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
18993955d011SMarcel Moolenaar 	va_end(ap);
19003955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19013955d011SMarcel Moolenaar 	(void)fflush(stderr);
19023955d011SMarcel Moolenaar 
19039f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
19043955d011SMarcel Moolenaar 
19053955d011SMarcel Moolenaar 	DieHorribly();
19063955d011SMarcel Moolenaar }
19073955d011SMarcel Moolenaar 
1908956e45f6SSimon J. Gerraty /* Exit without giving a message. */
19093955d011SMarcel Moolenaar void
19103955d011SMarcel Moolenaar DieHorribly(void)
19113955d011SMarcel Moolenaar {
19123955d011SMarcel Moolenaar 	if (jobsRunning)
19133955d011SMarcel Moolenaar 		Job_AbortAll();
19143955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2))
19153955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1916e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
191706b9b3e0SSimon J. Gerraty 	exit(2);		/* Not 1 so -q can distinguish error */
19183955d011SMarcel Moolenaar }
19193955d011SMarcel Moolenaar 
192006b9b3e0SSimon J. Gerraty /*
192106b9b3e0SSimon J. Gerraty  * Called when aborting due to errors in child shell to signal abnormal exit.
1922956e45f6SSimon J. Gerraty  * The program exits.
192306b9b3e0SSimon J. Gerraty  * Errors is the number of errors encountered in Make_Make.
192406b9b3e0SSimon J. Gerraty  */
19253955d011SMarcel Moolenaar void
1926956e45f6SSimon J. Gerraty Finish(int errs)
19273955d011SMarcel Moolenaar {
1928e2eeea75SSimon J. Gerraty 	if (shouldDieQuietly(NULL, -1))
19293841c287SSimon J. Gerraty 		exit(2);
1930956e45f6SSimon J. Gerraty 	Fatal("%d error%s", errs, errs == 1 ? "" : "s");
19313955d011SMarcel Moolenaar }
19323955d011SMarcel Moolenaar 
19334fde40d9SSimon J. Gerraty int
19349f45a3c8SSimon J. Gerraty unlink_file(const char *file)
19353955d011SMarcel Moolenaar {
19363955d011SMarcel Moolenaar 	struct stat st;
19373955d011SMarcel Moolenaar 
19383955d011SMarcel Moolenaar 	if (lstat(file, &st) == -1)
19394fde40d9SSimon J. Gerraty 		return -1;
19403955d011SMarcel Moolenaar 
19413955d011SMarcel Moolenaar 	if (S_ISDIR(st.st_mode)) {
19424fde40d9SSimon J. Gerraty 		/*
19434fde40d9SSimon J. Gerraty 		 * POSIX says for unlink: "The path argument shall not name
19444fde40d9SSimon J. Gerraty 		 * a directory unless [...]".
19454fde40d9SSimon J. Gerraty 		 */
19463955d011SMarcel Moolenaar 		errno = EISDIR;
19474fde40d9SSimon J. Gerraty 		return -1;
19483955d011SMarcel Moolenaar 	}
19494fde40d9SSimon J. Gerraty 	return unlink(file);
19503955d011SMarcel Moolenaar }
19513955d011SMarcel Moolenaar 
1952956e45f6SSimon J. Gerraty static void
1953956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n)
1954956e45f6SSimon J. Gerraty {
1955956e45f6SSimon J. Gerraty 	const char *mem = data;
1956956e45f6SSimon J. Gerraty 
1957956e45f6SSimon J. Gerraty 	while (n > 0) {
1958956e45f6SSimon J. Gerraty 		ssize_t written = write(fd, mem, n);
19599f45a3c8SSimon J. Gerraty 		/* XXX: Should this EAGAIN be EINTR? */
1960956e45f6SSimon J. Gerraty 		if (written == -1 && errno == EAGAIN)
1961956e45f6SSimon J. Gerraty 			continue;
1962956e45f6SSimon J. Gerraty 		if (written == -1)
1963956e45f6SSimon J. Gerraty 			break;
1964956e45f6SSimon J. Gerraty 		mem += written;
1965956e45f6SSimon J. Gerraty 		n -= (size_t)written;
1966956e45f6SSimon J. Gerraty 	}
1967956e45f6SSimon J. Gerraty }
1968956e45f6SSimon J. Gerraty 
19699f45a3c8SSimon J. Gerraty /* Print why exec failed, avoiding stdio. */
1970956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD
1971956e45f6SSimon J. Gerraty execDie(const char *af, const char *av)
19723955d011SMarcel Moolenaar {
1973956e45f6SSimon J. Gerraty 	Buffer buf;
19743955d011SMarcel Moolenaar 
1975e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
1976956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, progname);
1977956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ": ");
1978956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, af);
1979956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, "(");
1980956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, av);
1981956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ") failed (");
1982956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, strerror(errno));
1983956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ")\n");
19843955d011SMarcel Moolenaar 
1985dba7b0efSSimon J. Gerraty 	write_all(STDERR_FILENO, buf.data, buf.len);
1986956e45f6SSimon J. Gerraty 
1987dba7b0efSSimon J. Gerraty 	Buf_Done(&buf);
1988956e45f6SSimon J. Gerraty 	_exit(1);
19893955d011SMarcel Moolenaar }
19903955d011SMarcel Moolenaar 
1991e1cee40dSSimon J. Gerraty static void
1992e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void)
1993e1cee40dSSimon J. Gerraty {
1994956e45f6SSimon J. Gerraty 	HashIter hi;
1995*8d5c8e21SSimon J. Gerraty 	bool more;
1996b778b302SSimon J. Gerraty 
1997e2eeea75SSimon J. Gerraty 	HashIter_Init(&hi, &cached_realpaths);
1998*8d5c8e21SSimon J. Gerraty 	more = HashIter_Next(&hi);
1999*8d5c8e21SSimon J. Gerraty 	while (more) {
2000*8d5c8e21SSimon J. Gerraty 		HashEntry *he = hi.entry;
2001*8d5c8e21SSimon J. Gerraty 		more = HashIter_Next(&hi);
2002956e45f6SSimon J. Gerraty 		if (he->key[0] != '/') {
2003e2eeea75SSimon J. Gerraty 			DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
2004*8d5c8e21SSimon J. Gerraty 			free(he->value);
2005e2eeea75SSimon J. Gerraty 			HashTable_DeleteEntry(&cached_realpaths, he);
2006b46b9039SSimon J. Gerraty 		}
2007b46b9039SSimon J. Gerraty 	}
2008b46b9039SSimon J. Gerraty }
2009e1cee40dSSimon J. Gerraty 
20109f45a3c8SSimon J. Gerraty const char *
2011e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved)
2012e1cee40dSSimon J. Gerraty {
20132c3632d1SSimon J. Gerraty 	const char *rp;
2014e1cee40dSSimon J. Gerraty 
2015e2eeea75SSimon J. Gerraty 	if (pathname == NULL || pathname[0] == '\0')
2016e1cee40dSSimon J. Gerraty 		return NULL;
2017e1cee40dSSimon J. Gerraty 
2018e2eeea75SSimon J. Gerraty 	rp = HashTable_FindValue(&cached_realpaths, pathname);
2019e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2020*8d5c8e21SSimon J. Gerraty 		snprintf(resolved, MAXPATHLEN, "%s", rp);
2021e2eeea75SSimon J. Gerraty 		return resolved;
2022e2eeea75SSimon J. Gerraty 	}
20233841c287SSimon J. Gerraty 
2024e2eeea75SSimon J. Gerraty 	rp = realpath(pathname, resolved);
2025e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2026e2eeea75SSimon J. Gerraty 		HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
2027e2eeea75SSimon J. Gerraty 		DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
2028e2eeea75SSimon J. Gerraty 		return resolved;
2029e2eeea75SSimon J. Gerraty 	}
2030e2eeea75SSimon J. Gerraty 
2031e2eeea75SSimon J. Gerraty 	/* should we negative-cache? */
2032e2eeea75SSimon J. Gerraty 	return NULL;
2033b778b302SSimon J. Gerraty }
2034b778b302SSimon J. Gerraty 
20353841c287SSimon J. Gerraty /*
20363841c287SSimon J. Gerraty  * Return true if we should die without noise.
2037e2eeea75SSimon J. Gerraty  * For example our failing child was a sub-make or failure happened elsewhere.
20383841c287SSimon J. Gerraty  */
2039b0c40a00SSimon J. Gerraty bool
2040e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf)
20413841c287SSimon J. Gerraty {
20423841c287SSimon J. Gerraty 	static int quietly = -1;
20433841c287SSimon J. Gerraty 
20443841c287SSimon J. Gerraty 	if (quietly < 0) {
2045b0c40a00SSimon J. Gerraty 		if (DEBUG(JOB) ||
2046b0c40a00SSimon J. Gerraty 		    !GetBooleanExpr("${.MAKE.DIE_QUIETLY}", true))
20473841c287SSimon J. Gerraty 			quietly = 0;
20483841c287SSimon J. Gerraty 		else if (bf >= 0)
20493841c287SSimon J. Gerraty 			quietly = bf;
20503841c287SSimon J. Gerraty 		else
205106b9b3e0SSimon J. Gerraty 			quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
20523841c287SSimon J. Gerraty 	}
2053dba7b0efSSimon J. Gerraty 	return quietly != 0;
20543841c287SSimon J. Gerraty }
20553841c287SSimon J. Gerraty 
2056956e45f6SSimon J. Gerraty static void
2057956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn)
2058956e45f6SSimon J. Gerraty {
2059956e45f6SSimon J. Gerraty 	StringListNode *ln;
2060c59c3bf3SSimon J. Gerraty 	char sts[16];
2061956e45f6SSimon J. Gerraty 
2062956e45f6SSimon J. Gerraty 	/*
2063956e45f6SSimon J. Gerraty 	 * We can print this even if there is no .ERROR target.
2064956e45f6SSimon J. Gerraty 	 */
2065c59c3bf3SSimon J. Gerraty 	snprintf(sts, sizeof(sts), "%d", gn->exit_status);
2066c59c3bf3SSimon J. Gerraty 	Global_Set(".ERROR_EXIT", sts);
2067dba7b0efSSimon J. Gerraty 	Global_Set(".ERROR_TARGET", gn->name);
2068dba7b0efSSimon J. Gerraty 	Global_Delete(".ERROR_CMD");
2069956e45f6SSimon J. Gerraty 
207006b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
2071956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
2072956e45f6SSimon J. Gerraty 
2073956e45f6SSimon J. Gerraty 		if (cmd == NULL)
2074956e45f6SSimon J. Gerraty 			break;
2075dba7b0efSSimon J. Gerraty 		Global_Append(".ERROR_CMD", cmd);
2076956e45f6SSimon J. Gerraty 	}
2077956e45f6SSimon J. Gerraty }
2078956e45f6SSimon J. Gerraty 
207906b9b3e0SSimon J. Gerraty /*
208006b9b3e0SSimon J. Gerraty  * Print some helpful information in case of an error.
208106b9b3e0SSimon J. Gerraty  * The caller should exit soon after calling this function.
208206b9b3e0SSimon J. Gerraty  */
20833955d011SMarcel Moolenaar void
2084e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg)
20853955d011SMarcel Moolenaar {
2086e2eeea75SSimon J. Gerraty 	static GNode *errorNode = NULL;
20873955d011SMarcel Moolenaar 
20882c3632d1SSimon J. Gerraty 	if (DEBUG(HASH)) {
20892c3632d1SSimon J. Gerraty 		Targ_Stats();
20902c3632d1SSimon J. Gerraty 		Var_Stats();
20912c3632d1SSimon J. Gerraty 	}
20922c3632d1SSimon J. Gerraty 
209306b9b3e0SSimon J. Gerraty 	if (errorNode != NULL)
209406b9b3e0SSimon J. Gerraty 		return;		/* we've been here! */
20953841c287SSimon J. Gerraty 
20969f45a3c8SSimon J. Gerraty 	printf("%s%s: stopped in %s\n", msg, progname, curdir);
20973955d011SMarcel Moolenaar 
209806b9b3e0SSimon J. Gerraty 	/* we generally want to keep quiet if a sub-make died */
209906b9b3e0SSimon J. Gerraty 	if (shouldDieQuietly(gn, -1))
210006b9b3e0SSimon J. Gerraty 		return;
2101e2eeea75SSimon J. Gerraty 
2102e2eeea75SSimon J. Gerraty 	if (gn != NULL)
2103956e45f6SSimon J. Gerraty 		SetErrorVars(gn);
2104e2eeea75SSimon J. Gerraty 
2105e2eeea75SSimon J. Gerraty 	{
21068c973ee2SSimon J. Gerraty 		char *errorVarsValues = Var_Subst(
21078c973ee2SSimon J. Gerraty 		    "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
2108*8d5c8e21SSimon J. Gerraty 		    SCOPE_GLOBAL, VARE_EVAL);
2109956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
2110e2eeea75SSimon J. Gerraty 		printf("%s", errorVarsValues);
2111e2eeea75SSimon J. Gerraty 		free(errorVarsValues);
2112e2eeea75SSimon J. Gerraty 	}
2113e2eeea75SSimon J. Gerraty 
2114ac3446e9SSimon J. Gerraty 	fflush(stdout);
2115ac3446e9SSimon J. Gerraty 
21163955d011SMarcel Moolenaar 	/*
21173955d011SMarcel Moolenaar 	 * Finally, see if there is a .ERROR target, and run it if so.
21183955d011SMarcel Moolenaar 	 */
2119e2eeea75SSimon J. Gerraty 	errorNode = Targ_FindNode(".ERROR");
2120e2eeea75SSimon J. Gerraty 	if (errorNode != NULL) {
2121e2eeea75SSimon J. Gerraty 		errorNode->type |= OP_SPECIAL;
2122e2eeea75SSimon J. Gerraty 		Compat_Make(errorNode, errorNode);
21233955d011SMarcel Moolenaar 	}
21243955d011SMarcel Moolenaar }
21253955d011SMarcel Moolenaar 
21263955d011SMarcel Moolenaar void
2127b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(bool first)
21283955d011SMarcel Moolenaar {
2129b0c40a00SSimon J. Gerraty 	static bool once = true;
21309f45a3c8SSimon J. Gerraty 	char *flags;
21313955d011SMarcel Moolenaar 
21323955d011SMarcel Moolenaar 	if (once != first)
21333955d011SMarcel Moolenaar 		return;
2134b0c40a00SSimon J. Gerraty 	once = false;
21353955d011SMarcel Moolenaar 
21368c973ee2SSimon J. Gerraty 	flags = Var_Subst(
21379f45a3c8SSimon J. Gerraty 	    "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
2138*8d5c8e21SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_EVAL);
2139956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2140c59c3bf3SSimon J. Gerraty 	if (flags[0] != '\0')
21419f45a3c8SSimon J. Gerraty 		setenv("MAKEFLAGS", flags, 1);
2142*8d5c8e21SSimon J. Gerraty 	free(flags);
21433955d011SMarcel Moolenaar }
21443955d011SMarcel Moolenaar 
21453955d011SMarcel Moolenaar char *
21463955d011SMarcel Moolenaar getTmpdir(void)
21473955d011SMarcel Moolenaar {
21483955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
21493955d011SMarcel Moolenaar 	struct stat st;
21503955d011SMarcel Moolenaar 
2151e2eeea75SSimon J. Gerraty 	if (tmpdir != NULL)
2152e2eeea75SSimon J. Gerraty 		return tmpdir;
2153e2eeea75SSimon J. Gerraty 
21549f45a3c8SSimon J. Gerraty 	/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
21558c973ee2SSimon J. Gerraty 	tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
2156*8d5c8e21SSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_EVAL);
2157956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2158e2eeea75SSimon J. Gerraty 
21593955d011SMarcel Moolenaar 	if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
21603955d011SMarcel Moolenaar 		free(tmpdir);
21613955d011SMarcel Moolenaar 		tmpdir = bmake_strdup(_PATH_TMP);
21623955d011SMarcel Moolenaar 	}
21633955d011SMarcel Moolenaar 	return tmpdir;
21643955d011SMarcel Moolenaar }
21653955d011SMarcel Moolenaar 
21663955d011SMarcel Moolenaar /*
21673955d011SMarcel Moolenaar  * Create and open a temp file using "pattern".
2168d5e0a182SSimon J. Gerraty  * If tfile is provided, set it to a copy of the filename created.
21693955d011SMarcel Moolenaar  * Otherwise unlink the file once open.
21703955d011SMarcel Moolenaar  */
21713955d011SMarcel Moolenaar int
2172dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz)
21733955d011SMarcel Moolenaar {
21743955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
2175dba7b0efSSimon J. Gerraty 	char tbuf[MAXPATHLEN];
21763955d011SMarcel Moolenaar 	int fd;
21773955d011SMarcel Moolenaar 
2178e2eeea75SSimon J. Gerraty 	if (pattern == NULL)
21793955d011SMarcel Moolenaar 		pattern = TMPPAT;
2180956e45f6SSimon J. Gerraty 	if (tmpdir == NULL)
21813955d011SMarcel Moolenaar 		tmpdir = getTmpdir();
2182dba7b0efSSimon J. Gerraty 	if (tfile == NULL) {
2183dba7b0efSSimon J. Gerraty 		tfile = tbuf;
2184dba7b0efSSimon J. Gerraty 		tfile_sz = sizeof tbuf;
2185dba7b0efSSimon J. Gerraty 	}
21869f45a3c8SSimon J. Gerraty 
21879f45a3c8SSimon J. Gerraty 	if (pattern[0] == '/')
2188dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s", pattern);
21899f45a3c8SSimon J. Gerraty 	else
2190dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern);
21919f45a3c8SSimon J. Gerraty 
21923955d011SMarcel Moolenaar 	if ((fd = mkstemp(tfile)) < 0)
2193e2eeea75SSimon J. Gerraty 		Punt("Could not create temporary file %s: %s", tfile,
2194e2eeea75SSimon J. Gerraty 		    strerror(errno));
21959f45a3c8SSimon J. Gerraty 	if (tfile == tbuf)
219606b9b3e0SSimon J. Gerraty 		unlink(tfile);	/* we just want the descriptor */
21979f45a3c8SSimon J. Gerraty 
21983955d011SMarcel Moolenaar 	return fd;
21993955d011SMarcel Moolenaar }
22003955d011SMarcel Moolenaar 
2201be19d90bSSimon J. Gerraty /*
2202e2eeea75SSimon J. Gerraty  * Convert a string representation of a boolean into a boolean value.
2203b0c40a00SSimon J. Gerraty  * Anything that looks like "No", "False", "Off", "0" etc. is false,
2204b0c40a00SSimon J. Gerraty  * the empty string is the fallback, everything else is true.
2205be19d90bSSimon J. Gerraty  */
2206b0c40a00SSimon J. Gerraty bool
2207b0c40a00SSimon J. Gerraty ParseBoolean(const char *s, bool fallback)
2208be19d90bSSimon J. Gerraty {
2209e2eeea75SSimon J. Gerraty 	char ch = ch_tolower(s[0]);
2210e2eeea75SSimon J. Gerraty 	if (ch == '\0')
2211e2eeea75SSimon J. Gerraty 		return fallback;
2212e2eeea75SSimon J. Gerraty 	if (ch == '0' || ch == 'f' || ch == 'n')
2213b0c40a00SSimon J. Gerraty 		return false;
2214e2eeea75SSimon J. Gerraty 	if (ch == 'o')
2215e2eeea75SSimon J. Gerraty 		return ch_tolower(s[1]) != 'f';
2216b0c40a00SSimon J. Gerraty 	return true;
2217be19d90bSSimon J. Gerraty }
2218