xref: /freebsd/contrib/bmake/main.c (revision d9a65c5de1c9f30ae71ce0be8fb88be9d20d216d)
1*d9a65c5dSSimon J. Gerraty /*	$NetBSD: main.c,v 1.639 2025/03/07 06:50:34 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  */
873955d011SMarcel Moolenaar 
883955d011SMarcel Moolenaar #include <sys/types.h>
893955d011SMarcel Moolenaar #include <sys/time.h>
903955d011SMarcel Moolenaar #include <sys/param.h>
913955d011SMarcel Moolenaar #include <sys/resource.h>
923955d011SMarcel Moolenaar #include <sys/stat.h>
930dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL)
940dede8b0SSimon J. Gerraty #include <sys/sysctl.h>
950dede8b0SSimon J. Gerraty #endif
963955d011SMarcel Moolenaar #include <sys/utsname.h>
973955d011SMarcel Moolenaar #include "wait.h"
983955d011SMarcel Moolenaar 
993955d011SMarcel Moolenaar #include <errno.h>
10051ee2c1cSSimon J. Gerraty #include <signal.h>
1013955d011SMarcel Moolenaar #include <stdarg.h>
1023955d011SMarcel Moolenaar #include <time.h>
1033955d011SMarcel Moolenaar 
1043955d011SMarcel Moolenaar #include "make.h"
1053955d011SMarcel Moolenaar #include "dir.h"
1063955d011SMarcel Moolenaar #include "job.h"
1073955d011SMarcel Moolenaar #include "pathnames.h"
1083955d011SMarcel Moolenaar #include "trace.h"
1093955d011SMarcel Moolenaar 
110956e45f6SSimon J. Gerraty /*	"@(#)main.c	8.3 (Berkeley) 3/19/94"	*/
111*d9a65c5dSSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.639 2025/03/07 06:50:34 rillig Exp $");
112d5e0a182SSimon J. Gerraty #if defined(MAKE_NATIVE)
113956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
114956e45f6SSimon J. Gerraty 	    "The Regents of the University of California.  "
115956e45f6SSimon J. Gerraty 	    "All rights reserved.");
1163955d011SMarcel Moolenaar #endif
1173955d011SMarcel Moolenaar 
1180dede8b0SSimon J. Gerraty #ifndef __arraycount
1190dede8b0SSimon J. Gerraty # define __arraycount(__x)	(sizeof(__x) / sizeof(__x[0]))
1200dede8b0SSimon J. Gerraty #endif
1210dede8b0SSimon J. Gerraty 
122956e45f6SSimon J. Gerraty CmdOpts opts;
1233955d011SMarcel Moolenaar time_t now;			/* Time at start of make */
124e2eeea75SSimon J. Gerraty GNode *defaultNode;		/* .DEFAULT node */
125d5e0a182SSimon J. Gerraty bool allPrecious;		/* .PRECIOUS given on a line by itself */
126b0c40a00SSimon J. Gerraty bool deleteOnError;		/* .DELETE_ON_ERROR: set */
1273955d011SMarcel Moolenaar 
1283955d011SMarcel Moolenaar static int maxJobTokens;	/* -j argument */
1298c973ee2SSimon J. Gerraty static bool enterFlagObj;	/* -w and objdir != srcdir */
130956e45f6SSimon J. Gerraty 
1313955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
132b0c40a00SSimon J. Gerraty bool doing_depend;		/* Set while reading .depend */
133b0c40a00SSimon J. Gerraty static bool jobsRunning;	/* true if the jobs might be running */
1343955d011SMarcel Moolenaar static const char *tracefile;
1359f45a3c8SSimon J. Gerraty static bool ReadMakefile(const char *);
136e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void);
1373955d011SMarcel Moolenaar 
138b0c40a00SSimon J. Gerraty static bool ignorePWD;		/* if we use -C, PWD is meaningless */
1393955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
1403955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1];	/* Startup directory */
14106b9b3e0SSimon J. Gerraty const char *progname;
1423955d011SMarcel Moolenaar char *makeDependfile;
1433955d011SMarcel Moolenaar pid_t myPid;
14451ee2c1cSSimon J. Gerraty int makelevel;
1453955d011SMarcel Moolenaar 
146b0c40a00SSimon J. Gerraty bool forceJobs = false;
14706b9b3e0SSimon J. Gerraty static int main_errors = 0;
148e2eeea75SSimon J. Gerraty static HashTable cached_realpaths;
1493955d011SMarcel Moolenaar 
15051ee2c1cSSimon J. Gerraty /*
15151ee2c1cSSimon J. Gerraty  * For compatibility with the POSIX version of MAKEFLAGS that includes
152e2eeea75SSimon J. Gerraty  * all the options without '-', convert 'flags' to '-f -l -a -g -s '.
15351ee2c1cSSimon J. Gerraty  */
15451ee2c1cSSimon J. Gerraty static char *
15551ee2c1cSSimon J. Gerraty explode(const char *flags)
15651ee2c1cSSimon J. Gerraty {
1579f45a3c8SSimon J. Gerraty 	char *exploded, *ep;
1589f45a3c8SSimon J. Gerraty 	const char *p;
15951ee2c1cSSimon J. Gerraty 
16051ee2c1cSSimon J. Gerraty 	if (flags == NULL)
16151ee2c1cSSimon J. Gerraty 		return NULL;
16251ee2c1cSSimon J. Gerraty 
1639f45a3c8SSimon J. Gerraty 	for (p = flags; *p != '\0'; p++)
1649f45a3c8SSimon J. Gerraty 		if (!ch_isalpha(*p))
16551ee2c1cSSimon J. Gerraty 			return bmake_strdup(flags);
16651ee2c1cSSimon J. Gerraty 
1679f45a3c8SSimon J. Gerraty 	exploded = bmake_malloc((size_t)(p - flags) * 3 + 1);
1689f45a3c8SSimon J. Gerraty 	for (p = flags, ep = exploded; *p != '\0'; p++) {
1699f45a3c8SSimon J. Gerraty 		*ep++ = '-';
1709f45a3c8SSimon J. Gerraty 		*ep++ = *p;
1719f45a3c8SSimon J. Gerraty 		*ep++ = ' ';
17251ee2c1cSSimon J. Gerraty 	}
1739f45a3c8SSimon J. Gerraty 	*ep = '\0';
1749f45a3c8SSimon J. Gerraty 	return exploded;
17551ee2c1cSSimon J. Gerraty }
17651ee2c1cSSimon J. Gerraty 
177e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void
178e2eeea75SSimon J. Gerraty usage(void)
179e2eeea75SSimon J. Gerraty {
180e2eeea75SSimon J. Gerraty 	size_t prognameLen = strcspn(progname, "[");
181e2eeea75SSimon J. Gerraty 
182e2eeea75SSimon J. Gerraty 	(void)fprintf(stderr,
183e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n"
184e2eeea75SSimon J. Gerraty "            [-C directory] [-D variable] [-d flags] [-f makefile]\n"
185e2eeea75SSimon J. Gerraty "            [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
186e2eeea75SSimon J. Gerraty "            [-V variable] [-v variable] [variable=value] [target ...]\n",
187e2eeea75SSimon J. Gerraty 	    (int)prognameLen, progname);
188e2eeea75SSimon J. Gerraty 	exit(2);
189e2eeea75SSimon J. Gerraty }
190e2eeea75SSimon J. Gerraty 
1913955d011SMarcel Moolenaar static void
192dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg)
1933955d011SMarcel Moolenaar {
1943955d011SMarcel Moolenaar 	const char *mode;
195956e45f6SSimon J. Gerraty 	size_t len;
1963955d011SMarcel Moolenaar 	char *fname;
1973955d011SMarcel Moolenaar 
198956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout && opts.debug_file != stderr)
199956e45f6SSimon J. Gerraty 		fclose(opts.debug_file);
200956e45f6SSimon J. Gerraty 
201dba7b0efSSimon J. Gerraty 	if (*arg == '+') {
202dba7b0efSSimon J. Gerraty 		arg++;
2033955d011SMarcel Moolenaar 		mode = "a";
2043955d011SMarcel Moolenaar 	} else
2053955d011SMarcel Moolenaar 		mode = "w";
206956e45f6SSimon J. Gerraty 
207dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stdout") == 0) {
208956e45f6SSimon J. Gerraty 		opts.debug_file = stdout;
209956e45f6SSimon J. Gerraty 		return;
2103955d011SMarcel Moolenaar 	}
211dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stderr") == 0) {
212956e45f6SSimon J. Gerraty 		opts.debug_file = stderr;
213956e45f6SSimon J. Gerraty 		return;
2143955d011SMarcel Moolenaar 	}
215956e45f6SSimon J. Gerraty 
216dba7b0efSSimon J. Gerraty 	len = strlen(arg);
217e1cee40dSSimon J. Gerraty 	fname = bmake_malloc(len + 20);
218dba7b0efSSimon J. Gerraty 	memcpy(fname, arg, len + 1);
219956e45f6SSimon J. Gerraty 
2209f45a3c8SSimon J. Gerraty 	/* Replace the trailing '%d' after '.%d' with the pid. */
2219f45a3c8SSimon J. Gerraty 	if (len >= 3 && memcmp(fname + len - 3, ".%d", 3) == 0)
2223955d011SMarcel Moolenaar 		snprintf(fname + len - 2, 20, "%d", getpid());
223956e45f6SSimon J. Gerraty 
224956e45f6SSimon J. Gerraty 	opts.debug_file = fopen(fname, mode);
225e2eeea75SSimon J. Gerraty 	if (opts.debug_file == NULL) {
226d5e0a182SSimon J. Gerraty 		fprintf(stderr, "Cannot open debug file \"%s\"\n", fname);
2279f45a3c8SSimon J. Gerraty 		exit(2);
2283955d011SMarcel Moolenaar 	}
2293955d011SMarcel Moolenaar 	free(fname);
230956e45f6SSimon J. Gerraty }
231956e45f6SSimon J. Gerraty 
232956e45f6SSimon J. Gerraty static void
233dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue)
234956e45f6SSimon J. Gerraty {
235956e45f6SSimon J. Gerraty 	const char *modules;
236e2eeea75SSimon J. Gerraty 	DebugFlags debug = opts.debug;
237956e45f6SSimon J. Gerraty 
238dba7b0efSSimon J. Gerraty 	for (modules = argvalue; *modules != '\0'; modules++) {
239956e45f6SSimon J. Gerraty 		switch (*modules) {
240956e45f6SSimon J. Gerraty 		case '0':	/* undocumented, only intended for tests */
2419f45a3c8SSimon J. Gerraty 			memset(&debug, 0, sizeof(debug));
242956e45f6SSimon J. Gerraty 			break;
243956e45f6SSimon J. Gerraty 		case 'A':
2449f45a3c8SSimon J. Gerraty 			memset(&debug, ~0, sizeof(debug));
245956e45f6SSimon J. Gerraty 			break;
246956e45f6SSimon J. Gerraty 		case 'a':
2479f45a3c8SSimon J. Gerraty 			debug.DEBUG_ARCH = true;
248956e45f6SSimon J. Gerraty 			break;
249956e45f6SSimon J. Gerraty 		case 'C':
2509f45a3c8SSimon J. Gerraty 			debug.DEBUG_CWD = true;
251956e45f6SSimon J. Gerraty 			break;
252956e45f6SSimon J. Gerraty 		case 'c':
2539f45a3c8SSimon J. Gerraty 			debug.DEBUG_COND = true;
254956e45f6SSimon J. Gerraty 			break;
255956e45f6SSimon J. Gerraty 		case 'd':
2569f45a3c8SSimon J. Gerraty 			debug.DEBUG_DIR = true;
257956e45f6SSimon J. Gerraty 			break;
258956e45f6SSimon J. Gerraty 		case 'e':
2599f45a3c8SSimon J. Gerraty 			debug.DEBUG_ERROR = true;
260956e45f6SSimon J. Gerraty 			break;
261956e45f6SSimon J. Gerraty 		case 'f':
2629f45a3c8SSimon J. Gerraty 			debug.DEBUG_FOR = true;
263956e45f6SSimon J. Gerraty 			break;
264956e45f6SSimon J. Gerraty 		case 'g':
265956e45f6SSimon J. Gerraty 			if (modules[1] == '1') {
2669f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH1 = true;
267e2eeea75SSimon J. Gerraty 				modules++;
268e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '2') {
2699f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH2 = true;
270e2eeea75SSimon J. Gerraty 				modules++;
271e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '3') {
2729f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH3 = true;
273e2eeea75SSimon J. Gerraty 				modules++;
274956e45f6SSimon J. Gerraty 			}
275956e45f6SSimon J. Gerraty 			break;
276956e45f6SSimon J. Gerraty 		case 'h':
2779f45a3c8SSimon J. Gerraty 			debug.DEBUG_HASH = true;
278956e45f6SSimon J. Gerraty 			break;
279956e45f6SSimon J. Gerraty 		case 'j':
2809f45a3c8SSimon J. Gerraty 			debug.DEBUG_JOB = true;
281956e45f6SSimon J. Gerraty 			break;
282956e45f6SSimon J. Gerraty 		case 'L':
283b0c40a00SSimon J. Gerraty 			opts.strict = true;
284956e45f6SSimon J. Gerraty 			break;
285956e45f6SSimon J. Gerraty 		case 'l':
2869f45a3c8SSimon J. Gerraty 			debug.DEBUG_LOUD = true;
287956e45f6SSimon J. Gerraty 			break;
288956e45f6SSimon J. Gerraty 		case 'M':
2899f45a3c8SSimon J. Gerraty 			debug.DEBUG_META = true;
290956e45f6SSimon J. Gerraty 			break;
291956e45f6SSimon J. Gerraty 		case 'm':
2929f45a3c8SSimon J. Gerraty 			debug.DEBUG_MAKE = true;
293956e45f6SSimon J. Gerraty 			break;
294956e45f6SSimon J. Gerraty 		case 'n':
2959f45a3c8SSimon J. Gerraty 			debug.DEBUG_SCRIPT = true;
296956e45f6SSimon J. Gerraty 			break;
297956e45f6SSimon J. Gerraty 		case 'p':
2989f45a3c8SSimon J. Gerraty 			debug.DEBUG_PARSE = true;
299956e45f6SSimon J. Gerraty 			break;
300956e45f6SSimon J. Gerraty 		case 's':
3019f45a3c8SSimon J. Gerraty 			debug.DEBUG_SUFF = true;
302956e45f6SSimon J. Gerraty 			break;
303956e45f6SSimon J. Gerraty 		case 't':
3049f45a3c8SSimon J. Gerraty 			debug.DEBUG_TARG = true;
305956e45f6SSimon J. Gerraty 			break;
306956e45f6SSimon J. Gerraty 		case 'V':
307b0c40a00SSimon J. Gerraty 			opts.debugVflag = true;
308956e45f6SSimon J. Gerraty 			break;
309956e45f6SSimon J. Gerraty 		case 'v':
3109f45a3c8SSimon J. Gerraty 			debug.DEBUG_VAR = true;
311956e45f6SSimon J. Gerraty 			break;
312956e45f6SSimon J. Gerraty 		case 'x':
3139f45a3c8SSimon J. Gerraty 			debug.DEBUG_SHELL = true;
314956e45f6SSimon J. Gerraty 			break;
315956e45f6SSimon J. Gerraty 		case 'F':
316dba7b0efSSimon J. Gerraty 			MainParseArgDebugFile(modules + 1);
3171d3f2ddcSSimon J. Gerraty 			goto finish;
3183955d011SMarcel Moolenaar 		default:
3193955d011SMarcel Moolenaar 			(void)fprintf(stderr,
3203955d011SMarcel Moolenaar 			    "%s: illegal argument to d option -- %c\n",
3213955d011SMarcel Moolenaar 			    progname, *modules);
3223955d011SMarcel Moolenaar 			usage();
3233955d011SMarcel Moolenaar 		}
3243955d011SMarcel Moolenaar 	}
325e2eeea75SSimon J. Gerraty 
3261d3f2ddcSSimon J. Gerraty finish:
327e2eeea75SSimon J. Gerraty 	opts.debug = debug;
328e2eeea75SSimon J. Gerraty 
329956e45f6SSimon J. Gerraty 	setvbuf(opts.debug_file, NULL, _IONBF, 0);
3301d3f2ddcSSimon J. Gerraty 	if (opts.debug_file != stdout)
3313955d011SMarcel Moolenaar 		setvbuf(stdout, NULL, _IOLBF, 0);
3323955d011SMarcel Moolenaar }
3333955d011SMarcel Moolenaar 
3341d3f2ddcSSimon J. Gerraty /* Is path relative or does it contain any relative component "." or ".."? */
335b0c40a00SSimon J. Gerraty static bool
336dba7b0efSSimon J. Gerraty IsRelativePath(const char *path)
337e1cee40dSSimon J. Gerraty {
338b0c40a00SSimon J. Gerraty 	const char *p;
339e1cee40dSSimon J. Gerraty 
340e1cee40dSSimon J. Gerraty 	if (path[0] != '/')
341b0c40a00SSimon J. Gerraty 		return true;
342b0c40a00SSimon J. Gerraty 	p = path;
343b0c40a00SSimon J. Gerraty 	while ((p = strstr(p, "/.")) != NULL) {
344b0c40a00SSimon J. Gerraty 		p += 2;
345b0c40a00SSimon J. Gerraty 		if (*p == '.')
346b0c40a00SSimon J. Gerraty 			p++;
347b0c40a00SSimon J. Gerraty 		if (*p == '/' || *p == '\0')
348b0c40a00SSimon J. Gerraty 			return true;
3492c3632d1SSimon J. Gerraty 	}
350b0c40a00SSimon J. Gerraty 	return false;
351e1cee40dSSimon J. Gerraty }
352e1cee40dSSimon J. Gerraty 
353956e45f6SSimon J. Gerraty static void
354956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue)
355956e45f6SSimon J. Gerraty {
356956e45f6SSimon J. Gerraty 	struct stat sa, sb;
357956e45f6SSimon J. Gerraty 
358956e45f6SSimon J. Gerraty 	if (chdir(argvalue) == -1) {
359956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: chdir %s: %s\n",
360956e45f6SSimon J. Gerraty 		    progname, argvalue, strerror(errno));
36106b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
362956e45f6SSimon J. Gerraty 	}
363956e45f6SSimon J. Gerraty 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
364956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
365956e45f6SSimon J. Gerraty 		exit(2);
366956e45f6SSimon J. Gerraty 	}
367dba7b0efSSimon J. Gerraty 	if (!IsRelativePath(argvalue) &&
368956e45f6SSimon J. Gerraty 	    stat(argvalue, &sa) != -1 &&
369956e45f6SSimon J. Gerraty 	    stat(curdir, &sb) != -1 &&
370956e45f6SSimon J. Gerraty 	    sa.st_ino == sb.st_ino &&
371956e45f6SSimon J. Gerraty 	    sa.st_dev == sb.st_dev)
3728d5c8e21SSimon J. Gerraty 		snprintf(curdir, MAXPATHLEN, "%s", argvalue);
373b0c40a00SSimon J. Gerraty 	ignorePWD = true;
374956e45f6SSimon J. Gerraty }
375956e45f6SSimon J. Gerraty 
376956e45f6SSimon J. Gerraty static void
377956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue)
378956e45f6SSimon J. Gerraty {
379e2eeea75SSimon J. Gerraty 	char end;
380e2eeea75SSimon J. Gerraty 	if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
381956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
382956e45f6SSimon J. Gerraty 		    "%s: internal error -- J option malformed (%s)\n",
383956e45f6SSimon J. Gerraty 		    progname, argvalue);
384956e45f6SSimon J. Gerraty 		usage();
385956e45f6SSimon J. Gerraty 	}
386956e45f6SSimon J. Gerraty 	if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
387956e45f6SSimon J. Gerraty 	    (fcntl(jp_1, F_GETFD, 0) < 0)) {
388956e45f6SSimon J. Gerraty 		jp_0 = -1;
389956e45f6SSimon J. Gerraty 		jp_1 = -1;
390b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
391956e45f6SSimon J. Gerraty 	} else {
392dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-J");
393dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
394956e45f6SSimon J. Gerraty 	}
395956e45f6SSimon J. Gerraty }
396956e45f6SSimon J. Gerraty 
397956e45f6SSimon J. Gerraty static void
39898875883SSimon J. Gerraty MainParseArgJobs(const char *arg)
399956e45f6SSimon J. Gerraty {
40098875883SSimon J. Gerraty 	const char *p;
40198875883SSimon J. Gerraty 	char *end;
40298875883SSimon J. Gerraty 	char v[12];
403956e45f6SSimon J. Gerraty 
404b0c40a00SSimon J. Gerraty 	forceJobs = true;
40598875883SSimon J. Gerraty 	opts.maxJobs = (int)strtol(arg, &end, 0);
406d5e0a182SSimon J. Gerraty 	p = end;
40798875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
40898875883SSimon J. Gerraty 	if (*p != '\0') {
40998875883SSimon J. Gerraty 		double d;
41098875883SSimon J. Gerraty 
411d5e0a182SSimon J. Gerraty 		if (*p == 'C')
41298875883SSimon J. Gerraty 			d = (opts.maxJobs > 0) ? opts.maxJobs : 1;
413d5e0a182SSimon J. Gerraty 		else if (*p == '.') {
41498875883SSimon J. Gerraty 			d = strtod(arg, &end);
415d5e0a182SSimon J. Gerraty 			p = end;
41698875883SSimon J. Gerraty 		} else
417d5e0a182SSimon J. Gerraty 			d = 0.0;
418d5e0a182SSimon J. Gerraty 		if (d > 0.0) {
41998875883SSimon J. Gerraty 			p = "";
42098875883SSimon J. Gerraty 			opts.maxJobs = (int)sysconf(_SC_NPROCESSORS_ONLN);
42198875883SSimon J. Gerraty 			opts.maxJobs = (int)(d * (double)opts.maxJobs);
42298875883SSimon J. Gerraty 		}
42398875883SSimon J. Gerraty 	}
42498875883SSimon J. Gerraty #endif
425956e45f6SSimon J. Gerraty 	if (*p != '\0' || opts.maxJobs < 1) {
426956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
42798875883SSimon J. Gerraty 		    "%s: argument '%s' to option '-j' "
42898875883SSimon J. Gerraty 		    "must be a positive number\n",
42998875883SSimon J. Gerraty 		    progname, arg);
43006b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
431956e45f6SSimon J. Gerraty 	}
43298875883SSimon J. Gerraty 	snprintf(v, sizeof(v), "%d", opts.maxJobs);
433dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-j");
43498875883SSimon J. Gerraty 	Global_Append(MAKEFLAGS, v);
43598875883SSimon J. Gerraty 	Global_Set(".MAKE.JOBS", v);
436956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
437956e45f6SSimon J. Gerraty }
438956e45f6SSimon J. Gerraty 
439956e45f6SSimon J. Gerraty static void
440956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue)
441956e45f6SSimon J. Gerraty {
442d5e0a182SSimon J. Gerraty 	if (strncmp(argvalue, ".../", 4) == 0) {
443956e45f6SSimon J. Gerraty 		char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
444956e45f6SSimon J. Gerraty 		if (found_path == NULL)
445956e45f6SSimon J. Gerraty 			return;
446dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, found_path);
447956e45f6SSimon J. Gerraty 		free(found_path);
448956e45f6SSimon J. Gerraty 	} else {
449dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, argvalue);
450956e45f6SSimon J. Gerraty 	}
451dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-m");
452dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, argvalue);
4534fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
454956e45f6SSimon J. Gerraty }
455956e45f6SSimon J. Gerraty 
456b0c40a00SSimon J. Gerraty static bool
4578c973ee2SSimon J. Gerraty MainParseOption(char c, const char *argvalue)
458956e45f6SSimon J. Gerraty {
459956e45f6SSimon J. Gerraty 	switch (c) {
460956e45f6SSimon J. Gerraty 	case '\0':
461956e45f6SSimon J. Gerraty 		break;
462956e45f6SSimon J. Gerraty 	case 'B':
463b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
464dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-B");
4658c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.MODE", "compat");
466956e45f6SSimon J. Gerraty 		break;
467956e45f6SSimon J. Gerraty 	case 'C':
468956e45f6SSimon J. Gerraty 		MainParseArgChdir(argvalue);
469956e45f6SSimon J. Gerraty 		break;
470956e45f6SSimon J. Gerraty 	case 'D':
4719f45a3c8SSimon J. Gerraty 		if (argvalue[0] == '\0')
4729f45a3c8SSimon J. Gerraty 			return false;
4739f45a3c8SSimon J. Gerraty 		Var_SetExpand(SCOPE_GLOBAL, argvalue, "1");
474dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-D");
475dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
476956e45f6SSimon J. Gerraty 		break;
477956e45f6SSimon J. Gerraty 	case 'I':
478d5e0a182SSimon J. Gerraty 		SearchPath_Add(parseIncPath, argvalue);
479dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-I");
480dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
481956e45f6SSimon J. Gerraty 		break;
482956e45f6SSimon J. Gerraty 	case 'J':
483956e45f6SSimon J. Gerraty 		MainParseArgJobsInternal(argvalue);
484956e45f6SSimon J. Gerraty 		break;
485956e45f6SSimon J. Gerraty 	case 'N':
486b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
487b0c40a00SSimon J. Gerraty 		opts.noRecursiveExecute = true;
488dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-N");
489956e45f6SSimon J. Gerraty 		break;
490956e45f6SSimon J. Gerraty 	case 'S':
491b0c40a00SSimon J. Gerraty 		opts.keepgoing = false;
492dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-S");
493956e45f6SSimon J. Gerraty 		break;
494956e45f6SSimon J. Gerraty 	case 'T':
495956e45f6SSimon J. Gerraty 		tracefile = bmake_strdup(argvalue);
496dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-T");
497dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
498956e45f6SSimon J. Gerraty 		break;
499956e45f6SSimon J. Gerraty 	case 'V':
500956e45f6SSimon J. Gerraty 	case 'v':
501e2eeea75SSimon J. Gerraty 		opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
50206b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.variables, bmake_strdup(argvalue));
503956e45f6SSimon J. Gerraty 		/* XXX: Why always -V? */
504dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-V");
505dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
506956e45f6SSimon J. Gerraty 		break;
507956e45f6SSimon J. Gerraty 	case 'W':
508b0c40a00SSimon J. Gerraty 		opts.parseWarnFatal = true;
5099f45a3c8SSimon J. Gerraty 		/* XXX: why no Global_Append? */
510956e45f6SSimon J. Gerraty 		break;
511956e45f6SSimon J. Gerraty 	case 'X':
512b0c40a00SSimon J. Gerraty 		opts.varNoExportEnv = true;
513dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-X");
514956e45f6SSimon J. Gerraty 		break;
515956e45f6SSimon J. Gerraty 	case 'd':
516956e45f6SSimon J. Gerraty 		/* If '-d-opts' don't pass to children */
517956e45f6SSimon J. Gerraty 		if (argvalue[0] == '-')
518956e45f6SSimon J. Gerraty 			argvalue++;
519956e45f6SSimon J. Gerraty 		else {
520dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, "-d");
521dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, argvalue);
522956e45f6SSimon J. Gerraty 		}
523dba7b0efSSimon J. Gerraty 		MainParseArgDebug(argvalue);
524956e45f6SSimon J. Gerraty 		break;
525956e45f6SSimon J. Gerraty 	case 'e':
526b0c40a00SSimon J. Gerraty 		opts.checkEnvFirst = true;
527dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-e");
528956e45f6SSimon J. Gerraty 		break;
529956e45f6SSimon J. Gerraty 	case 'f':
53006b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.makefiles, bmake_strdup(argvalue));
531956e45f6SSimon J. Gerraty 		break;
532956e45f6SSimon J. Gerraty 	case 'i':
533b0c40a00SSimon J. Gerraty 		opts.ignoreErrors = true;
534dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-i");
535956e45f6SSimon J. Gerraty 		break;
536956e45f6SSimon J. Gerraty 	case 'j':
537956e45f6SSimon J. Gerraty 		MainParseArgJobs(argvalue);
538956e45f6SSimon J. Gerraty 		break;
539956e45f6SSimon J. Gerraty 	case 'k':
540b0c40a00SSimon J. Gerraty 		opts.keepgoing = true;
541dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-k");
542956e45f6SSimon J. Gerraty 		break;
543956e45f6SSimon J. Gerraty 	case 'm':
544956e45f6SSimon J. Gerraty 		MainParseArgSysInc(argvalue);
545e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
546956e45f6SSimon J. Gerraty 		break;
547956e45f6SSimon J. Gerraty 	case 'n':
548b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
549dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-n");
550956e45f6SSimon J. Gerraty 		break;
551956e45f6SSimon J. Gerraty 	case 'q':
5529f45a3c8SSimon J. Gerraty 		opts.query = true;
553956e45f6SSimon J. Gerraty 		/* Kind of nonsensical, wot? */
554dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-q");
555956e45f6SSimon J. Gerraty 		break;
556956e45f6SSimon J. Gerraty 	case 'r':
557b0c40a00SSimon J. Gerraty 		opts.noBuiltins = true;
558dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-r");
559956e45f6SSimon J. Gerraty 		break;
560956e45f6SSimon J. Gerraty 	case 's':
5619f45a3c8SSimon J. Gerraty 		opts.silent = true;
562dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-s");
563956e45f6SSimon J. Gerraty 		break;
564956e45f6SSimon J. Gerraty 	case 't':
5659f45a3c8SSimon J. Gerraty 		opts.touch = true;
566dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-t");
567956e45f6SSimon J. Gerraty 		break;
568956e45f6SSimon J. Gerraty 	case 'w':
569b0c40a00SSimon J. Gerraty 		opts.enterFlag = true;
570dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-w");
571956e45f6SSimon J. Gerraty 		break;
572956e45f6SSimon J. Gerraty 	default:
573956e45f6SSimon J. Gerraty 		usage();
574956e45f6SSimon J. Gerraty 	}
575b0c40a00SSimon J. Gerraty 	return true;
576956e45f6SSimon J. Gerraty }
577956e45f6SSimon J. Gerraty 
57806b9b3e0SSimon J. Gerraty /*
57906b9b3e0SSimon J. Gerraty  * Parse the given arguments.  Called from main() and from
5803955d011SMarcel Moolenaar  * Main_ParseArgLine() when the .MAKEFLAGS target is used.
5813955d011SMarcel Moolenaar  *
582956e45f6SSimon J. Gerraty  * The arguments must be treated as read-only and will be freed after the
583956e45f6SSimon J. Gerraty  * call.
5843955d011SMarcel Moolenaar  *
58506b9b3e0SSimon J. Gerraty  * XXX: Deal with command line overriding .MAKEFLAGS in makefile
58606b9b3e0SSimon J. Gerraty  */
5873955d011SMarcel Moolenaar static void
5883955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv)
5893955d011SMarcel Moolenaar {
590956e45f6SSimon J. Gerraty 	char c;
5913955d011SMarcel Moolenaar 	int arginc;
5923955d011SMarcel Moolenaar 	char *argvalue;
5933955d011SMarcel Moolenaar 	char *optscan;
594b0c40a00SSimon J. Gerraty 	bool inOption, dashDash = false;
5953955d011SMarcel Moolenaar 
596956e45f6SSimon J. Gerraty 	const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
5973955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */
5983955d011SMarcel Moolenaar 
5993955d011SMarcel Moolenaar rearg:
600b0c40a00SSimon J. Gerraty 	inOption = false;
6013955d011SMarcel Moolenaar 	optscan = NULL;
6023955d011SMarcel Moolenaar 	while (argc > 1) {
603956e45f6SSimon J. Gerraty 		const char *optspec;
6043955d011SMarcel Moolenaar 		if (!inOption)
6053955d011SMarcel Moolenaar 			optscan = argv[1];
6063955d011SMarcel Moolenaar 		c = *optscan++;
6073955d011SMarcel Moolenaar 		arginc = 0;
6083955d011SMarcel Moolenaar 		if (inOption) {
6093955d011SMarcel Moolenaar 			if (c == '\0') {
610e2eeea75SSimon J. Gerraty 				argv++;
611e2eeea75SSimon J. Gerraty 				argc--;
612b0c40a00SSimon J. Gerraty 				inOption = false;
6133955d011SMarcel Moolenaar 				continue;
6143955d011SMarcel Moolenaar 			}
6153955d011SMarcel Moolenaar 		} else {
6163955d011SMarcel Moolenaar 			if (c != '-' || dashDash)
6173955d011SMarcel Moolenaar 				break;
618b0c40a00SSimon J. Gerraty 			inOption = true;
6193955d011SMarcel Moolenaar 			c = *optscan++;
6203955d011SMarcel Moolenaar 		}
6213955d011SMarcel Moolenaar 		/* '-' found at some earlier point */
622956e45f6SSimon J. Gerraty 		optspec = strchr(optspecs, c);
623956e45f6SSimon J. Gerraty 		if (c != '\0' && optspec != NULL && optspec[1] == ':') {
6249f45a3c8SSimon J. Gerraty 			/*
6259f45a3c8SSimon J. Gerraty 			 * -<something> found, and <something> should have an
6269f45a3c8SSimon J. Gerraty 			 * argument
6279f45a3c8SSimon J. Gerraty 			 */
628b0c40a00SSimon J. Gerraty 			inOption = false;
6293955d011SMarcel Moolenaar 			arginc = 1;
6303955d011SMarcel Moolenaar 			argvalue = optscan;
6313955d011SMarcel Moolenaar 			if (*argvalue == '\0') {
6323955d011SMarcel Moolenaar 				if (argc < 3)
6333955d011SMarcel Moolenaar 					goto noarg;
6343955d011SMarcel Moolenaar 				argvalue = argv[2];
6353955d011SMarcel Moolenaar 				arginc = 2;
6363955d011SMarcel Moolenaar 			}
6373955d011SMarcel Moolenaar 		} else {
6383955d011SMarcel Moolenaar 			argvalue = NULL;
6393955d011SMarcel Moolenaar 		}
6403955d011SMarcel Moolenaar 		switch (c) {
6413955d011SMarcel Moolenaar 		case '\0':
6423955d011SMarcel Moolenaar 			arginc = 1;
643b0c40a00SSimon J. Gerraty 			inOption = false;
6443955d011SMarcel Moolenaar 			break;
6453955d011SMarcel Moolenaar 		case '-':
646b0c40a00SSimon J. Gerraty 			dashDash = true;
6473955d011SMarcel Moolenaar 			break;
6483955d011SMarcel Moolenaar 		default:
6498c973ee2SSimon J. Gerraty 			if (!MainParseOption(c, argvalue))
650956e45f6SSimon J. Gerraty 				goto noarg;
6513955d011SMarcel Moolenaar 		}
6523955d011SMarcel Moolenaar 		argv += arginc;
6533955d011SMarcel Moolenaar 		argc -= arginc;
6543955d011SMarcel Moolenaar 	}
6553955d011SMarcel Moolenaar 
6563955d011SMarcel Moolenaar 	/*
6573955d011SMarcel Moolenaar 	 * See if the rest of the arguments are variable assignments and
6583955d011SMarcel Moolenaar 	 * perform them if so. Else take them to be targets and stuff them
6593955d011SMarcel Moolenaar 	 * on the end of the "create" list.
6603955d011SMarcel Moolenaar 	 */
661dba7b0efSSimon J. Gerraty 	for (; argc > 1; argv++, argc--) {
6629f45a3c8SSimon J. Gerraty 		if (!Parse_VarAssign(argv[1], false, SCOPE_CMDLINE)) {
663e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '\0')
6643955d011SMarcel Moolenaar 				Punt("illegal (null) argument.");
665e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '-' && !dashDash)
6663955d011SMarcel Moolenaar 				goto rearg;
66706b9b3e0SSimon J. Gerraty 			Lst_Append(&opts.create, bmake_strdup(argv[1]));
668956e45f6SSimon J. Gerraty 		}
6693955d011SMarcel Moolenaar 	}
6703955d011SMarcel Moolenaar 
6713955d011SMarcel Moolenaar 	return;
6723955d011SMarcel Moolenaar noarg:
6733955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
6743955d011SMarcel Moolenaar 	    progname, c);
6753955d011SMarcel Moolenaar 	usage();
6763955d011SMarcel Moolenaar }
6773955d011SMarcel Moolenaar 
67806b9b3e0SSimon J. Gerraty /*
67906b9b3e0SSimon J. Gerraty  * Break a line of arguments into words and parse them.
6803955d011SMarcel Moolenaar  *
681956e45f6SSimon J. Gerraty  * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
68206b9b3e0SSimon J. Gerraty  * by main() when reading the MAKEFLAGS environment variable.
68306b9b3e0SSimon J. Gerraty  */
6843955d011SMarcel Moolenaar void
6853955d011SMarcel Moolenaar Main_ParseArgLine(const char *line)
6863955d011SMarcel Moolenaar {
6872c3632d1SSimon J. Gerraty 	Words words;
6882c3632d1SSimon J. Gerraty 	char *buf;
689d5e0a182SSimon J. Gerraty 	const char *p;
6903955d011SMarcel Moolenaar 
6913955d011SMarcel Moolenaar 	if (line == NULL)
6923955d011SMarcel Moolenaar 		return;
693d5e0a182SSimon J. Gerraty 	for (p = line; *p == ' '; p++)
6943955d011SMarcel Moolenaar 		continue;
695d5e0a182SSimon J. Gerraty 	if (p[0] == '\0')
6963955d011SMarcel Moolenaar 		return;
6973955d011SMarcel Moolenaar 
698e2eeea75SSimon J. Gerraty 	{
699dba7b0efSSimon J. Gerraty 		FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE");
700d5e0a182SSimon J. Gerraty 		buf = str_concat3(argv0.str, " ", p);
70106b9b3e0SSimon J. Gerraty 		FStr_Done(&argv0);
702e2eeea75SSimon J. Gerraty 	}
7033955d011SMarcel Moolenaar 
704b0c40a00SSimon J. Gerraty 	words = Str_Words(buf, true);
7052c3632d1SSimon J. Gerraty 	if (words.words == NULL) {
7063955d011SMarcel Moolenaar 		Error("Unterminated quoted string [%s]", buf);
7073955d011SMarcel Moolenaar 		free(buf);
7083955d011SMarcel Moolenaar 		return;
7093955d011SMarcel Moolenaar 	}
7103955d011SMarcel Moolenaar 	free(buf);
7112c3632d1SSimon J. Gerraty 	MainParseArgs((int)words.len, words.words);
7123955d011SMarcel Moolenaar 
7132c3632d1SSimon J. Gerraty 	Words_Free(words);
7143955d011SMarcel Moolenaar }
7153955d011SMarcel Moolenaar 
716b0c40a00SSimon J. Gerraty bool
717b0c40a00SSimon J. Gerraty Main_SetObjdir(bool writable, const char *fmt, ...)
7183955d011SMarcel Moolenaar {
7193955d011SMarcel Moolenaar 	struct stat sb;
720b46b9039SSimon J. Gerraty 	char *path;
721b46b9039SSimon J. Gerraty 	char buf[MAXPATHLEN + 1];
722e23f3f6eSSimon J. Gerraty 	char buf2[MAXPATHLEN + 1];
72345447996SSimon J. Gerraty 	va_list ap;
72445447996SSimon J. Gerraty 
72545447996SSimon J. Gerraty 	va_start(ap, fmt);
726b46b9039SSimon J. Gerraty 	vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
72745447996SSimon J. Gerraty 	va_end(ap);
7283955d011SMarcel Moolenaar 
7293955d011SMarcel Moolenaar 	if (path[0] != '/') {
7304fde40d9SSimon J. Gerraty 		if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN)
731e1cee40dSSimon J. Gerraty 			path = buf2;
7324fde40d9SSimon J. Gerraty 		else
7334fde40d9SSimon J. Gerraty 			return false;
7343955d011SMarcel Moolenaar 	}
7353955d011SMarcel Moolenaar 
7363955d011SMarcel Moolenaar 	/* look for the directory and try to chdir there */
7379f45a3c8SSimon J. Gerraty 	if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))
7389f45a3c8SSimon J. Gerraty 		return false;
7399f45a3c8SSimon J. Gerraty 
7409f45a3c8SSimon J. Gerraty 	if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
7411d3f2ddcSSimon J. Gerraty 		(void)fprintf(stderr, "%s: warning: %s: %s.\n",
742e2eeea75SSimon J. Gerraty 		    progname, path, strerror(errno));
7438d5c8e21SSimon J. Gerraty 		/* Allow debugging how we got here - not always obvious */
7448d5c8e21SSimon J. Gerraty 		if (GetBooleanExpr("${MAKE_DEBUG_OBJDIR_CHECK_WRITABLE}",
7458d5c8e21SSimon J. Gerraty 			false))
7468d5c8e21SSimon J. Gerraty 			PrintOnError(NULL, "");
7479f45a3c8SSimon J. Gerraty 		return false;
7489f45a3c8SSimon J. Gerraty 	}
7499f45a3c8SSimon J. Gerraty 
7502c3632d1SSimon J. Gerraty 	snprintf(objdir, sizeof objdir, "%s", path);
751dba7b0efSSimon J. Gerraty 	Global_Set(".OBJDIR", objdir);
7523955d011SMarcel Moolenaar 	setenv("PWD", objdir, 1);
7533955d011SMarcel Moolenaar 	Dir_InitDot();
754e2eeea75SSimon J. Gerraty 	purge_relative_cached_realpaths();
755956e45f6SSimon J. Gerraty 	if (opts.enterFlag && strcmp(objdir, curdir) != 0)
756b0c40a00SSimon J. Gerraty 		enterFlagObj = true;
7579f45a3c8SSimon J. Gerraty 	return true;
7583955d011SMarcel Moolenaar }
7593955d011SMarcel Moolenaar 
760b0c40a00SSimon J. Gerraty static bool
761b0c40a00SSimon J. Gerraty SetVarObjdir(bool writable, const char *var, const char *suffix)
76245447996SSimon J. Gerraty {
763dba7b0efSSimon J. Gerraty 	FStr path = Var_Value(SCOPE_CMDLINE, var);
764b46b9039SSimon J. Gerraty 
76506b9b3e0SSimon J. Gerraty 	if (path.str == NULL || path.str[0] == '\0') {
76606b9b3e0SSimon J. Gerraty 		FStr_Done(&path);
767b0c40a00SSimon J. Gerraty 		return false;
7682c3632d1SSimon J. Gerraty 	}
76945447996SSimon J. Gerraty 
7708d5c8e21SSimon J. Gerraty 	Var_Expand(&path, SCOPE_GLOBAL, VARE_EVAL);
771b46b9039SSimon J. Gerraty 
7729f45a3c8SSimon J. Gerraty 	(void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
773b46b9039SSimon J. Gerraty 
77406b9b3e0SSimon J. Gerraty 	FStr_Done(&path);
775b0c40a00SSimon J. Gerraty 	return true;
77645447996SSimon J. Gerraty }
77745447996SSimon J. Gerraty 
77806b9b3e0SSimon J. Gerraty /*
779d5e0a182SSimon J. Gerraty  * Splits str into words (in-place, modifying it), adding them to the list.
78006b9b3e0SSimon J. Gerraty  * The string must be kept alive as long as the list.
78106b9b3e0SSimon J. Gerraty  */
782d5e0a182SSimon J. Gerraty void
783d5e0a182SSimon J. Gerraty AppendWords(StringList *lp, char *str)
7843955d011SMarcel Moolenaar {
785d5e0a182SSimon J. Gerraty 	char *p;
786e2eeea75SSimon J. Gerraty 	const char *sep = " \t";
7873955d011SMarcel Moolenaar 
788d5e0a182SSimon J. Gerraty 	for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep))
789d5e0a182SSimon J. Gerraty 		Lst_Append(lp, p);
7903955d011SMarcel Moolenaar }
7913955d011SMarcel Moolenaar 
7923955d011SMarcel Moolenaar #ifdef SIGINFO
7933955d011SMarcel Moolenaar static void
7943955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED)
7953955d011SMarcel Moolenaar {
7963955d011SMarcel Moolenaar 	char dir[MAXPATHLEN];
7973955d011SMarcel Moolenaar 	char str[2 * MAXPATHLEN];
7983955d011SMarcel Moolenaar 	int len;
799e2eeea75SSimon J. Gerraty 	if (getcwd(dir, sizeof dir) == NULL)
8003955d011SMarcel Moolenaar 		return;
801e2eeea75SSimon J. Gerraty 	len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir);
8023955d011SMarcel Moolenaar 	if (len > 0)
8033955d011SMarcel Moolenaar 		(void)write(STDERR_FILENO, str, (size_t)len);
8043955d011SMarcel Moolenaar }
8053955d011SMarcel Moolenaar #endif
8063955d011SMarcel Moolenaar 
80706b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */
80806b9b3e0SSimon J. Gerraty static void
80906b9b3e0SSimon J. Gerraty MakeMode(void)
8103955d011SMarcel Moolenaar {
8118d5c8e21SSimon J. Gerraty 	char *mode = Var_Subst("${.MAKE.MODE:tl}", SCOPE_GLOBAL, VARE_EVAL);
812956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
8133955d011SMarcel Moolenaar 
814dba7b0efSSimon J. Gerraty 	if (mode[0] != '\0') {
815dba7b0efSSimon J. Gerraty 		if (strstr(mode, "compat") != NULL) {
816b0c40a00SSimon J. Gerraty 			opts.compatMake = true;
817b0c40a00SSimon J. Gerraty 			forceJobs = false;
8183955d011SMarcel Moolenaar 		}
8193955d011SMarcel Moolenaar #if USE_META
820dba7b0efSSimon J. Gerraty 		if (strstr(mode, "meta") != NULL)
821dba7b0efSSimon J. Gerraty 			meta_mode_init(mode);
8223955d011SMarcel Moolenaar #endif
823954401e6SSimon J. Gerraty 		if (strstr(mode, "randomize-targets") != NULL)
824954401e6SSimon J. Gerraty 			opts.randomizeTargets = true;
8253955d011SMarcel Moolenaar 	}
826be19d90bSSimon J. Gerraty 
827dba7b0efSSimon J. Gerraty 	free(mode);
8283955d011SMarcel Moolenaar }
8293955d011SMarcel Moolenaar 
8308695518cSSimon J. Gerraty static void
831b0c40a00SSimon J. Gerraty PrintVar(const char *varname, bool expandVars)
832956e45f6SSimon J. Gerraty {
83306b9b3e0SSimon J. Gerraty 	if (strchr(varname, '$') != NULL) {
8348d5c8e21SSimon J. Gerraty 		char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_EVAL);
835956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
836956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8379f45a3c8SSimon J. Gerraty 		free(evalue);
838956e45f6SSimon J. Gerraty 
839956e45f6SSimon J. Gerraty 	} else if (expandVars) {
840956e45f6SSimon J. Gerraty 		char *expr = str_concat3("${", varname, "}");
8418d5c8e21SSimon J. Gerraty 		char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
842956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
843956e45f6SSimon J. Gerraty 		free(expr);
844956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8459f45a3c8SSimon J. Gerraty 		free(evalue);
846956e45f6SSimon J. Gerraty 
847956e45f6SSimon J. Gerraty 	} else {
848dba7b0efSSimon J. Gerraty 		FStr value = Var_Value(SCOPE_GLOBAL, varname);
84906b9b3e0SSimon J. Gerraty 		printf("%s\n", value.str != NULL ? value.str : "");
85006b9b3e0SSimon J. Gerraty 		FStr_Done(&value);
851956e45f6SSimon J. Gerraty 	}
852956e45f6SSimon J. Gerraty }
853956e45f6SSimon J. Gerraty 
854e2eeea75SSimon J. Gerraty /*
855b0c40a00SSimon J. Gerraty  * Return a bool based on a variable.
856e2eeea75SSimon J. Gerraty  *
857e2eeea75SSimon J. Gerraty  * If the knob is not set, return the fallback.
858e2eeea75SSimon J. Gerraty  * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
859b0c40a00SSimon J. Gerraty  * is false, otherwise true.
860e2eeea75SSimon J. Gerraty  */
861b0c40a00SSimon J. Gerraty bool
862b0c40a00SSimon J. Gerraty GetBooleanExpr(const char *expr, bool fallback)
863e2eeea75SSimon J. Gerraty {
864e2eeea75SSimon J. Gerraty 	char *value;
865b0c40a00SSimon J. Gerraty 	bool res;
866e2eeea75SSimon J. Gerraty 
8678d5c8e21SSimon J. Gerraty 	value = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
868e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
869e2eeea75SSimon J. Gerraty 	res = ParseBoolean(value, fallback);
870e2eeea75SSimon J. Gerraty 	free(value);
871e2eeea75SSimon J. Gerraty 	return res;
872e2eeea75SSimon J. Gerraty }
873e2eeea75SSimon J. Gerraty 
874956e45f6SSimon J. Gerraty static void
8758695518cSSimon J. Gerraty doPrintVars(void)
8768695518cSSimon J. Gerraty {
877956e45f6SSimon J. Gerraty 	StringListNode *ln;
878b0c40a00SSimon J. Gerraty 	bool expandVars;
8798695518cSSimon J. Gerraty 
880e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_EXPANDED)
881b0c40a00SSimon J. Gerraty 		expandVars = true;
882956e45f6SSimon J. Gerraty 	else if (opts.debugVflag)
883b0c40a00SSimon J. Gerraty 		expandVars = false;
8848695518cSSimon J. Gerraty 	else
885b0c40a00SSimon J. Gerraty 		expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}",
886b0c40a00SSimon J. Gerraty 		    false);
8878695518cSSimon J. Gerraty 
88806b9b3e0SSimon J. Gerraty 	for (ln = opts.variables.first; ln != NULL; ln = ln->next) {
889956e45f6SSimon J. Gerraty 		const char *varname = ln->datum;
890956e45f6SSimon J. Gerraty 		PrintVar(varname, expandVars);
8918695518cSSimon J. Gerraty 	}
8928695518cSSimon J. Gerraty }
8938695518cSSimon J. Gerraty 
894b0c40a00SSimon J. Gerraty static bool
8958695518cSSimon J. Gerraty runTargets(void)
8968695518cSSimon J. Gerraty {
89706b9b3e0SSimon J. Gerraty 	GNodeList targs = LST_INIT;	/* target nodes to create */
898b0c40a00SSimon J. Gerraty 	bool outOfDate;		/* false if all targets up to date */
8998695518cSSimon J. Gerraty 
9008695518cSSimon J. Gerraty 	/*
9018695518cSSimon J. Gerraty 	 * Have now read the entire graph and need to make a list of
9028695518cSSimon J. Gerraty 	 * targets to create. If none was given on the command line,
9038695518cSSimon J. Gerraty 	 * we consult the parsing module to find the main target(s)
9048695518cSSimon J. Gerraty 	 * to create.
9058695518cSSimon J. Gerraty 	 */
90606b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create))
90706b9b3e0SSimon J. Gerraty 		Parse_MainName(&targs);
9088695518cSSimon J. Gerraty 	else
90906b9b3e0SSimon J. Gerraty 		Targ_FindList(&targs, &opts.create);
9108695518cSSimon J. Gerraty 
911956e45f6SSimon J. Gerraty 	if (!opts.compatMake) {
9128695518cSSimon J. Gerraty 		/*
9138695518cSSimon J. Gerraty 		 * Initialize job module before traversing the graph
9148695518cSSimon J. Gerraty 		 * now that any .BEGIN and .END targets have been read.
9158695518cSSimon J. Gerraty 		 * This is done only if the -q flag wasn't given
9168695518cSSimon J. Gerraty 		 * (to prevent the .BEGIN from being executed should
9178695518cSSimon J. Gerraty 		 * it exist).
9188695518cSSimon J. Gerraty 		 */
9199f45a3c8SSimon J. Gerraty 		if (!opts.query) {
9208695518cSSimon J. Gerraty 			Job_Init();
921b0c40a00SSimon J. Gerraty 			jobsRunning = true;
9228695518cSSimon J. Gerraty 		}
9238695518cSSimon J. Gerraty 
9248695518cSSimon J. Gerraty 		/* Traverse the graph, checking on all the targets */
92506b9b3e0SSimon J. Gerraty 		outOfDate = Make_Run(&targs);
9268695518cSSimon J. Gerraty 	} else {
927954401e6SSimon J. Gerraty 		Compat_MakeAll(&targs);
928b0c40a00SSimon J. Gerraty 		outOfDate = false;
9298695518cSSimon J. Gerraty 	}
930dba7b0efSSimon J. Gerraty 	Lst_Done(&targs);	/* Don't free the targets themselves. */
9318695518cSSimon J. Gerraty 	return outOfDate;
9328695518cSSimon J. Gerraty }
9338695518cSSimon J. Gerraty 
934956e45f6SSimon J. Gerraty /*
9359f45a3c8SSimon J. Gerraty  * Set up the .TARGETS variable to contain the list of targets to be created.
9369f45a3c8SSimon J. Gerraty  * If none specified, make the variable empty for now, the parser will fill
9379f45a3c8SSimon J. Gerraty  * in the default or .MAIN target later.
938956e45f6SSimon J. Gerraty  */
939956e45f6SSimon J. Gerraty static void
940956e45f6SSimon J. Gerraty InitVarTargets(void)
941956e45f6SSimon J. Gerraty {
942956e45f6SSimon J. Gerraty 	StringListNode *ln;
943956e45f6SSimon J. Gerraty 
94406b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create)) {
945dba7b0efSSimon J. Gerraty 		Global_Set(".TARGETS", "");
946956e45f6SSimon J. Gerraty 		return;
947956e45f6SSimon J. Gerraty 	}
948956e45f6SSimon J. Gerraty 
94906b9b3e0SSimon J. Gerraty 	for (ln = opts.create.first; ln != NULL; ln = ln->next) {
950dba7b0efSSimon J. Gerraty 		const char *name = ln->datum;
951dba7b0efSSimon J. Gerraty 		Global_Append(".TARGETS", name);
952956e45f6SSimon J. Gerraty 	}
953956e45f6SSimon J. Gerraty }
954956e45f6SSimon J. Gerraty 
955956e45f6SSimon J. Gerraty static void
956956e45f6SSimon J. Gerraty InitRandom(void)
957956e45f6SSimon J. Gerraty {
958956e45f6SSimon J. Gerraty 	struct timeval tv;
959956e45f6SSimon J. Gerraty 
960956e45f6SSimon J. Gerraty 	gettimeofday(&tv, NULL);
961956e45f6SSimon J. Gerraty 	srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
962956e45f6SSimon J. Gerraty }
963956e45f6SSimon J. Gerraty 
964956e45f6SSimon J. Gerraty static const char *
965dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED)
966956e45f6SSimon J. Gerraty {
967956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE
968e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE;
969956e45f6SSimon J. Gerraty #else
970956e45f6SSimon J. Gerraty     	const char *machine = getenv("MACHINE");
971e2eeea75SSimon J. Gerraty 
972956e45f6SSimon J. Gerraty 	if (machine != NULL)
973956e45f6SSimon J. Gerraty 		return machine;
974956e45f6SSimon J. Gerraty 
975e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE)
976956e45f6SSimon J. Gerraty 	return utsname->machine;
977e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE)
978956e45f6SSimon J. Gerraty 	return MAKE_MACHINE;
979956e45f6SSimon J. Gerraty #else
980956e45f6SSimon J. Gerraty 	return "unknown";
981956e45f6SSimon J. Gerraty #endif
982956e45f6SSimon J. Gerraty #endif
983956e45f6SSimon J. Gerraty }
984956e45f6SSimon J. Gerraty 
985956e45f6SSimon J. Gerraty static const char *
986e2eeea75SSimon J. Gerraty InitVarMachineArch(void)
987956e45f6SSimon J. Gerraty {
988e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH
989e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE_ARCH;
990e2eeea75SSimon J. Gerraty #else
991956e45f6SSimon J. Gerraty 	const char *env = getenv("MACHINE_ARCH");
992956e45f6SSimon J. Gerraty 	if (env != NULL)
993956e45f6SSimon J. Gerraty 		return env;
994956e45f6SSimon J. Gerraty 
995956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW)
996956e45f6SSimon J. Gerraty 	{
997956e45f6SSimon J. Gerraty 		struct utsname utsname;
998e2eeea75SSimon J. Gerraty 		static char machine_arch_buf[sizeof utsname.machine];
999956e45f6SSimon J. Gerraty 		const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
1000e2eeea75SSimon J. Gerraty 		size_t len = sizeof machine_arch_buf;
1001956e45f6SSimon J. Gerraty 
100206b9b3e0SSimon J. Gerraty 		if (sysctl(mib, (unsigned int)__arraycount(mib),
100306b9b3e0SSimon J. Gerraty 		    machine_arch_buf, &len, NULL, 0) < 0) {
100406b9b3e0SSimon J. Gerraty 			(void)fprintf(stderr, "%s: sysctl failed (%s).\n",
100506b9b3e0SSimon J. Gerraty 			    progname, strerror(errno));
1006956e45f6SSimon J. Gerraty 			exit(2);
1007956e45f6SSimon J. Gerraty 		}
1008956e45f6SSimon J. Gerraty 
1009956e45f6SSimon J. Gerraty 		return machine_arch_buf;
1010956e45f6SSimon J. Gerraty 	}
1011e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH)
1012e2eeea75SSimon J. Gerraty 	return MACHINE_ARCH;
1013e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH)
1014956e45f6SSimon J. Gerraty 	return MAKE_MACHINE_ARCH;
1015956e45f6SSimon J. Gerraty #else
1016956e45f6SSimon J. Gerraty 	return "unknown";
1017956e45f6SSimon J. Gerraty #endif
1018956e45f6SSimon J. Gerraty #endif
1019956e45f6SSimon J. Gerraty }
1020956e45f6SSimon J. Gerraty 
1021956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE
1022956e45f6SSimon J. Gerraty /*
1023956e45f6SSimon J. Gerraty  * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1024956e45f6SSimon J. Gerraty  * since the value of curdir can vary depending on how we got
1025d5e0a182SSimon J. Gerraty  * here.  That is, sitting at a shell prompt (shell that provides $PWD)
1026d5e0a182SSimon J. Gerraty  * or via subdir.mk, in which case it's likely a shell which does
1027956e45f6SSimon J. Gerraty  * not provide it.
1028956e45f6SSimon J. Gerraty  *
1029956e45f6SSimon J. Gerraty  * So, to stop it breaking this case only, we ignore PWD if
1030d5e0a182SSimon J. Gerraty  * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression.
1031956e45f6SSimon J. Gerraty  */
1032956e45f6SSimon J. Gerraty static void
1033956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st)
1034956e45f6SSimon J. Gerraty {
1035956e45f6SSimon J. Gerraty 	char *pwd;
10369f45a3c8SSimon J. Gerraty 	FStr makeobjdir;
1037956e45f6SSimon J. Gerraty 	struct stat pwd_st;
1038956e45f6SSimon J. Gerraty 
1039956e45f6SSimon J. Gerraty 	if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1040956e45f6SSimon J. Gerraty 		return;
1041956e45f6SSimon J. Gerraty 
10429f45a3c8SSimon J. Gerraty 	if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"))
1043956e45f6SSimon J. Gerraty 		return;
1044956e45f6SSimon J. Gerraty 
1045dba7b0efSSimon J. Gerraty 	makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR");
104606b9b3e0SSimon J. Gerraty 	if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
1047956e45f6SSimon J. Gerraty 		goto ignore_pwd;
1048956e45f6SSimon J. Gerraty 
1049956e45f6SSimon J. Gerraty 	if (stat(pwd, &pwd_st) == 0 &&
1050956e45f6SSimon J. Gerraty 	    curdir_st->st_ino == pwd_st.st_ino &&
1051956e45f6SSimon J. Gerraty 	    curdir_st->st_dev == pwd_st.st_dev)
10528d5c8e21SSimon J. Gerraty 		snprintf(curdir, MAXPATHLEN, "%s", pwd);
1053956e45f6SSimon J. Gerraty 
1054956e45f6SSimon J. Gerraty ignore_pwd:
105506b9b3e0SSimon J. Gerraty 	FStr_Done(&makeobjdir);
1056956e45f6SSimon J. Gerraty }
1057956e45f6SSimon J. Gerraty #endif
1058956e45f6SSimon J. Gerraty 
1059956e45f6SSimon J. Gerraty /*
10609f45a3c8SSimon J. Gerraty  * Find the .OBJDIR.  If MAKEOBJDIRPREFIX, or failing that, MAKEOBJDIR is set
10619f45a3c8SSimon J. Gerraty  * in the environment, try only that value and fall back to .CURDIR if it
10629f45a3c8SSimon J. Gerraty  * does not exist.
1063956e45f6SSimon J. Gerraty  *
1064956e45f6SSimon J. Gerraty  * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
10659f45a3c8SSimon J. Gerraty  * and finally _PATH_OBJDIRPREFIX`pwd`, in that order.  If none of these
10669f45a3c8SSimon J. Gerraty  * paths exist, just use .CURDIR.
1067956e45f6SSimon J. Gerraty  */
1068956e45f6SSimon J. Gerraty static void
1069956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch)
1070956e45f6SSimon J. Gerraty {
1071b0c40a00SSimon J. Gerraty 	bool writable;
1072956e45f6SSimon J. Gerraty 
107306b9b3e0SSimon J. Gerraty 	Dir_InitCur(curdir);
1074b0c40a00SSimon J. Gerraty 	writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true);
1075b0c40a00SSimon J. Gerraty 	(void)Main_SetObjdir(false, "%s", curdir);
1076e2eeea75SSimon J. Gerraty 
1077e2eeea75SSimon J. Gerraty 	if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
1078e2eeea75SSimon J. Gerraty 	    !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
1079e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1080e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
1081e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
1082e2eeea75SSimon J. Gerraty 		(void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
1083956e45f6SSimon J. Gerraty }
1084956e45f6SSimon J. Gerraty 
1085956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */
1086956e45f6SSimon J. Gerraty static void
1087956e45f6SSimon J. Gerraty UnlimitFiles(void)
1088956e45f6SSimon J. Gerraty {
108912904384SSimon J. Gerraty #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
1090956e45f6SSimon J. Gerraty 	struct rlimit rl;
1091956e45f6SSimon J. Gerraty 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1092956e45f6SSimon J. Gerraty 	    rl.rlim_cur != rl.rlim_max) {
10938c973ee2SSimon J. Gerraty #ifdef BMAKE_NOFILE_MAX
10948c973ee2SSimon J. Gerraty 		if (BMAKE_NOFILE_MAX < rl.rlim_max)
10958c973ee2SSimon J. Gerraty 			rl.rlim_cur = BMAKE_NOFILE_MAX;
10968c973ee2SSimon J. Gerraty 		else
10978c973ee2SSimon J. Gerraty #endif
1098956e45f6SSimon J. Gerraty 		rl.rlim_cur = rl.rlim_max;
1099956e45f6SSimon J. Gerraty 		(void)setrlimit(RLIMIT_NOFILE, &rl);
1100956e45f6SSimon J. Gerraty 	}
1101956e45f6SSimon J. Gerraty #endif
1102956e45f6SSimon J. Gerraty }
1103956e45f6SSimon J. Gerraty 
1104956e45f6SSimon J. Gerraty static void
1105956e45f6SSimon J. Gerraty CmdOpts_Init(void)
1106956e45f6SSimon J. Gerraty {
1107b0c40a00SSimon J. Gerraty 	opts.compatMake = false;
11089f45a3c8SSimon J. Gerraty 	memset(&opts.debug, 0, sizeof(opts.debug));
1109dba7b0efSSimon J. Gerraty 	/* opts.debug_file has already been initialized earlier */
1110b0c40a00SSimon J. Gerraty 	opts.strict = false;
1111b0c40a00SSimon J. Gerraty 	opts.debugVflag = false;
1112b0c40a00SSimon J. Gerraty 	opts.checkEnvFirst = false;
111306b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.makefiles);
1114b0c40a00SSimon J. Gerraty 	opts.ignoreErrors = false;	/* Pay attention to non-zero returns */
111506b9b3e0SSimon J. Gerraty 	opts.maxJobs = 1;
1116b0c40a00SSimon J. Gerraty 	opts.keepgoing = false;		/* Stop on error */
1117b0c40a00SSimon J. Gerraty 	opts.noRecursiveExecute = false; /* Execute all .MAKE targets */
1118b0c40a00SSimon J. Gerraty 	opts.noExecute = false;		/* Execute all commands */
11199f45a3c8SSimon J. Gerraty 	opts.query = false;
1120b0c40a00SSimon J. Gerraty 	opts.noBuiltins = false;	/* Read the built-in rules */
11219f45a3c8SSimon J. Gerraty 	opts.silent = false;		/* Print commands as executed */
11229f45a3c8SSimon J. Gerraty 	opts.touch = false;
1123e2eeea75SSimon J. Gerraty 	opts.printVars = PVM_NONE;
112406b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.variables);
1125b0c40a00SSimon J. Gerraty 	opts.parseWarnFatal = false;
1126b0c40a00SSimon J. Gerraty 	opts.enterFlag = false;
1127b0c40a00SSimon J. Gerraty 	opts.varNoExportEnv = false;
112806b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.create);
1129956e45f6SSimon J. Gerraty }
1130956e45f6SSimon J. Gerraty 
113106b9b3e0SSimon J. Gerraty /*
113206b9b3e0SSimon J. Gerraty  * Initialize MAKE and .MAKE to the path of the executable, so that it can be
1133956e45f6SSimon J. Gerraty  * found by execvp(3) and the shells, even after a chdir.
1134956e45f6SSimon J. Gerraty  *
1135956e45f6SSimon J. Gerraty  * If it's a relative path and contains a '/', resolve it to an absolute path.
113606b9b3e0SSimon J. Gerraty  * Otherwise keep it as is, assuming it will be found in the PATH.
113706b9b3e0SSimon J. Gerraty  */
1138956e45f6SSimon J. Gerraty static void
1139956e45f6SSimon J. Gerraty InitVarMake(const char *argv0)
1140956e45f6SSimon J. Gerraty {
1141956e45f6SSimon J. Gerraty 	const char *make = argv0;
11428d5c8e21SSimon J. Gerraty 	char pathbuf[MAXPATHLEN];
1143956e45f6SSimon J. Gerraty 
1144956e45f6SSimon J. Gerraty 	if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
114506b9b3e0SSimon J. Gerraty 		const char *abspath = cached_realpath(argv0, pathbuf);
1146956e45f6SSimon J. Gerraty 		struct stat st;
114706b9b3e0SSimon J. Gerraty 		if (abspath != NULL && abspath[0] == '/' &&
114806b9b3e0SSimon J. Gerraty 		    stat(make, &st) == 0)
114906b9b3e0SSimon J. Gerraty 			make = abspath;
1150956e45f6SSimon J. Gerraty 	}
1151956e45f6SSimon J. Gerraty 
1152dba7b0efSSimon J. Gerraty 	Global_Set("MAKE", make);
1153dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE", make);
1154956e45f6SSimon J. Gerraty }
1155956e45f6SSimon J. Gerraty 
115606b9b3e0SSimon J. Gerraty /*
115706b9b3e0SSimon J. Gerraty  * Add the directories from the colon-separated syspath to defSysIncPath.
115806b9b3e0SSimon J. Gerraty  * After returning, the contents of syspath is unspecified.
115906b9b3e0SSimon J. Gerraty  */
1160956e45f6SSimon J. Gerraty static void
1161956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath)
1162956e45f6SSimon J. Gerraty {
1163956e45f6SSimon J. Gerraty 	static char defsyspath[] = _PATH_DEFSYSPATH;
1164d5e0a182SSimon J. Gerraty 	char *start, *p;
1165956e45f6SSimon J. Gerraty 
1166956e45f6SSimon J. Gerraty 	/*
1167956e45f6SSimon J. Gerraty 	 * If no user-supplied system path was given (through the -m option)
1168956e45f6SSimon J. Gerraty 	 * add the directories from the DEFSYSPATH (more than one may be given
1169956e45f6SSimon J. Gerraty 	 * as dir1:...:dirn) to the system include path.
1170956e45f6SSimon J. Gerraty 	 */
1171956e45f6SSimon J. Gerraty 	if (syspath == NULL || syspath[0] == '\0')
1172956e45f6SSimon J. Gerraty 		syspath = defsyspath;
1173956e45f6SSimon J. Gerraty 	else
1174956e45f6SSimon J. Gerraty 		syspath = bmake_strdup(syspath);
1175956e45f6SSimon J. Gerraty 
1176d5e0a182SSimon J. Gerraty 	for (start = syspath; *start != '\0'; start = p) {
1177d5e0a182SSimon J. Gerraty 		for (p = start; *p != '\0' && *p != ':'; p++)
1178956e45f6SSimon J. Gerraty 			continue;
1179d5e0a182SSimon J. Gerraty 		if (*p == ':')
1180d5e0a182SSimon J. Gerraty 			*p++ = '\0';
1181e2eeea75SSimon J. Gerraty 
1182956e45f6SSimon J. Gerraty 		/* look for magic parent directory search string */
1183e2eeea75SSimon J. Gerraty 		if (strncmp(start, ".../", 4) == 0) {
1184956e45f6SSimon J. Gerraty 			char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1185956e45f6SSimon J. Gerraty 			if (dir != NULL) {
1186dba7b0efSSimon J. Gerraty 				(void)SearchPath_Add(defSysIncPath, dir);
1187956e45f6SSimon J. Gerraty 				free(dir);
1188956e45f6SSimon J. Gerraty 			}
1189e2eeea75SSimon J. Gerraty 		} else {
1190dba7b0efSSimon J. Gerraty 			(void)SearchPath_Add(defSysIncPath, start);
1191956e45f6SSimon J. Gerraty 		}
1192956e45f6SSimon J. Gerraty 	}
1193956e45f6SSimon J. Gerraty 
1194956e45f6SSimon J. Gerraty 	if (syspath != defsyspath)
1195956e45f6SSimon J. Gerraty 		free(syspath);
1196956e45f6SSimon J. Gerraty }
1197956e45f6SSimon J. Gerraty 
1198956e45f6SSimon J. Gerraty static void
1199956e45f6SSimon J. Gerraty ReadBuiltinRules(void)
1200956e45f6SSimon J. Gerraty {
1201e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1202dba7b0efSSimon J. Gerraty 	StringList sysMkFiles = LST_INIT;
1203e2eeea75SSimon J. Gerraty 
1204dba7b0efSSimon J. Gerraty 	SearchPath_Expand(
1205dba7b0efSSimon J. Gerraty 	    Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath,
1206dba7b0efSSimon J. Gerraty 	    _PATH_DEFSYSMK,
1207dba7b0efSSimon J. Gerraty 	    &sysMkFiles);
1208dba7b0efSSimon J. Gerraty 	if (Lst_IsEmpty(&sysMkFiles))
1209956e45f6SSimon J. Gerraty 		Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1210e2eeea75SSimon J. Gerraty 
1211dba7b0efSSimon J. Gerraty 	for (ln = sysMkFiles.first; ln != NULL; ln = ln->next)
12129f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1213e2eeea75SSimon J. Gerraty 			break;
1214e2eeea75SSimon J. Gerraty 
1215e2eeea75SSimon J. Gerraty 	if (ln == NULL)
1216e2eeea75SSimon J. Gerraty 		Fatal("%s: cannot open %s.",
1217dba7b0efSSimon J. Gerraty 		    progname, (const char *)sysMkFiles.first->datum);
1218e2eeea75SSimon J. Gerraty 
1219548bfc56SSimon J. Gerraty 	Lst_DoneFree(&sysMkFiles);
1220956e45f6SSimon J. Gerraty }
1221956e45f6SSimon J. Gerraty 
1222956e45f6SSimon J. Gerraty static void
1223956e45f6SSimon J. Gerraty InitMaxJobs(void)
1224956e45f6SSimon J. Gerraty {
1225956e45f6SSimon J. Gerraty 	char *value;
1226956e45f6SSimon J. Gerraty 	int n;
1227956e45f6SSimon J. Gerraty 
1228956e45f6SSimon J. Gerraty 	if (forceJobs || opts.compatMake ||
1229dba7b0efSSimon J. Gerraty 	    !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
1230956e45f6SSimon J. Gerraty 		return;
1231956e45f6SSimon J. Gerraty 
12328d5c8e21SSimon J. Gerraty 	value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_EVAL);
1233956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1234956e45f6SSimon J. Gerraty 	n = (int)strtol(value, NULL, 0);
1235956e45f6SSimon J. Gerraty 	if (n < 1) {
1236956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
1237956e45f6SSimon J. Gerraty 		    "%s: illegal value for .MAKE.JOBS "
1238956e45f6SSimon J. Gerraty 		    "-- must be positive integer!\n",
1239956e45f6SSimon J. Gerraty 		    progname);
124006b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
1241956e45f6SSimon J. Gerraty 	}
1242956e45f6SSimon J. Gerraty 
1243956e45f6SSimon J. Gerraty 	if (n != opts.maxJobs) {
1244dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-j");
1245dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, value);
1246956e45f6SSimon J. Gerraty 	}
1247956e45f6SSimon J. Gerraty 
1248956e45f6SSimon J. Gerraty 	opts.maxJobs = n;
1249956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1250b0c40a00SSimon J. Gerraty 	forceJobs = true;
1251956e45f6SSimon J. Gerraty 	free(value);
1252956e45f6SSimon J. Gerraty }
1253956e45f6SSimon J. Gerraty 
1254956e45f6SSimon J. Gerraty /*
1255956e45f6SSimon J. Gerraty  * For compatibility, look at the directories in the VPATH variable
1256956e45f6SSimon J. Gerraty  * and add them to the search path, if the variable is defined. The
1257956e45f6SSimon J. Gerraty  * variable's value is in the same format as the PATH environment
1258956e45f6SSimon J. Gerraty  * variable, i.e. <directory>:<directory>:<directory>...
1259956e45f6SSimon J. Gerraty  */
1260956e45f6SSimon J. Gerraty static void
1261956e45f6SSimon J. Gerraty InitVpath(void)
1262956e45f6SSimon J. Gerraty {
1263956e45f6SSimon J. Gerraty 	char *vpath, savec, *path;
1264dba7b0efSSimon J. Gerraty 	if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
1265956e45f6SSimon J. Gerraty 		return;
1266956e45f6SSimon J. Gerraty 
12678d5c8e21SSimon J. Gerraty 	vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_EVAL);
1268956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1269956e45f6SSimon J. Gerraty 	path = vpath;
1270956e45f6SSimon J. Gerraty 	do {
1271d5e0a182SSimon J. Gerraty 		char *p;
1272956e45f6SSimon J. Gerraty 		/* skip to end of directory */
1273d5e0a182SSimon J. Gerraty 		for (p = path; *p != ':' && *p != '\0'; p++)
1274956e45f6SSimon J. Gerraty 			continue;
1275956e45f6SSimon J. Gerraty 		/* Save terminator character so know when to stop */
1276d5e0a182SSimon J. Gerraty 		savec = *p;
1277d5e0a182SSimon J. Gerraty 		*p = '\0';
1278956e45f6SSimon J. Gerraty 		/* Add directory to search path */
1279dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(&dirSearchPath, path);
1280d5e0a182SSimon J. Gerraty 		*p = savec;
1281d5e0a182SSimon J. Gerraty 		path = p + 1;
1282956e45f6SSimon J. Gerraty 	} while (savec == ':');
1283956e45f6SSimon J. Gerraty 	free(vpath);
1284956e45f6SSimon J. Gerraty }
1285956e45f6SSimon J. Gerraty 
1286956e45f6SSimon J. Gerraty static void
12879f45a3c8SSimon J. Gerraty ReadAllMakefiles(const StringList *makefiles)
1288956e45f6SSimon J. Gerraty {
1289956e45f6SSimon J. Gerraty 	StringListNode *ln;
1290956e45f6SSimon J. Gerraty 
1291e2eeea75SSimon J. Gerraty 	for (ln = makefiles->first; ln != NULL; ln = ln->next) {
1292e2eeea75SSimon J. Gerraty 		const char *fname = ln->datum;
12939f45a3c8SSimon J. Gerraty 		if (!ReadMakefile(fname))
1294e2eeea75SSimon J. Gerraty 			Fatal("%s: cannot open %s.", progname, fname);
1295956e45f6SSimon J. Gerraty 	}
1296956e45f6SSimon J. Gerraty }
1297956e45f6SSimon J. Gerraty 
1298956e45f6SSimon J. Gerraty static void
1299e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void)
1300956e45f6SSimon J. Gerraty {
13019f45a3c8SSimon J. Gerraty 	StringList makefiles = LST_INIT;
1302e2eeea75SSimon J. Gerraty 	StringListNode *ln;
13038c973ee2SSimon J. Gerraty 	char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
13048d5c8e21SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_EVAL);
1305e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
1306956e45f6SSimon J. Gerraty 
1307d5e0a182SSimon J. Gerraty 	AppendWords(&makefiles, prefs);
1308956e45f6SSimon J. Gerraty 
13099f45a3c8SSimon J. Gerraty 	for (ln = makefiles.first; ln != NULL; ln = ln->next)
13109f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1311e2eeea75SSimon J. Gerraty 			break;
1312956e45f6SSimon J. Gerraty 
13139f45a3c8SSimon J. Gerraty 	Lst_Done(&makefiles);
1314e2eeea75SSimon J. Gerraty 	free(prefs);
1315956e45f6SSimon J. Gerraty }
1316956e45f6SSimon J. Gerraty 
131706b9b3e0SSimon J. Gerraty /*
131806b9b3e0SSimon J. Gerraty  * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
1319e2eeea75SSimon J. Gerraty  * Initialize a few modules.
132006b9b3e0SSimon J. Gerraty  * Parse the arguments from MAKEFLAGS and the command line.
132106b9b3e0SSimon J. Gerraty  */
1322e2eeea75SSimon J. Gerraty static void
1323e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv)
13243955d011SMarcel Moolenaar {
1325956e45f6SSimon J. Gerraty 	struct stat sa;
1326956e45f6SSimon J. Gerraty 	const char *machine;
1327956e45f6SSimon J. Gerraty 	const char *machine_arch;
13283955d011SMarcel Moolenaar 	char *syspath = getenv("MAKESYSPATH");
13293955d011SMarcel Moolenaar 	struct utsname utsname;
13303955d011SMarcel Moolenaar 
13313955d011SMarcel Moolenaar 	/* default to writing debug to stderr */
1332956e45f6SSimon J. Gerraty 	opts.debug_file = stderr;
13333955d011SMarcel Moolenaar 
13349f45a3c8SSimon J. Gerraty 	Str_Intern_Init();
1335e2eeea75SSimon J. Gerraty 	HashTable_Init(&cached_realpaths);
1336e2eeea75SSimon J. Gerraty 
13373955d011SMarcel Moolenaar #ifdef SIGINFO
13383955d011SMarcel Moolenaar 	(void)bmake_signal(SIGINFO, siginfo);
13393955d011SMarcel Moolenaar #endif
1340956e45f6SSimon J. Gerraty 
1341956e45f6SSimon J. Gerraty 	InitRandom();
13423955d011SMarcel Moolenaar 
134306b9b3e0SSimon J. Gerraty 	progname = str_basename(argv[0]);
1344956e45f6SSimon J. Gerraty 
1345956e45f6SSimon J. Gerraty 	UnlimitFiles();
13463955d011SMarcel Moolenaar 
13471748de26SSimon J. Gerraty 	if (uname(&utsname) == -1) {
13481748de26SSimon J. Gerraty 		(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
13491748de26SSimon J. Gerraty 		    strerror(errno));
13501748de26SSimon J. Gerraty 		exit(2);
13511748de26SSimon J. Gerraty 	}
13521748de26SSimon J. Gerraty 
1353e2eeea75SSimon J. Gerraty 	machine = InitVarMachine(&utsname);
1354e2eeea75SSimon J. Gerraty 	machine_arch = InitVarMachineArch();
13553955d011SMarcel Moolenaar 
13563955d011SMarcel Moolenaar 	myPid = getpid();	/* remember this for vFork() */
13573955d011SMarcel Moolenaar 
1358d5e0a182SSimon J. Gerraty 	/* Just in case MAKEOBJDIR wants us to do something tricky. */
1359e2eeea75SSimon J. Gerraty 	Targ_Init();
1360548bfc56SSimon J. Gerraty #ifdef FORCE_MAKE_OS
1361548bfc56SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.OS", FORCE_MAKE_OS);
1362548bfc56SSimon J. Gerraty #else
13634fde40d9SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.OS", utsname.sysname);
1364548bfc56SSimon J. Gerraty #endif
1365dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE", machine);
1366dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE_ARCH", machine_arch);
13673955d011SMarcel Moolenaar #ifdef MAKE_VERSION
1368dba7b0efSSimon J. Gerraty 	Global_Set("MAKE_VERSION", MAKE_VERSION);
13693955d011SMarcel Moolenaar #endif
1370d5e0a182SSimon J. Gerraty 	Global_Set_ReadOnly(".newline", "\n");
13713955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST
13729f45a3c8SSimon J. Gerraty 	/* This is the traditional preference for makefiles. */
13733955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
13743955d011SMarcel Moolenaar #endif
13758c973ee2SSimon J. Gerraty 	Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST);
13764fde40d9SSimon J. Gerraty 	Global_Set(".MAKE.DEPENDFILE", ".depend");
137798875883SSimon J. Gerraty 	/* Tell makefiles like jobs.mk whether we support -jC */
137898875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
137998875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "yes");
138098875883SSimon J. Gerraty #else
138198875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "no");
138298875883SSimon J. Gerraty #endif
13833955d011SMarcel Moolenaar 
1384956e45f6SSimon J. Gerraty 	CmdOpts_Init();
1385b0c40a00SSimon J. Gerraty 	allPrecious = false;	/* Remove targets when interrupted */
1386b0c40a00SSimon J. Gerraty 	deleteOnError = false;	/* Historical default behavior */
1387b0c40a00SSimon J. Gerraty 	jobsRunning = false;
13883955d011SMarcel Moolenaar 
1389956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1390b0c40a00SSimon J. Gerraty 	ignorePWD = false;
13913955d011SMarcel Moolenaar 
13923955d011SMarcel Moolenaar 	/*
13933955d011SMarcel Moolenaar 	 * Initialize the parsing, directory and variable modules to prepare
13943955d011SMarcel Moolenaar 	 * for the reading of inclusion paths and variable settings on the
13953955d011SMarcel Moolenaar 	 * command line
13963955d011SMarcel Moolenaar 	 */
13973955d011SMarcel Moolenaar 
13983955d011SMarcel Moolenaar 	/*
13993955d011SMarcel Moolenaar 	 * Initialize various variables.
14003955d011SMarcel Moolenaar 	 *	MAKE also gets this name, for compatibility
14013955d011SMarcel Moolenaar 	 *	.MAKEFLAGS gets set to the empty string just in case.
14023955d011SMarcel Moolenaar 	 *	MFLAGS also gets initialized empty, for compatibility.
14033955d011SMarcel Moolenaar 	 */
14043955d011SMarcel Moolenaar 	Parse_Init();
1405956e45f6SSimon J. Gerraty 	InitVarMake(argv[0]);
1406dba7b0efSSimon J. Gerraty 	Global_Set(MAKEFLAGS, "");
14078c973ee2SSimon J. Gerraty 	Global_Set(".MAKEOVERRIDES", "");
1408dba7b0efSSimon J. Gerraty 	Global_Set("MFLAGS", "");
1409dba7b0efSSimon J. Gerraty 	Global_Set(".ALLTARGETS", "");
1410c9f4001fSSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV);
14113955d011SMarcel Moolenaar 
1412e2eeea75SSimon J. Gerraty 	/* Set some other useful variables. */
14133955d011SMarcel Moolenaar 	{
14146a7405f5SSimon J. Gerraty 		char buf[64];
14156a7405f5SSimon J. Gerraty 		const char *ep = getenv(MAKE_LEVEL_ENV);
14163955d011SMarcel Moolenaar 
1417e2eeea75SSimon J. Gerraty 		makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
141851ee2c1cSSimon J. Gerraty 		if (makelevel < 0)
141951ee2c1cSSimon J. Gerraty 			makelevel = 0;
14209f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%d", makelevel);
14218c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.LEVEL", buf);
14229f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", myPid);
14234fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PID", buf);
14249f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getppid());
14254fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PPID", buf);
14269f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getuid());
14274fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.UID", buf);
14289f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getgid());
14294fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.GID", buf);
14303955d011SMarcel Moolenaar 	}
143151ee2c1cSSimon J. Gerraty 	if (makelevel > 0) {
143251ee2c1cSSimon J. Gerraty 		char pn[1024];
1433e2eeea75SSimon J. Gerraty 		snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
143451ee2c1cSSimon J. Gerraty 		progname = bmake_strdup(pn);
143551ee2c1cSSimon J. Gerraty 	}
14363955d011SMarcel Moolenaar 
14371748de26SSimon J. Gerraty #ifdef USE_META
14381748de26SSimon J. Gerraty 	meta_init();
14391748de26SSimon J. Gerraty #endif
14402c3632d1SSimon J. Gerraty 	Dir_Init();
14411ce939a7SSimon J. Gerraty 
14429f45a3c8SSimon J. Gerraty 	{
14439f45a3c8SSimon J. Gerraty 		char *makeflags = explode(getenv("MAKEFLAGS"));
14449f45a3c8SSimon J. Gerraty 		Main_ParseArgLine(makeflags);
14459f45a3c8SSimon J. Gerraty 		free(makeflags);
14469f45a3c8SSimon J. Gerraty 	}
14473955d011SMarcel Moolenaar 
14483955d011SMarcel Moolenaar 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
14493955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: getcwd: %s.\n",
14503955d011SMarcel Moolenaar 		    progname, strerror(errno));
14513955d011SMarcel Moolenaar 		exit(2);
14523955d011SMarcel Moolenaar 	}
14533955d011SMarcel Moolenaar 
14543955d011SMarcel Moolenaar 	MainParseArgs(argc, argv);
14553955d011SMarcel Moolenaar 
1456956e45f6SSimon J. Gerraty 	if (opts.enterFlag)
145751ee2c1cSSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, curdir);
145851ee2c1cSSimon J. Gerraty 
14593955d011SMarcel Moolenaar 	if (stat(curdir, &sa) == -1) {
14603955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: %s: %s.\n",
14613955d011SMarcel Moolenaar 		    progname, curdir, strerror(errno));
14623955d011SMarcel Moolenaar 		exit(2);
14633955d011SMarcel Moolenaar 	}
14643955d011SMarcel Moolenaar 
14653955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE
1466956e45f6SSimon J. Gerraty 	HandlePWD(&sa);
14673955d011SMarcel Moolenaar #endif
1468dba7b0efSSimon J. Gerraty 	Global_Set(".CURDIR", curdir);
14693955d011SMarcel Moolenaar 
1470956e45f6SSimon J. Gerraty 	InitObjdir(machine, machine_arch);
14713955d011SMarcel Moolenaar 
14723955d011SMarcel Moolenaar 	Arch_Init();
14733955d011SMarcel Moolenaar 	Suff_Init();
14743955d011SMarcel Moolenaar 	Trace_Init(tracefile);
14753955d011SMarcel Moolenaar 
1476e2eeea75SSimon J. Gerraty 	defaultNode = NULL;
14773955d011SMarcel Moolenaar 	(void)time(&now);
14783955d011SMarcel Moolenaar 
14793955d011SMarcel Moolenaar 	Trace_Log(MAKESTART, NULL);
14803955d011SMarcel Moolenaar 
1481956e45f6SSimon J. Gerraty 	InitVarTargets();
14823955d011SMarcel Moolenaar 
1483956e45f6SSimon J. Gerraty 	InitDefSysIncPath(syspath);
1484e2eeea75SSimon J. Gerraty }
14853955d011SMarcel Moolenaar 
148606b9b3e0SSimon J. Gerraty /*
148706b9b3e0SSimon J. Gerraty  * Read the system makefile followed by either makefile, Makefile or the
148806b9b3e0SSimon J. Gerraty  * files given by the -f option. Exit on parse errors.
148906b9b3e0SSimon J. Gerraty  */
1490e2eeea75SSimon J. Gerraty static void
1491e2eeea75SSimon J. Gerraty main_ReadFiles(void)
1492e2eeea75SSimon J. Gerraty {
1493e2eeea75SSimon J. Gerraty 
14944fde40d9SSimon J. Gerraty 	if (Lst_IsEmpty(&sysIncPath->dirs))
14954fde40d9SSimon J. Gerraty 		SearchPath_AddAll(sysIncPath, defSysIncPath);
14964fde40d9SSimon J. Gerraty 
14974fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
1498956e45f6SSimon J. Gerraty 	if (!opts.noBuiltins)
1499956e45f6SSimon J. Gerraty 		ReadBuiltinRules();
15003955d011SMarcel Moolenaar 
15012f2a5ecdSSimon J. Gerraty 	posix_state = PS_MAYBE_NEXT_LINE;
150206b9b3e0SSimon J. Gerraty 	if (!Lst_IsEmpty(&opts.makefiles))
150306b9b3e0SSimon J. Gerraty 		ReadAllMakefiles(&opts.makefiles);
1504e2eeea75SSimon J. Gerraty 	else
1505e2eeea75SSimon J. Gerraty 		ReadFirstDefaultMakefile();
1506e2eeea75SSimon J. Gerraty }
1507e2eeea75SSimon J. Gerraty 
1508e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */
1509e2eeea75SSimon J. Gerraty static void
1510e2eeea75SSimon J. Gerraty main_PrepareMaking(void)
1511e2eeea75SSimon J. Gerraty {
15123955d011SMarcel Moolenaar 	/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1513e2eeea75SSimon J. Gerraty 	if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
15148c973ee2SSimon J. Gerraty 		makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
15158d5c8e21SSimon J. Gerraty 		    SCOPE_CMDLINE, VARE_EVAL);
1516956e45f6SSimon J. Gerraty 		if (makeDependfile[0] != '\0') {
1517956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
1518b0c40a00SSimon J. Gerraty 			doing_depend = true;
15192c3632d1SSimon J. Gerraty 			(void)ReadMakefile(makeDependfile);
1520b0c40a00SSimon J. Gerraty 			doing_depend = false;
15213955d011SMarcel Moolenaar 		}
1522956e45f6SSimon J. Gerraty 	}
15233955d011SMarcel Moolenaar 
15244c620fe5SSimon J. Gerraty 	if (enterFlagObj)
15254c620fe5SSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, objdir);
15264c620fe5SSimon J. Gerraty 
152706b9b3e0SSimon J. Gerraty 	MakeMode();
15283955d011SMarcel Moolenaar 
1529956e45f6SSimon J. Gerraty 	{
1530dba7b0efSSimon J. Gerraty 		FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS);
1531dba7b0efSSimon J. Gerraty 		Global_Append("MFLAGS", makeflags.str);
153206b9b3e0SSimon J. Gerraty 		FStr_Done(&makeflags);
1533956e45f6SSimon J. Gerraty 	}
1534e48f47ddSSimon J. Gerraty 
1535956e45f6SSimon J. Gerraty 	InitMaxJobs();
1536e48f47ddSSimon J. Gerraty 
1537e2eeea75SSimon J. Gerraty 	if (!opts.compatMake && !forceJobs)
1538b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
1539e48f47ddSSimon J. Gerraty 
1540956e45f6SSimon J. Gerraty 	if (!opts.compatMake)
15413955d011SMarcel Moolenaar 		Job_ServerStart(maxJobTokens, jp_0, jp_1);
1542956e45f6SSimon J. Gerraty 	DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1543956e45f6SSimon J. Gerraty 	    jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
15443955d011SMarcel Moolenaar 
1545e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_NONE)
1546b0c40a00SSimon J. Gerraty 		Main_ExportMAKEFLAGS(true);	/* initial export */
15473955d011SMarcel Moolenaar 
1548956e45f6SSimon J. Gerraty 	InitVpath();
15493955d011SMarcel Moolenaar 
15503955d011SMarcel Moolenaar 	/*
15513955d011SMarcel Moolenaar 	 * Now that all search paths have been read for suffixes et al, it's
15523955d011SMarcel Moolenaar 	 * time to add the default search path to their lists...
15533955d011SMarcel Moolenaar 	 */
1554b0c40a00SSimon J. Gerraty 	Suff_ExtendPaths();
15553955d011SMarcel Moolenaar 
15563955d011SMarcel Moolenaar 	/*
15573955d011SMarcel Moolenaar 	 * Propagate attributes through :: dependency lists.
15583955d011SMarcel Moolenaar 	 */
15593955d011SMarcel Moolenaar 	Targ_Propagate();
15603955d011SMarcel Moolenaar 
15613955d011SMarcel Moolenaar 	/* print the initial graph, if the user requested it */
15623955d011SMarcel Moolenaar 	if (DEBUG(GRAPH1))
15633955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
15643955d011SMarcel Moolenaar }
15653955d011SMarcel Moolenaar 
156606b9b3e0SSimon J. Gerraty /*
156706b9b3e0SSimon J. Gerraty  * Make the targets.
1568e2eeea75SSimon J. Gerraty  * If the -v or -V options are given, print variables instead.
156906b9b3e0SSimon J. Gerraty  * Return whether any of the targets is out-of-date.
157006b9b3e0SSimon J. Gerraty  */
1571b0c40a00SSimon J. Gerraty static bool
1572e2eeea75SSimon J. Gerraty main_Run(void)
1573e2eeea75SSimon J. Gerraty {
1574e2eeea75SSimon J. Gerraty 	if (opts.printVars != PVM_NONE) {
1575e2eeea75SSimon J. Gerraty 		/* print the values of any variables requested by the user */
1576e2eeea75SSimon J. Gerraty 		doPrintVars();
1577b0c40a00SSimon J. Gerraty 		return false;
1578e2eeea75SSimon J. Gerraty 	} else {
1579e2eeea75SSimon J. Gerraty 		return runTargets();
1580e2eeea75SSimon J. Gerraty 	}
1581e2eeea75SSimon J. Gerraty }
15823955d011SMarcel Moolenaar 
1583e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */
1584e2eeea75SSimon J. Gerraty static void
1585e2eeea75SSimon J. Gerraty main_CleanUp(void)
1586e2eeea75SSimon J. Gerraty {
1587e2eeea75SSimon J. Gerraty #ifdef CLEANUP
1588548bfc56SSimon J. Gerraty 	Lst_DoneFree(&opts.variables);
1589548bfc56SSimon J. Gerraty 	Lst_DoneFree(&opts.makefiles);
1590548bfc56SSimon J. Gerraty 	Lst_DoneFree(&opts.create);
1591e2eeea75SSimon J. Gerraty #endif
1592e2eeea75SSimon J. Gerraty 
1593e2eeea75SSimon J. Gerraty 	if (DEBUG(GRAPH2))
1594e2eeea75SSimon J. Gerraty 		Targ_PrintGraph(2);
1595e2eeea75SSimon J. Gerraty 
1596e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEEND, NULL);
1597e2eeea75SSimon J. Gerraty 
1598e2eeea75SSimon J. Gerraty 	if (enterFlagObj)
1599e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, objdir);
1600e2eeea75SSimon J. Gerraty 	if (opts.enterFlag)
1601e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, curdir);
1602e2eeea75SSimon J. Gerraty 
160322619282SSimon J. Gerraty 	Var_Stats();
160422619282SSimon J. Gerraty 	Targ_Stats();
160522619282SSimon J. Gerraty 
1606e2eeea75SSimon J. Gerraty #ifdef USE_META
1607e2eeea75SSimon J. Gerraty 	meta_finish();
1608e2eeea75SSimon J. Gerraty #endif
160922619282SSimon J. Gerraty #ifdef CLEANUP
1610e2eeea75SSimon J. Gerraty 	Suff_End();
1611e2eeea75SSimon J. Gerraty 	Targ_End();
1612e2eeea75SSimon J. Gerraty 	Arch_End();
1613e2eeea75SSimon J. Gerraty 	Parse_End();
1614e2eeea75SSimon J. Gerraty 	Dir_End();
1615e2eeea75SSimon J. Gerraty 	Job_End();
161622619282SSimon J. Gerraty #endif
1617e2eeea75SSimon J. Gerraty 	Trace_End();
161822619282SSimon J. Gerraty #ifdef CLEANUP
16199f45a3c8SSimon J. Gerraty 	Str_Intern_End();
162022619282SSimon J. Gerraty #endif
1621e2eeea75SSimon J. Gerraty }
1622e2eeea75SSimon J. Gerraty 
1623e2eeea75SSimon J. Gerraty /* Determine the exit code. */
1624e2eeea75SSimon J. Gerraty static int
1625b0c40a00SSimon J. Gerraty main_Exit(bool outOfDate)
1626e2eeea75SSimon J. Gerraty {
162722619282SSimon J. Gerraty 	if ((opts.strict && main_errors > 0) || parseErrors > 0)
1628956e45f6SSimon J. Gerraty 		return 2;	/* Not 1 so -q can distinguish error */
16293955d011SMarcel Moolenaar 	return outOfDate ? 1 : 0;
16303955d011SMarcel Moolenaar }
16313955d011SMarcel Moolenaar 
1632e2eeea75SSimon J. Gerraty int
1633e2eeea75SSimon J. Gerraty main(int argc, char **argv)
1634e2eeea75SSimon J. Gerraty {
1635b0c40a00SSimon J. Gerraty 	bool outOfDate;
1636e2eeea75SSimon J. Gerraty 
1637e2eeea75SSimon J. Gerraty 	main_Init(argc, argv);
1638e2eeea75SSimon J. Gerraty 	main_ReadFiles();
1639e2eeea75SSimon J. Gerraty 	main_PrepareMaking();
1640e2eeea75SSimon J. Gerraty 	outOfDate = main_Run();
1641e2eeea75SSimon J. Gerraty 	main_CleanUp();
1642e2eeea75SSimon J. Gerraty 	return main_Exit(outOfDate);
1643e2eeea75SSimon J. Gerraty }
1644e2eeea75SSimon J. Gerraty 
164506b9b3e0SSimon J. Gerraty /*
164606b9b3e0SSimon J. Gerraty  * Open and parse the given makefile, with all its side effects.
16479f45a3c8SSimon J. Gerraty  * Return false if the file could not be opened.
16483955d011SMarcel Moolenaar  */
16499f45a3c8SSimon J. Gerraty static bool
16502c3632d1SSimon J. Gerraty ReadMakefile(const char *fname)
16513955d011SMarcel Moolenaar {
16523955d011SMarcel Moolenaar 	int fd;
16532c3632d1SSimon J. Gerraty 	char *name, *path = NULL;
16543955d011SMarcel Moolenaar 
1655e2eeea75SSimon J. Gerraty 	if (strcmp(fname, "-") == 0) {
16569f45a3c8SSimon J. Gerraty 		Parse_File("(stdin)", -1);
1657dba7b0efSSimon J. Gerraty 		Var_Set(SCOPE_INTERNAL, "MAKEFILE", "");
16583955d011SMarcel Moolenaar 	} else {
16596a7405f5SSimon J. Gerraty 		if (strncmp(fname, ".../", 4) == 0) {
16606a7405f5SSimon J. Gerraty 			name = Dir_FindHereOrAbove(curdir, fname + 4);
16616a7405f5SSimon J. Gerraty 			if (name != NULL) {
16626a7405f5SSimon J. Gerraty 				/* Dir_FindHereOrAbove returns dirname */
16636a7405f5SSimon J. Gerraty 				path = str_concat3(name, "/",
16646a7405f5SSimon J. Gerraty 				    str_basename(fname));
16656a7405f5SSimon J. Gerraty 				free(name);
16666a7405f5SSimon J. Gerraty 				fd = open(path, O_RDONLY);
16676a7405f5SSimon J. Gerraty 				if (fd != -1) {
16686a7405f5SSimon J. Gerraty 					fname = path;
16696a7405f5SSimon J. Gerraty 					goto found;
16706a7405f5SSimon J. Gerraty 				}
16716a7405f5SSimon J. Gerraty 			}
16726a7405f5SSimon J. Gerraty 		}
16733955d011SMarcel Moolenaar 		/* if we've chdir'd, rebuild the path name */
1674e2eeea75SSimon J. Gerraty 		if (strcmp(curdir, objdir) != 0 && *fname != '/') {
16752c3632d1SSimon J. Gerraty 			path = str_concat3(curdir, "/", fname);
16763955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16773955d011SMarcel Moolenaar 			if (fd != -1) {
16783955d011SMarcel Moolenaar 				fname = path;
16793955d011SMarcel Moolenaar 				goto found;
16803955d011SMarcel Moolenaar 			}
16812c3632d1SSimon J. Gerraty 			free(path);
16823955d011SMarcel Moolenaar 
16833955d011SMarcel Moolenaar 			/* If curdir failed, try objdir (ala .depend) */
16842c3632d1SSimon J. Gerraty 			path = str_concat3(objdir, "/", fname);
16853955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16863955d011SMarcel Moolenaar 			if (fd != -1) {
16873955d011SMarcel Moolenaar 				fname = path;
16883955d011SMarcel Moolenaar 				goto found;
16893955d011SMarcel Moolenaar 			}
16903955d011SMarcel Moolenaar 		} else {
16913955d011SMarcel Moolenaar 			fd = open(fname, O_RDONLY);
16923955d011SMarcel Moolenaar 			if (fd != -1)
16933955d011SMarcel Moolenaar 				goto found;
16943955d011SMarcel Moolenaar 		}
16953955d011SMarcel Moolenaar 		/* look in -I and system include directories. */
16963955d011SMarcel Moolenaar 		name = Dir_FindFile(fname, parseIncPath);
1697e2eeea75SSimon J. Gerraty 		if (name == NULL) {
1698dba7b0efSSimon J. Gerraty 			SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs)
1699956e45f6SSimon J. Gerraty 			    ? defSysIncPath : sysIncPath;
1700956e45f6SSimon J. Gerraty 			name = Dir_FindFile(fname, sysInc);
1701956e45f6SSimon J. Gerraty 		}
1702e2eeea75SSimon J. Gerraty 		if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
17033955d011SMarcel Moolenaar 			free(name);
17043955d011SMarcel Moolenaar 			free(path);
17059f45a3c8SSimon J. Gerraty 			return false;
17063955d011SMarcel Moolenaar 		}
17073955d011SMarcel Moolenaar 		fname = name;
17083955d011SMarcel Moolenaar 		/*
17093955d011SMarcel Moolenaar 		 * set the MAKEFILE variable desired by System V fans -- the
17103955d011SMarcel Moolenaar 		 * placement of the setting here means it gets set to the last
17113955d011SMarcel Moolenaar 		 * makefile specified, as it is set by SysV make.
17123955d011SMarcel Moolenaar 		 */
17133955d011SMarcel Moolenaar found:
17143955d011SMarcel Moolenaar 		if (!doing_depend)
1715dba7b0efSSimon J. Gerraty 			Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname);
17163955d011SMarcel Moolenaar 		Parse_File(fname, fd);
17173955d011SMarcel Moolenaar 	}
17183955d011SMarcel Moolenaar 	free(path);
17199f45a3c8SSimon J. Gerraty 	return true;
17203955d011SMarcel Moolenaar }
17213955d011SMarcel Moolenaar 
172222619282SSimon J. Gerraty /* populate av for Cmd_Exec and Compat_RunCommand */
172322619282SSimon J. Gerraty int
172422619282SSimon J. Gerraty Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
172522619282SSimon J. Gerraty     char *cmd_file, size_t cmd_filesz, bool eflag, bool xflag)
172622619282SSimon J. Gerraty {
172722619282SSimon J. Gerraty 	int ac = 0;
172822619282SSimon J. Gerraty 	int cmd_fd = -1;
172922619282SSimon J. Gerraty 
173022619282SSimon J. Gerraty 	if (shellPath == NULL)
173122619282SSimon J. Gerraty 		Shell_Init();
173222619282SSimon J. Gerraty 
173322619282SSimon J. Gerraty 	if (cmd_file != NULL) {
173422619282SSimon J. Gerraty 		if (cmd_len == 0)
173522619282SSimon J. Gerraty 			cmd_len = strlen(cmd);
173622619282SSimon J. Gerraty 
173722619282SSimon J. Gerraty 		if (cmd_len > MAKE_CMDLEN_LIMIT) {
173822619282SSimon J. Gerraty 			cmd_fd = mkTempFile(NULL, cmd_file, cmd_filesz);
173922619282SSimon J. Gerraty 			if (cmd_fd >= 0) {
174022619282SSimon J. Gerraty 				ssize_t n;
174122619282SSimon J. Gerraty 
174222619282SSimon J. Gerraty 				n = write(cmd_fd, cmd, cmd_len);
174322619282SSimon J. Gerraty 				close(cmd_fd);
174422619282SSimon J. Gerraty 				if (n < (ssize_t)cmd_len) {
174522619282SSimon J. Gerraty 					unlink(cmd_file);
174622619282SSimon J. Gerraty 					cmd_fd = -1;
174722619282SSimon J. Gerraty 				}
174822619282SSimon J. Gerraty 			}
174922619282SSimon J. Gerraty 		} else
175022619282SSimon J. Gerraty 			cmd_file[0] = '\0';
175122619282SSimon J. Gerraty 	}
175222619282SSimon J. Gerraty 
175322619282SSimon J. Gerraty 	if (avsz < 4 || (eflag && avsz < 5))
175422619282SSimon J. Gerraty 		return -1;
175522619282SSimon J. Gerraty 
175622619282SSimon J. Gerraty 	/* The following works for any of the builtin shell specs. */
175722619282SSimon J. Gerraty 	av[ac++] = shellPath;
175822619282SSimon J. Gerraty 	if (eflag)
175922619282SSimon J. Gerraty 		av[ac++] = shellErrFlag;
176022619282SSimon J. Gerraty 	if (cmd_fd >= 0) {
176122619282SSimon J. Gerraty 		if (xflag)
176222619282SSimon J. Gerraty 			av[ac++] = "-x";
176322619282SSimon J. Gerraty 		av[ac++] = cmd_file;
176422619282SSimon J. Gerraty 	} else {
176522619282SSimon J. Gerraty 		av[ac++] = xflag ? "-xc" : "-c";
176622619282SSimon J. Gerraty 		av[ac++] = cmd;
176722619282SSimon J. Gerraty 	}
176822619282SSimon J. Gerraty 	av[ac] = NULL;
176922619282SSimon J. Gerraty 	return ac;
177022619282SSimon J. Gerraty }
177122619282SSimon J. Gerraty 
1772dba7b0efSSimon J. Gerraty /*
17739f45a3c8SSimon J. Gerraty  * Execute the command in cmd, and return its output (only stdout, not
17749f45a3c8SSimon J. Gerraty  * stderr, possibly empty).  In the output, replace newlines with spaces.
17753955d011SMarcel Moolenaar  */
17763955d011SMarcel Moolenaar char *
17779f45a3c8SSimon J. Gerraty Cmd_Exec(const char *cmd, char **error)
17783955d011SMarcel Moolenaar {
17799f45a3c8SSimon J. Gerraty 	const char *args[4];	/* Arguments for invoking the shell */
178006b9b3e0SSimon J. Gerraty 	int pipefds[2];
17813955d011SMarcel Moolenaar 	int cpid;		/* Child PID */
17823955d011SMarcel Moolenaar 	int pid;		/* PID from wait() */
1783*d9a65c5dSSimon J. Gerraty 	WAIT_T status;		/* command exit status */
17843955d011SMarcel Moolenaar 	Buffer buf;		/* buffer to store the result */
17852c3632d1SSimon J. Gerraty 	ssize_t bytes_read;
17869f45a3c8SSimon J. Gerraty 	char *output;
1787d5e0a182SSimon J. Gerraty 	char *p;
17889f45a3c8SSimon J. Gerraty 	int saved_errno;
1789d5e0a182SSimon J. Gerraty 	char cmd_file[MAXPATHLEN];
17903955d011SMarcel Moolenaar 
17919f45a3c8SSimon J. Gerraty 	DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
17923955d011SMarcel Moolenaar 
179322619282SSimon J. Gerraty 	if (Cmd_Argv(cmd, 0, args, 4, cmd_file, sizeof(cmd_file), false, false) < 0
179422619282SSimon J. Gerraty 	    || pipe(pipefds) == -1) {
17959f45a3c8SSimon J. Gerraty 		*error = str_concat3(
17969f45a3c8SSimon J. Gerraty 		    "Couldn't create pipe for \"", cmd, "\"");
17979f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17983955d011SMarcel Moolenaar 	}
17993955d011SMarcel Moolenaar 
1800c59c3bf3SSimon J. Gerraty 	Var_ReexportVars(SCOPE_GLOBAL);
180106b9b3e0SSimon J. Gerraty 
18026a7405f5SSimon J. Gerraty 	switch (cpid = FORK_FUNCTION()) {
18033955d011SMarcel Moolenaar 	case 0:
18049f45a3c8SSimon J. Gerraty 		(void)close(pipefds[0]);
18059f45a3c8SSimon J. Gerraty 		(void)dup2(pipefds[1], STDOUT_FILENO);
180606b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]);
18073955d011SMarcel Moolenaar 
18083955d011SMarcel Moolenaar 		(void)execv(shellPath, UNCONST(args));
18093955d011SMarcel Moolenaar 		_exit(1);
18103955d011SMarcel Moolenaar 		/* NOTREACHED */
18113955d011SMarcel Moolenaar 
18123955d011SMarcel Moolenaar 	case -1:
18139f45a3c8SSimon J. Gerraty 		*error = str_concat3("Couldn't exec \"", cmd, "\"");
18149f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
18159f45a3c8SSimon J. Gerraty 	}
18163955d011SMarcel Moolenaar 
181706b9b3e0SSimon J. Gerraty 	(void)close(pipefds[1]);	/* No need for the writing half */
18183955d011SMarcel Moolenaar 
18199f45a3c8SSimon J. Gerraty 	saved_errno = 0;
1820e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
18213955d011SMarcel Moolenaar 
18223955d011SMarcel Moolenaar 	do {
18233955d011SMarcel Moolenaar 		char result[BUFSIZ];
182406b9b3e0SSimon J. Gerraty 		bytes_read = read(pipefds[0], result, sizeof result);
18252c3632d1SSimon J. Gerraty 		if (bytes_read > 0)
18262c3632d1SSimon J. Gerraty 			Buf_AddBytes(&buf, result, (size_t)bytes_read);
18279f45a3c8SSimon J. Gerraty 	} while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
18282c3632d1SSimon J. Gerraty 	if (bytes_read == -1)
18299f45a3c8SSimon J. Gerraty 		saved_errno = errno;
18303955d011SMarcel Moolenaar 
183106b9b3e0SSimon J. Gerraty 	(void)close(pipefds[0]); /* Close the input side of the pipe. */
18323955d011SMarcel Moolenaar 
1833e2eeea75SSimon J. Gerraty 	while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
1834b0c40a00SSimon J. Gerraty 		JobReapChild(pid, status, false);
1835e2eeea75SSimon J. Gerraty 
18369f45a3c8SSimon J. Gerraty 	if (Buf_EndsWith(&buf, '\n'))
18379f45a3c8SSimon J. Gerraty 		buf.data[buf.len - 1] = '\0';
18383955d011SMarcel Moolenaar 
18399f45a3c8SSimon J. Gerraty 	output = Buf_DoneData(&buf);
1840d5e0a182SSimon J. Gerraty 	for (p = output; *p != '\0'; p++)
1841d5e0a182SSimon J. Gerraty 		if (*p == '\n')
1842d5e0a182SSimon J. Gerraty 			*p = ' ';
18439f45a3c8SSimon J. Gerraty 
18449f45a3c8SSimon J. Gerraty 	if (WIFSIGNALED(status))
18459f45a3c8SSimon J. Gerraty 		*error = str_concat3("\"", cmd, "\" exited on a signal");
184622619282SSimon J. Gerraty 	else if (WEXITSTATUS(status) != 0) {
184722619282SSimon J. Gerraty 		Buffer errBuf;
184822619282SSimon J. Gerraty 		Buf_Init(&errBuf);
184922619282SSimon J. Gerraty 		Buf_AddStr(&errBuf, "Command \"");
185022619282SSimon J. Gerraty 		Buf_AddStr(&errBuf, cmd);
185122619282SSimon J. Gerraty 		Buf_AddStr(&errBuf, "\" exited with status ");
185222619282SSimon J. Gerraty 		Buf_AddInt(&errBuf, WEXITSTATUS(status));
185322619282SSimon J. Gerraty 		*error = Buf_DoneData(&errBuf);
185422619282SSimon J. Gerraty 	} else if (saved_errno != 0)
18559f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18569f45a3c8SSimon J. Gerraty 		    "Couldn't read shell's output for \"", cmd, "\"");
18579f45a3c8SSimon J. Gerraty 	else
18589f45a3c8SSimon J. Gerraty 		*error = NULL;
1859d5e0a182SSimon J. Gerraty 	if (cmd_file[0] != '\0')
1860d5e0a182SSimon J. Gerraty 		unlink(cmd_file);
18619f45a3c8SSimon J. Gerraty 	return output;
18623955d011SMarcel Moolenaar }
18633955d011SMarcel Moolenaar 
186406b9b3e0SSimon J. Gerraty /*
186506b9b3e0SSimon J. Gerraty  * Print a printf-style error message.
18663955d011SMarcel Moolenaar  *
18679f45a3c8SSimon J. Gerraty  * In default mode, this error message has no consequences, for compatibility
18689f45a3c8SSimon J. Gerraty  * reasons, in particular it does not affect the exit status.  Only in lint
18699f45a3c8SSimon J. Gerraty  * mode (-dL) it does.
187006b9b3e0SSimon J. Gerraty  */
18713955d011SMarcel Moolenaar void
18723955d011SMarcel Moolenaar Error(const char *fmt, ...)
18733955d011SMarcel Moolenaar {
18743955d011SMarcel Moolenaar 	va_list ap;
18759f45a3c8SSimon J. Gerraty 	FILE *f;
18763955d011SMarcel Moolenaar 
18779f45a3c8SSimon J. Gerraty 	f = opts.debug_file;
18789f45a3c8SSimon J. Gerraty 	if (f == stdout)
18799f45a3c8SSimon J. Gerraty 		f = stderr;
18803955d011SMarcel Moolenaar 	(void)fflush(stdout);
18819f45a3c8SSimon J. Gerraty 
18823955d011SMarcel Moolenaar 	for (;;) {
18839f45a3c8SSimon J. Gerraty 		fprintf(f, "%s: ", progname);
18843955d011SMarcel Moolenaar 		va_start(ap, fmt);
18859f45a3c8SSimon J. Gerraty 		(void)vfprintf(f, fmt, ap);
18863955d011SMarcel Moolenaar 		va_end(ap);
18879f45a3c8SSimon J. Gerraty 		(void)fprintf(f, "\n");
18889f45a3c8SSimon J. Gerraty 		(void)fflush(f);
18899f45a3c8SSimon J. Gerraty 		if (f == stderr)
18903955d011SMarcel Moolenaar 			break;
18919f45a3c8SSimon J. Gerraty 		f = stderr;
18923955d011SMarcel Moolenaar 	}
189306b9b3e0SSimon J. Gerraty 	main_errors++;
18943955d011SMarcel Moolenaar }
18953955d011SMarcel Moolenaar 
189606b9b3e0SSimon J. Gerraty /*
189706b9b3e0SSimon J. Gerraty  * Wait for any running jobs to finish, then produce an error message,
1898e2eeea75SSimon J. Gerraty  * finally exit immediately.
18993955d011SMarcel Moolenaar  *
1900e2eeea75SSimon J. Gerraty  * Exiting immediately differs from Parse_Error, which exits only after the
190106b9b3e0SSimon J. Gerraty  * current top-level makefile has been parsed completely.
190206b9b3e0SSimon J. Gerraty  */
19033955d011SMarcel Moolenaar void
19043955d011SMarcel Moolenaar Fatal(const char *fmt, ...)
19053955d011SMarcel Moolenaar {
19063955d011SMarcel Moolenaar 	va_list ap;
19073955d011SMarcel Moolenaar 
19083955d011SMarcel Moolenaar 	if (jobsRunning)
19093955d011SMarcel Moolenaar 		Job_Wait();
19103955d011SMarcel Moolenaar 
19113955d011SMarcel Moolenaar 	(void)fflush(stdout);
1912d5e0a182SSimon J. Gerraty 	fprintf(stderr, "%s: ", progname);
1913e2eeea75SSimon J. Gerraty 	va_start(ap, fmt);
19143955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19153955d011SMarcel Moolenaar 	va_end(ap);
19163955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19173955d011SMarcel Moolenaar 	(void)fflush(stderr);
19189f45a3c8SSimon J. Gerraty 	PrintStackTrace(true);
19193955d011SMarcel Moolenaar 
19209f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
19213955d011SMarcel Moolenaar 
19223955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
19233955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1924e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
19253955d011SMarcel Moolenaar 	exit(2);		/* Not 1 so -q can distinguish error */
19263955d011SMarcel Moolenaar }
19273955d011SMarcel Moolenaar 
192806b9b3e0SSimon J. Gerraty /*
192906b9b3e0SSimon J. Gerraty  * Major exception once jobs are being created.
193006b9b3e0SSimon J. Gerraty  * Kills all jobs, prints a message and exits.
193106b9b3e0SSimon J. Gerraty  */
19323955d011SMarcel Moolenaar void
19333955d011SMarcel Moolenaar Punt(const char *fmt, ...)
19343955d011SMarcel Moolenaar {
19353955d011SMarcel Moolenaar 	va_list ap;
19363955d011SMarcel Moolenaar 
19373955d011SMarcel Moolenaar 	(void)fflush(stdout);
19383955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: ", progname);
19399f45a3c8SSimon J. Gerraty 	va_start(ap, fmt);
19403955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19413955d011SMarcel Moolenaar 	va_end(ap);
19423955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19433955d011SMarcel Moolenaar 	(void)fflush(stderr);
19443955d011SMarcel Moolenaar 
19459f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
19463955d011SMarcel Moolenaar 
19473955d011SMarcel Moolenaar 	DieHorribly();
19483955d011SMarcel Moolenaar }
19493955d011SMarcel Moolenaar 
1950956e45f6SSimon J. Gerraty /* Exit without giving a message. */
19513955d011SMarcel Moolenaar void
19523955d011SMarcel Moolenaar DieHorribly(void)
19533955d011SMarcel Moolenaar {
19543955d011SMarcel Moolenaar 	if (jobsRunning)
19553955d011SMarcel Moolenaar 		Job_AbortAll();
19563955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2))
19573955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1958e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
195906b9b3e0SSimon J. Gerraty 	exit(2);		/* Not 1 so -q can distinguish error */
19603955d011SMarcel Moolenaar }
19613955d011SMarcel Moolenaar 
19624fde40d9SSimon J. Gerraty int
19639f45a3c8SSimon J. Gerraty unlink_file(const char *file)
19643955d011SMarcel Moolenaar {
19653955d011SMarcel Moolenaar 	struct stat st;
19663955d011SMarcel Moolenaar 
19673955d011SMarcel Moolenaar 	if (lstat(file, &st) == -1)
19684fde40d9SSimon J. Gerraty 		return -1;
19693955d011SMarcel Moolenaar 
19703955d011SMarcel Moolenaar 	if (S_ISDIR(st.st_mode)) {
19714fde40d9SSimon J. Gerraty 		/*
19724fde40d9SSimon J. Gerraty 		 * POSIX says for unlink: "The path argument shall not name
19734fde40d9SSimon J. Gerraty 		 * a directory unless [...]".
19744fde40d9SSimon J. Gerraty 		 */
19753955d011SMarcel Moolenaar 		errno = EISDIR;
19764fde40d9SSimon J. Gerraty 		return -1;
19773955d011SMarcel Moolenaar 	}
19784fde40d9SSimon J. Gerraty 	return unlink(file);
19793955d011SMarcel Moolenaar }
19803955d011SMarcel Moolenaar 
1981956e45f6SSimon J. Gerraty static void
1982956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n)
1983956e45f6SSimon J. Gerraty {
1984956e45f6SSimon J. Gerraty 	const char *mem = data;
1985956e45f6SSimon J. Gerraty 
1986956e45f6SSimon J. Gerraty 	while (n > 0) {
1987956e45f6SSimon J. Gerraty 		ssize_t written = write(fd, mem, n);
19889f45a3c8SSimon J. Gerraty 		/* XXX: Should this EAGAIN be EINTR? */
1989956e45f6SSimon J. Gerraty 		if (written == -1 && errno == EAGAIN)
1990956e45f6SSimon J. Gerraty 			continue;
1991956e45f6SSimon J. Gerraty 		if (written == -1)
1992956e45f6SSimon J. Gerraty 			break;
1993956e45f6SSimon J. Gerraty 		mem += written;
1994956e45f6SSimon J. Gerraty 		n -= (size_t)written;
1995956e45f6SSimon J. Gerraty 	}
1996956e45f6SSimon J. Gerraty }
1997956e45f6SSimon J. Gerraty 
19989f45a3c8SSimon J. Gerraty /* Print why exec failed, avoiding stdio. */
1999956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD
20006a7405f5SSimon J. Gerraty execDie(const char *func, const char *arg)
20013955d011SMarcel Moolenaar {
20026a7405f5SSimon J. Gerraty 	char msg[1024];
20036a7405f5SSimon J. Gerraty 	int len;
20043955d011SMarcel Moolenaar 
20056a7405f5SSimon J. Gerraty 	len = snprintf(msg, sizeof(msg), "%s: %s(%s) failed (%s)\n",
20066a7405f5SSimon J. Gerraty 	    progname, func, arg, strerror(errno));
20076a7405f5SSimon J. Gerraty 	write_all(STDERR_FILENO, msg, (size_t)len);
2008956e45f6SSimon J. Gerraty 	_exit(1);
20093955d011SMarcel Moolenaar }
20103955d011SMarcel Moolenaar 
2011e1cee40dSSimon J. Gerraty static void
2012e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void)
2013e1cee40dSSimon J. Gerraty {
2014956e45f6SSimon J. Gerraty 	HashIter hi;
20158d5c8e21SSimon J. Gerraty 	bool more;
2016b778b302SSimon J. Gerraty 
2017e2eeea75SSimon J. Gerraty 	HashIter_Init(&hi, &cached_realpaths);
20188d5c8e21SSimon J. Gerraty 	more = HashIter_Next(&hi);
20198d5c8e21SSimon J. Gerraty 	while (more) {
20208d5c8e21SSimon J. Gerraty 		HashEntry *he = hi.entry;
20218d5c8e21SSimon J. Gerraty 		more = HashIter_Next(&hi);
2022956e45f6SSimon J. Gerraty 		if (he->key[0] != '/') {
2023e2eeea75SSimon J. Gerraty 			DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
20248d5c8e21SSimon J. Gerraty 			free(he->value);
2025e2eeea75SSimon J. Gerraty 			HashTable_DeleteEntry(&cached_realpaths, he);
2026b46b9039SSimon J. Gerraty 		}
2027b46b9039SSimon J. Gerraty 	}
2028b46b9039SSimon J. Gerraty }
2029e1cee40dSSimon J. Gerraty 
20309f45a3c8SSimon J. Gerraty const char *
2031e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved)
2032e1cee40dSSimon J. Gerraty {
20332c3632d1SSimon J. Gerraty 	const char *rp;
2034e1cee40dSSimon J. Gerraty 
2035e2eeea75SSimon J. Gerraty 	if (pathname == NULL || pathname[0] == '\0')
2036e1cee40dSSimon J. Gerraty 		return NULL;
2037e1cee40dSSimon J. Gerraty 
2038e2eeea75SSimon J. Gerraty 	rp = HashTable_FindValue(&cached_realpaths, pathname);
2039e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
20408d5c8e21SSimon J. Gerraty 		snprintf(resolved, MAXPATHLEN, "%s", rp);
2041e2eeea75SSimon J. Gerraty 		return resolved;
2042e2eeea75SSimon J. Gerraty 	}
20433841c287SSimon J. Gerraty 
2044e2eeea75SSimon J. Gerraty 	rp = realpath(pathname, resolved);
2045e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2046e2eeea75SSimon J. Gerraty 		HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
2047e2eeea75SSimon J. Gerraty 		DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
2048e2eeea75SSimon J. Gerraty 		return resolved;
2049e2eeea75SSimon J. Gerraty 	}
2050e2eeea75SSimon J. Gerraty 
2051e2eeea75SSimon J. Gerraty 	/* should we negative-cache? */
2052e2eeea75SSimon J. Gerraty 	return NULL;
2053b778b302SSimon J. Gerraty }
2054b778b302SSimon J. Gerraty 
20553841c287SSimon J. Gerraty /*
20563841c287SSimon J. Gerraty  * Return true if we should die without noise.
2057e2eeea75SSimon J. Gerraty  * For example our failing child was a sub-make or failure happened elsewhere.
20583841c287SSimon J. Gerraty  */
2059b0c40a00SSimon J. Gerraty bool
2060e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf)
20613841c287SSimon J. Gerraty {
20623841c287SSimon J. Gerraty 	static int quietly = -1;
20633841c287SSimon J. Gerraty 
20643841c287SSimon J. Gerraty 	if (quietly < 0) {
2065b0c40a00SSimon J. Gerraty 		if (DEBUG(JOB) ||
2066b0c40a00SSimon J. Gerraty 		    !GetBooleanExpr("${.MAKE.DIE_QUIETLY}", true))
20673841c287SSimon J. Gerraty 			quietly = 0;
20683841c287SSimon J. Gerraty 		else if (bf >= 0)
20693841c287SSimon J. Gerraty 			quietly = bf;
20703841c287SSimon J. Gerraty 		else
207106b9b3e0SSimon J. Gerraty 			quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
20723841c287SSimon J. Gerraty 	}
2073dba7b0efSSimon J. Gerraty 	return quietly != 0;
20743841c287SSimon J. Gerraty }
20753841c287SSimon J. Gerraty 
2076956e45f6SSimon J. Gerraty static void
2077956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn)
2078956e45f6SSimon J. Gerraty {
2079956e45f6SSimon J. Gerraty 	StringListNode *ln;
2080c59c3bf3SSimon J. Gerraty 	char sts[16];
2081956e45f6SSimon J. Gerraty 
2082956e45f6SSimon J. Gerraty 	/*
2083956e45f6SSimon J. Gerraty 	 * We can print this even if there is no .ERROR target.
2084956e45f6SSimon J. Gerraty 	 */
2085c59c3bf3SSimon J. Gerraty 	snprintf(sts, sizeof(sts), "%d", gn->exit_status);
2086c59c3bf3SSimon J. Gerraty 	Global_Set(".ERROR_EXIT", sts);
2087dba7b0efSSimon J. Gerraty 	Global_Set(".ERROR_TARGET", gn->name);
2088dba7b0efSSimon J. Gerraty 	Global_Delete(".ERROR_CMD");
2089956e45f6SSimon J. Gerraty 
209006b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
2091956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
2092956e45f6SSimon J. Gerraty 
2093956e45f6SSimon J. Gerraty 		if (cmd == NULL)
2094956e45f6SSimon J. Gerraty 			break;
2095dba7b0efSSimon J. Gerraty 		Global_Append(".ERROR_CMD", cmd);
2096956e45f6SSimon J. Gerraty 	}
2097956e45f6SSimon J. Gerraty }
2098956e45f6SSimon J. Gerraty 
209906b9b3e0SSimon J. Gerraty /*
210006b9b3e0SSimon J. Gerraty  * Print some helpful information in case of an error.
210106b9b3e0SSimon J. Gerraty  * The caller should exit soon after calling this function.
210206b9b3e0SSimon J. Gerraty  */
21033955d011SMarcel Moolenaar void
2104e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg)
21053955d011SMarcel Moolenaar {
2106e2eeea75SSimon J. Gerraty 	static GNode *errorNode = NULL;
210722619282SSimon J. Gerraty 	StringListNode *ln;
21083955d011SMarcel Moolenaar 
21092c3632d1SSimon J. Gerraty 	if (DEBUG(HASH)) {
21102c3632d1SSimon J. Gerraty 		Targ_Stats();
21112c3632d1SSimon J. Gerraty 		Var_Stats();
21122c3632d1SSimon J. Gerraty 	}
21132c3632d1SSimon J. Gerraty 
211406b9b3e0SSimon J. Gerraty 	if (errorNode != NULL)
211506b9b3e0SSimon J. Gerraty 		return;		/* we've been here! */
21163841c287SSimon J. Gerraty 
211722619282SSimon J. Gerraty 	printf("%s%s: stopped", msg, progname);
211822619282SSimon J. Gerraty 	ln = opts.create.first;
211922619282SSimon J. Gerraty 	if (ln != NULL || mainNode != NULL) {
212022619282SSimon J. Gerraty 		printf(" making \"");
212122619282SSimon J. Gerraty 		if (ln != NULL) {
212222619282SSimon J. Gerraty 			printf("%s", (const char *)ln->datum);
212322619282SSimon J. Gerraty 			for (ln = ln->next; ln != NULL; ln = ln->next)
212422619282SSimon J. Gerraty 				printf(" %s", (const char *)ln->datum);
212522619282SSimon J. Gerraty 		} else
212622619282SSimon J. Gerraty 			printf("%s", mainNode->name);
212722619282SSimon J. Gerraty 		printf("\"");
212822619282SSimon J. Gerraty 	}
212922619282SSimon J. Gerraty 	printf(" in %s\n", curdir);
21303955d011SMarcel Moolenaar 
213106b9b3e0SSimon J. Gerraty 	/* we generally want to keep quiet if a sub-make died */
213206b9b3e0SSimon J. Gerraty 	if (shouldDieQuietly(gn, -1))
213306b9b3e0SSimon J. Gerraty 		return;
2134e2eeea75SSimon J. Gerraty 
2135e2eeea75SSimon J. Gerraty 	if (gn != NULL)
2136956e45f6SSimon J. Gerraty 		SetErrorVars(gn);
2137e2eeea75SSimon J. Gerraty 
2138e2eeea75SSimon J. Gerraty 	{
21398c973ee2SSimon J. Gerraty 		char *errorVarsValues = Var_Subst(
21408c973ee2SSimon J. Gerraty 		    "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
21418d5c8e21SSimon J. Gerraty 		    SCOPE_GLOBAL, VARE_EVAL);
2142956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
2143e2eeea75SSimon J. Gerraty 		printf("%s", errorVarsValues);
2144e2eeea75SSimon J. Gerraty 		free(errorVarsValues);
2145e2eeea75SSimon J. Gerraty 	}
2146e2eeea75SSimon J. Gerraty 
2147ac3446e9SSimon J. Gerraty 	fflush(stdout);
2148ac3446e9SSimon J. Gerraty 
21493955d011SMarcel Moolenaar 	/*
21503955d011SMarcel Moolenaar 	 * Finally, see if there is a .ERROR target, and run it if so.
21513955d011SMarcel Moolenaar 	 */
2152e2eeea75SSimon J. Gerraty 	errorNode = Targ_FindNode(".ERROR");
2153e2eeea75SSimon J. Gerraty 	if (errorNode != NULL) {
2154e2eeea75SSimon J. Gerraty 		errorNode->type |= OP_SPECIAL;
2155e2eeea75SSimon J. Gerraty 		Compat_Make(errorNode, errorNode);
21563955d011SMarcel Moolenaar 	}
21573955d011SMarcel Moolenaar }
21583955d011SMarcel Moolenaar 
21593955d011SMarcel Moolenaar void
2160b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(bool first)
21613955d011SMarcel Moolenaar {
2162b0c40a00SSimon J. Gerraty 	static bool once = true;
21639f45a3c8SSimon J. Gerraty 	char *flags;
21643955d011SMarcel Moolenaar 
21653955d011SMarcel Moolenaar 	if (once != first)
21663955d011SMarcel Moolenaar 		return;
2167b0c40a00SSimon J. Gerraty 	once = false;
21683955d011SMarcel Moolenaar 
21698c973ee2SSimon J. Gerraty 	flags = Var_Subst(
21709f45a3c8SSimon J. Gerraty 	    "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
21718d5c8e21SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_EVAL);
2172956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2173c59c3bf3SSimon J. Gerraty 	if (flags[0] != '\0')
21749f45a3c8SSimon J. Gerraty 		setenv("MAKEFLAGS", flags, 1);
21758d5c8e21SSimon J. Gerraty 	free(flags);
21763955d011SMarcel Moolenaar }
21773955d011SMarcel Moolenaar 
21783955d011SMarcel Moolenaar char *
21793955d011SMarcel Moolenaar getTmpdir(void)
21803955d011SMarcel Moolenaar {
21813955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
21823955d011SMarcel Moolenaar 	struct stat st;
21833955d011SMarcel Moolenaar 
2184e2eeea75SSimon J. Gerraty 	if (tmpdir != NULL)
2185e2eeea75SSimon J. Gerraty 		return tmpdir;
2186e2eeea75SSimon J. Gerraty 
21879f45a3c8SSimon J. Gerraty 	/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
21888c973ee2SSimon J. Gerraty 	tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
21898d5c8e21SSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_EVAL);
2190956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2191e2eeea75SSimon J. Gerraty 
21923955d011SMarcel Moolenaar 	if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
21933955d011SMarcel Moolenaar 		free(tmpdir);
21943955d011SMarcel Moolenaar 		tmpdir = bmake_strdup(_PATH_TMP);
21953955d011SMarcel Moolenaar 	}
21963955d011SMarcel Moolenaar 	return tmpdir;
21973955d011SMarcel Moolenaar }
21983955d011SMarcel Moolenaar 
21993955d011SMarcel Moolenaar /*
22003955d011SMarcel Moolenaar  * Create and open a temp file using "pattern".
2201d5e0a182SSimon J. Gerraty  * If tfile is provided, set it to a copy of the filename created.
22023955d011SMarcel Moolenaar  * Otherwise unlink the file once open.
22033955d011SMarcel Moolenaar  */
22043955d011SMarcel Moolenaar int
2205dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz)
22063955d011SMarcel Moolenaar {
22073955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
2208dba7b0efSSimon J. Gerraty 	char tbuf[MAXPATHLEN];
22093955d011SMarcel Moolenaar 	int fd;
22103955d011SMarcel Moolenaar 
2211e2eeea75SSimon J. Gerraty 	if (pattern == NULL)
22123955d011SMarcel Moolenaar 		pattern = TMPPAT;
2213956e45f6SSimon J. Gerraty 	if (tmpdir == NULL)
22143955d011SMarcel Moolenaar 		tmpdir = getTmpdir();
2215dba7b0efSSimon J. Gerraty 	if (tfile == NULL) {
2216dba7b0efSSimon J. Gerraty 		tfile = tbuf;
2217dba7b0efSSimon J. Gerraty 		tfile_sz = sizeof tbuf;
2218dba7b0efSSimon J. Gerraty 	}
22199f45a3c8SSimon J. Gerraty 
22209f45a3c8SSimon J. Gerraty 	if (pattern[0] == '/')
2221dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s", pattern);
22229f45a3c8SSimon J. Gerraty 	else
2223dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern);
22249f45a3c8SSimon J. Gerraty 
22253955d011SMarcel Moolenaar 	if ((fd = mkstemp(tfile)) < 0)
2226e2eeea75SSimon J. Gerraty 		Punt("Could not create temporary file %s: %s", tfile,
2227e2eeea75SSimon J. Gerraty 		    strerror(errno));
22289f45a3c8SSimon J. Gerraty 	if (tfile == tbuf)
222906b9b3e0SSimon J. Gerraty 		unlink(tfile);	/* we just want the descriptor */
22309f45a3c8SSimon J. Gerraty 
22313955d011SMarcel Moolenaar 	return fd;
22323955d011SMarcel Moolenaar }
22333955d011SMarcel Moolenaar 
2234be19d90bSSimon J. Gerraty /*
2235e2eeea75SSimon J. Gerraty  * Convert a string representation of a boolean into a boolean value.
2236b0c40a00SSimon J. Gerraty  * Anything that looks like "No", "False", "Off", "0" etc. is false,
2237b0c40a00SSimon J. Gerraty  * the empty string is the fallback, everything else is true.
2238be19d90bSSimon J. Gerraty  */
2239b0c40a00SSimon J. Gerraty bool
2240b0c40a00SSimon J. Gerraty ParseBoolean(const char *s, bool fallback)
2241be19d90bSSimon J. Gerraty {
2242e2eeea75SSimon J. Gerraty 	char ch = ch_tolower(s[0]);
2243e2eeea75SSimon J. Gerraty 	if (ch == '\0')
2244e2eeea75SSimon J. Gerraty 		return fallback;
2245e2eeea75SSimon J. Gerraty 	if (ch == '0' || ch == 'f' || ch == 'n')
2246b0c40a00SSimon J. Gerraty 		return false;
2247e2eeea75SSimon J. Gerraty 	if (ch == 'o')
2248e2eeea75SSimon J. Gerraty 		return ch_tolower(s[1]) != 'f';
2249b0c40a00SSimon J. Gerraty 	return true;
2250be19d90bSSimon J. Gerraty }
2251