xref: /freebsd/contrib/bmake/main.c (revision c59c3bf34db360695f07735bebc76a768cac5afc)
1*c59c3bf3SSimon J. Gerraty /*	$NetBSD: main.c,v 1.612 2024/03/10 02:53:37 sjg Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990, 1993
53955d011SMarcel Moolenaar  *	The Regents of the University of California.  All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
373955d011SMarcel Moolenaar  * All rights reserved.
383955d011SMarcel Moolenaar  *
393955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
403955d011SMarcel Moolenaar  * Adam de Boor.
413955d011SMarcel Moolenaar  *
423955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
433955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
443955d011SMarcel Moolenaar  * are met:
453955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
463955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
473955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
483955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
493955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
503955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
513955d011SMarcel Moolenaar  *    must display the following acknowledgement:
523955d011SMarcel Moolenaar  *	This product includes software developed by the University of
533955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
543955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
553955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
563955d011SMarcel Moolenaar  *    without specific prior written permission.
573955d011SMarcel Moolenaar  *
583955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
593955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
623955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
633955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
643955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
653955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
663955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
673955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
683955d011SMarcel Moolenaar  * SUCH DAMAGE.
693955d011SMarcel Moolenaar  */
703955d011SMarcel Moolenaar 
7106b9b3e0SSimon J. Gerraty /*
7206b9b3e0SSimon J. Gerraty  * The main file for this entire program. Exit routines etc. reside here.
733955d011SMarcel Moolenaar  *
743955d011SMarcel Moolenaar  * Utility functions defined in this file:
753955d011SMarcel Moolenaar  *
76dba7b0efSSimon J. Gerraty  *	Main_ParseArgLine
77dba7b0efSSimon J. Gerraty  *			Parse and process command line arguments from a
78dba7b0efSSimon J. Gerraty  *			single string.  Used to implement the special targets
79dba7b0efSSimon J. Gerraty  *			.MFLAGS and .MAKEFLAGS.
803955d011SMarcel Moolenaar  *
81e2eeea75SSimon J. Gerraty  *	Error		Print a tagged error message.
823955d011SMarcel Moolenaar  *
83e2eeea75SSimon J. Gerraty  *	Fatal		Print an error message and exit.
84e2eeea75SSimon J. Gerraty  *
85e2eeea75SSimon J. Gerraty  *	Punt		Abort all jobs and exit with a message.
863955d011SMarcel Moolenaar  *
87dba7b0efSSimon J. Gerraty  *	Finish		Finish things up by printing the number of errors
88dba7b0efSSimon J. Gerraty  *			that occurred, and exit.
893955d011SMarcel Moolenaar  */
903955d011SMarcel Moolenaar 
913955d011SMarcel Moolenaar #include <sys/types.h>
923955d011SMarcel Moolenaar #include <sys/time.h>
933955d011SMarcel Moolenaar #include <sys/param.h>
943955d011SMarcel Moolenaar #include <sys/resource.h>
953955d011SMarcel Moolenaar #include <sys/stat.h>
960dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL)
970dede8b0SSimon J. Gerraty #include <sys/sysctl.h>
980dede8b0SSimon J. Gerraty #endif
993955d011SMarcel Moolenaar #include <sys/utsname.h>
1003955d011SMarcel Moolenaar #include "wait.h"
1013955d011SMarcel Moolenaar 
1023955d011SMarcel Moolenaar #include <errno.h>
10351ee2c1cSSimon J. Gerraty #include <signal.h>
1043955d011SMarcel Moolenaar #include <stdarg.h>
1053955d011SMarcel Moolenaar #include <time.h>
1063955d011SMarcel Moolenaar 
1073955d011SMarcel Moolenaar #include "make.h"
1083955d011SMarcel Moolenaar #include "dir.h"
1093955d011SMarcel Moolenaar #include "job.h"
1103955d011SMarcel Moolenaar #include "pathnames.h"
1113955d011SMarcel Moolenaar #include "trace.h"
1123955d011SMarcel Moolenaar 
113956e45f6SSimon J. Gerraty /*	"@(#)main.c	8.3 (Berkeley) 3/19/94"	*/
114*c59c3bf3SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.612 2024/03/10 02:53:37 sjg Exp $");
115d5e0a182SSimon J. Gerraty #if defined(MAKE_NATIVE)
116956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
117956e45f6SSimon J. Gerraty 	    "The Regents of the University of California.  "
118956e45f6SSimon J. Gerraty 	    "All rights reserved.");
1193955d011SMarcel Moolenaar #endif
1203955d011SMarcel Moolenaar 
1210dede8b0SSimon J. Gerraty #ifndef __arraycount
1220dede8b0SSimon J. Gerraty # define __arraycount(__x)	(sizeof(__x) / sizeof(__x[0]))
1230dede8b0SSimon J. Gerraty #endif
1240dede8b0SSimon J. Gerraty 
125956e45f6SSimon J. Gerraty CmdOpts opts;
1263955d011SMarcel Moolenaar time_t now;			/* Time at start of make */
127e2eeea75SSimon J. Gerraty GNode *defaultNode;		/* .DEFAULT node */
128d5e0a182SSimon J. Gerraty bool allPrecious;		/* .PRECIOUS given on a line by itself */
129b0c40a00SSimon J. Gerraty bool deleteOnError;		/* .DELETE_ON_ERROR: set */
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar static int maxJobTokens;	/* -j argument */
1328c973ee2SSimon J. Gerraty static bool enterFlagObj;	/* -w and objdir != srcdir */
133956e45f6SSimon J. Gerraty 
1343955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
135b0c40a00SSimon J. Gerraty bool doing_depend;		/* Set while reading .depend */
136b0c40a00SSimon J. Gerraty static bool jobsRunning;	/* true if the jobs might be running */
1373955d011SMarcel Moolenaar static const char *tracefile;
1389f45a3c8SSimon J. Gerraty static bool ReadMakefile(const char *);
139e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void);
1403955d011SMarcel Moolenaar 
141b0c40a00SSimon J. Gerraty static bool ignorePWD;		/* if we use -C, PWD is meaningless */
1423955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
1433955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1];	/* Startup directory */
14406b9b3e0SSimon J. Gerraty const char *progname;
1453955d011SMarcel Moolenaar char *makeDependfile;
1463955d011SMarcel Moolenaar pid_t myPid;
14751ee2c1cSSimon J. Gerraty int makelevel;
1483955d011SMarcel Moolenaar 
149b0c40a00SSimon J. Gerraty bool forceJobs = false;
15006b9b3e0SSimon J. Gerraty static int main_errors = 0;
151e2eeea75SSimon J. Gerraty static HashTable cached_realpaths;
1523955d011SMarcel Moolenaar 
15351ee2c1cSSimon J. Gerraty /*
15451ee2c1cSSimon J. Gerraty  * For compatibility with the POSIX version of MAKEFLAGS that includes
155e2eeea75SSimon J. Gerraty  * all the options without '-', convert 'flags' to '-f -l -a -g -s '.
15651ee2c1cSSimon J. Gerraty  */
15751ee2c1cSSimon J. Gerraty static char *
15851ee2c1cSSimon J. Gerraty explode(const char *flags)
15951ee2c1cSSimon J. Gerraty {
1609f45a3c8SSimon J. Gerraty 	char *exploded, *ep;
1619f45a3c8SSimon J. Gerraty 	const char *p;
16251ee2c1cSSimon J. Gerraty 
16351ee2c1cSSimon J. Gerraty 	if (flags == NULL)
16451ee2c1cSSimon J. Gerraty 		return NULL;
16551ee2c1cSSimon J. Gerraty 
1669f45a3c8SSimon J. Gerraty 	for (p = flags; *p != '\0'; p++)
1679f45a3c8SSimon J. Gerraty 		if (!ch_isalpha(*p))
16851ee2c1cSSimon J. Gerraty 			return bmake_strdup(flags);
16951ee2c1cSSimon J. Gerraty 
1709f45a3c8SSimon J. Gerraty 	exploded = bmake_malloc((size_t)(p - flags) * 3 + 1);
1719f45a3c8SSimon J. Gerraty 	for (p = flags, ep = exploded; *p != '\0'; p++) {
1729f45a3c8SSimon J. Gerraty 		*ep++ = '-';
1739f45a3c8SSimon J. Gerraty 		*ep++ = *p;
1749f45a3c8SSimon J. Gerraty 		*ep++ = ' ';
17551ee2c1cSSimon J. Gerraty 	}
1769f45a3c8SSimon J. Gerraty 	*ep = '\0';
1779f45a3c8SSimon J. Gerraty 	return exploded;
17851ee2c1cSSimon J. Gerraty }
17951ee2c1cSSimon J. Gerraty 
180e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void
181e2eeea75SSimon J. Gerraty usage(void)
182e2eeea75SSimon J. Gerraty {
183e2eeea75SSimon J. Gerraty 	size_t prognameLen = strcspn(progname, "[");
184e2eeea75SSimon J. Gerraty 
185e2eeea75SSimon J. Gerraty 	(void)fprintf(stderr,
186e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n"
187e2eeea75SSimon J. Gerraty "            [-C directory] [-D variable] [-d flags] [-f makefile]\n"
188e2eeea75SSimon J. Gerraty "            [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
189e2eeea75SSimon J. Gerraty "            [-V variable] [-v variable] [variable=value] [target ...]\n",
190e2eeea75SSimon J. Gerraty 	    (int)prognameLen, progname);
191e2eeea75SSimon J. Gerraty 	exit(2);
192e2eeea75SSimon J. Gerraty }
193e2eeea75SSimon J. Gerraty 
1943955d011SMarcel Moolenaar static void
195dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg)
1963955d011SMarcel Moolenaar {
1973955d011SMarcel Moolenaar 	const char *mode;
198956e45f6SSimon J. Gerraty 	size_t len;
1993955d011SMarcel Moolenaar 	char *fname;
2003955d011SMarcel Moolenaar 
201956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout && opts.debug_file != stderr)
202956e45f6SSimon J. Gerraty 		fclose(opts.debug_file);
203956e45f6SSimon J. Gerraty 
204dba7b0efSSimon J. Gerraty 	if (*arg == '+') {
205dba7b0efSSimon J. Gerraty 		arg++;
2063955d011SMarcel Moolenaar 		mode = "a";
2073955d011SMarcel Moolenaar 	} else
2083955d011SMarcel Moolenaar 		mode = "w";
209956e45f6SSimon J. Gerraty 
210dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stdout") == 0) {
211956e45f6SSimon J. Gerraty 		opts.debug_file = stdout;
212956e45f6SSimon J. Gerraty 		return;
2133955d011SMarcel Moolenaar 	}
214dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stderr") == 0) {
215956e45f6SSimon J. Gerraty 		opts.debug_file = stderr;
216956e45f6SSimon J. Gerraty 		return;
2173955d011SMarcel Moolenaar 	}
218956e45f6SSimon J. Gerraty 
219dba7b0efSSimon J. Gerraty 	len = strlen(arg);
220e1cee40dSSimon J. Gerraty 	fname = bmake_malloc(len + 20);
221dba7b0efSSimon J. Gerraty 	memcpy(fname, arg, len + 1);
222956e45f6SSimon J. Gerraty 
2239f45a3c8SSimon J. Gerraty 	/* Replace the trailing '%d' after '.%d' with the pid. */
2249f45a3c8SSimon J. Gerraty 	if (len >= 3 && memcmp(fname + len - 3, ".%d", 3) == 0)
2253955d011SMarcel Moolenaar 		snprintf(fname + len - 2, 20, "%d", getpid());
226956e45f6SSimon J. Gerraty 
227956e45f6SSimon J. Gerraty 	opts.debug_file = fopen(fname, mode);
228e2eeea75SSimon J. Gerraty 	if (opts.debug_file == NULL) {
229d5e0a182SSimon J. Gerraty 		fprintf(stderr, "Cannot open debug file \"%s\"\n", fname);
2309f45a3c8SSimon J. Gerraty 		exit(2);
2313955d011SMarcel Moolenaar 	}
2323955d011SMarcel Moolenaar 	free(fname);
233956e45f6SSimon J. Gerraty }
234956e45f6SSimon J. Gerraty 
235956e45f6SSimon J. Gerraty static void
236dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue)
237956e45f6SSimon J. Gerraty {
238956e45f6SSimon J. Gerraty 	const char *modules;
239e2eeea75SSimon J. Gerraty 	DebugFlags debug = opts.debug;
240956e45f6SSimon J. Gerraty 
241dba7b0efSSimon J. Gerraty 	for (modules = argvalue; *modules != '\0'; modules++) {
242956e45f6SSimon J. Gerraty 		switch (*modules) {
243956e45f6SSimon J. Gerraty 		case '0':	/* undocumented, only intended for tests */
2449f45a3c8SSimon J. Gerraty 			memset(&debug, 0, sizeof(debug));
245956e45f6SSimon J. Gerraty 			break;
246956e45f6SSimon J. Gerraty 		case 'A':
2479f45a3c8SSimon J. Gerraty 			memset(&debug, ~0, sizeof(debug));
248956e45f6SSimon J. Gerraty 			break;
249956e45f6SSimon J. Gerraty 		case 'a':
2509f45a3c8SSimon J. Gerraty 			debug.DEBUG_ARCH = true;
251956e45f6SSimon J. Gerraty 			break;
252956e45f6SSimon J. Gerraty 		case 'C':
2539f45a3c8SSimon J. Gerraty 			debug.DEBUG_CWD = true;
254956e45f6SSimon J. Gerraty 			break;
255956e45f6SSimon J. Gerraty 		case 'c':
2569f45a3c8SSimon J. Gerraty 			debug.DEBUG_COND = true;
257956e45f6SSimon J. Gerraty 			break;
258956e45f6SSimon J. Gerraty 		case 'd':
2599f45a3c8SSimon J. Gerraty 			debug.DEBUG_DIR = true;
260956e45f6SSimon J. Gerraty 			break;
261956e45f6SSimon J. Gerraty 		case 'e':
2629f45a3c8SSimon J. Gerraty 			debug.DEBUG_ERROR = true;
263956e45f6SSimon J. Gerraty 			break;
264956e45f6SSimon J. Gerraty 		case 'f':
2659f45a3c8SSimon J. Gerraty 			debug.DEBUG_FOR = true;
266956e45f6SSimon J. Gerraty 			break;
267956e45f6SSimon J. Gerraty 		case 'g':
268956e45f6SSimon J. Gerraty 			if (modules[1] == '1') {
2699f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH1 = true;
270e2eeea75SSimon J. Gerraty 				modules++;
271e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '2') {
2729f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH2 = true;
273e2eeea75SSimon J. Gerraty 				modules++;
274e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '3') {
2759f45a3c8SSimon J. Gerraty 				debug.DEBUG_GRAPH3 = true;
276e2eeea75SSimon J. Gerraty 				modules++;
277956e45f6SSimon J. Gerraty 			}
278956e45f6SSimon J. Gerraty 			break;
279956e45f6SSimon J. Gerraty 		case 'h':
2809f45a3c8SSimon J. Gerraty 			debug.DEBUG_HASH = true;
281956e45f6SSimon J. Gerraty 			break;
282956e45f6SSimon J. Gerraty 		case 'j':
2839f45a3c8SSimon J. Gerraty 			debug.DEBUG_JOB = true;
284956e45f6SSimon J. Gerraty 			break;
285956e45f6SSimon J. Gerraty 		case 'L':
286b0c40a00SSimon J. Gerraty 			opts.strict = true;
287956e45f6SSimon J. Gerraty 			break;
288956e45f6SSimon J. Gerraty 		case 'l':
2899f45a3c8SSimon J. Gerraty 			debug.DEBUG_LOUD = true;
290956e45f6SSimon J. Gerraty 			break;
291956e45f6SSimon J. Gerraty 		case 'M':
2929f45a3c8SSimon J. Gerraty 			debug.DEBUG_META = true;
293956e45f6SSimon J. Gerraty 			break;
294956e45f6SSimon J. Gerraty 		case 'm':
2959f45a3c8SSimon J. Gerraty 			debug.DEBUG_MAKE = true;
296956e45f6SSimon J. Gerraty 			break;
297956e45f6SSimon J. Gerraty 		case 'n':
2989f45a3c8SSimon J. Gerraty 			debug.DEBUG_SCRIPT = true;
299956e45f6SSimon J. Gerraty 			break;
300956e45f6SSimon J. Gerraty 		case 'p':
3019f45a3c8SSimon J. Gerraty 			debug.DEBUG_PARSE = true;
302956e45f6SSimon J. Gerraty 			break;
303956e45f6SSimon J. Gerraty 		case 's':
3049f45a3c8SSimon J. Gerraty 			debug.DEBUG_SUFF = true;
305956e45f6SSimon J. Gerraty 			break;
306956e45f6SSimon J. Gerraty 		case 't':
3079f45a3c8SSimon J. Gerraty 			debug.DEBUG_TARG = true;
308956e45f6SSimon J. Gerraty 			break;
309956e45f6SSimon J. Gerraty 		case 'V':
310b0c40a00SSimon J. Gerraty 			opts.debugVflag = true;
311956e45f6SSimon J. Gerraty 			break;
312956e45f6SSimon J. Gerraty 		case 'v':
3139f45a3c8SSimon J. Gerraty 			debug.DEBUG_VAR = true;
314956e45f6SSimon J. Gerraty 			break;
315956e45f6SSimon J. Gerraty 		case 'x':
3169f45a3c8SSimon J. Gerraty 			debug.DEBUG_SHELL = true;
317956e45f6SSimon J. Gerraty 			break;
318956e45f6SSimon J. Gerraty 		case 'F':
319dba7b0efSSimon J. Gerraty 			MainParseArgDebugFile(modules + 1);
3201d3f2ddcSSimon J. Gerraty 			goto finish;
3213955d011SMarcel Moolenaar 		default:
3223955d011SMarcel Moolenaar 			(void)fprintf(stderr,
3233955d011SMarcel Moolenaar 			    "%s: illegal argument to d option -- %c\n",
3243955d011SMarcel Moolenaar 			    progname, *modules);
3253955d011SMarcel Moolenaar 			usage();
3263955d011SMarcel Moolenaar 		}
3273955d011SMarcel Moolenaar 	}
328e2eeea75SSimon J. Gerraty 
3291d3f2ddcSSimon J. Gerraty finish:
330e2eeea75SSimon J. Gerraty 	opts.debug = debug;
331e2eeea75SSimon J. Gerraty 
332956e45f6SSimon J. Gerraty 	setvbuf(opts.debug_file, NULL, _IONBF, 0);
3331d3f2ddcSSimon J. Gerraty 	if (opts.debug_file != stdout)
3343955d011SMarcel Moolenaar 		setvbuf(stdout, NULL, _IOLBF, 0);
3353955d011SMarcel Moolenaar }
3363955d011SMarcel Moolenaar 
3371d3f2ddcSSimon J. Gerraty /* Is path relative or does it contain any relative component "." or ".."? */
338b0c40a00SSimon J. Gerraty static bool
339dba7b0efSSimon J. Gerraty IsRelativePath(const char *path)
340e1cee40dSSimon J. Gerraty {
341b0c40a00SSimon J. Gerraty 	const char *p;
342e1cee40dSSimon J. Gerraty 
343e1cee40dSSimon J. Gerraty 	if (path[0] != '/')
344b0c40a00SSimon J. Gerraty 		return true;
345b0c40a00SSimon J. Gerraty 	p = path;
346b0c40a00SSimon J. Gerraty 	while ((p = strstr(p, "/.")) != NULL) {
347b0c40a00SSimon J. Gerraty 		p += 2;
348b0c40a00SSimon J. Gerraty 		if (*p == '.')
349b0c40a00SSimon J. Gerraty 			p++;
350b0c40a00SSimon J. Gerraty 		if (*p == '/' || *p == '\0')
351b0c40a00SSimon J. Gerraty 			return true;
3522c3632d1SSimon J. Gerraty 	}
353b0c40a00SSimon J. Gerraty 	return false;
354e1cee40dSSimon J. Gerraty }
355e1cee40dSSimon J. Gerraty 
356956e45f6SSimon J. Gerraty static void
357956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue)
358956e45f6SSimon J. Gerraty {
359956e45f6SSimon J. Gerraty 	struct stat sa, sb;
360956e45f6SSimon J. Gerraty 
361956e45f6SSimon J. Gerraty 	if (chdir(argvalue) == -1) {
362956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: chdir %s: %s\n",
363956e45f6SSimon J. Gerraty 		    progname, argvalue, strerror(errno));
36406b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
365956e45f6SSimon J. Gerraty 	}
366956e45f6SSimon J. Gerraty 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
367956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
368956e45f6SSimon J. Gerraty 		exit(2);
369956e45f6SSimon J. Gerraty 	}
370dba7b0efSSimon J. Gerraty 	if (!IsRelativePath(argvalue) &&
371956e45f6SSimon J. Gerraty 	    stat(argvalue, &sa) != -1 &&
372956e45f6SSimon J. Gerraty 	    stat(curdir, &sb) != -1 &&
373956e45f6SSimon J. Gerraty 	    sa.st_ino == sb.st_ino &&
374956e45f6SSimon J. Gerraty 	    sa.st_dev == sb.st_dev)
375956e45f6SSimon J. Gerraty 		strncpy(curdir, argvalue, MAXPATHLEN);
376b0c40a00SSimon J. Gerraty 	ignorePWD = true;
377956e45f6SSimon J. Gerraty }
378956e45f6SSimon J. Gerraty 
379956e45f6SSimon J. Gerraty static void
380956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue)
381956e45f6SSimon J. Gerraty {
382e2eeea75SSimon J. Gerraty 	char end;
383e2eeea75SSimon J. Gerraty 	if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
384956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
385956e45f6SSimon J. Gerraty 		    "%s: internal error -- J option malformed (%s)\n",
386956e45f6SSimon J. Gerraty 		    progname, argvalue);
387956e45f6SSimon J. Gerraty 		usage();
388956e45f6SSimon J. Gerraty 	}
389956e45f6SSimon J. Gerraty 	if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
390956e45f6SSimon J. Gerraty 	    (fcntl(jp_1, F_GETFD, 0) < 0)) {
391956e45f6SSimon J. Gerraty 		jp_0 = -1;
392956e45f6SSimon J. Gerraty 		jp_1 = -1;
393b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
394956e45f6SSimon J. Gerraty 	} else {
395dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-J");
396dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
397956e45f6SSimon J. Gerraty 	}
398956e45f6SSimon J. Gerraty }
399956e45f6SSimon J. Gerraty 
400956e45f6SSimon J. Gerraty static void
40198875883SSimon J. Gerraty MainParseArgJobs(const char *arg)
402956e45f6SSimon J. Gerraty {
40398875883SSimon J. Gerraty 	const char *p;
40498875883SSimon J. Gerraty 	char *end;
40598875883SSimon J. Gerraty 	char v[12];
406956e45f6SSimon J. Gerraty 
407b0c40a00SSimon J. Gerraty 	forceJobs = true;
40898875883SSimon J. Gerraty 	opts.maxJobs = (int)strtol(arg, &end, 0);
409d5e0a182SSimon J. Gerraty 	p = end;
41098875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
41198875883SSimon J. Gerraty 	if (*p != '\0') {
41298875883SSimon J. Gerraty 		double d;
41398875883SSimon J. Gerraty 
414d5e0a182SSimon J. Gerraty 		if (*p == 'C')
41598875883SSimon J. Gerraty 			d = (opts.maxJobs > 0) ? opts.maxJobs : 1;
416d5e0a182SSimon J. Gerraty 		else if (*p == '.') {
41798875883SSimon J. Gerraty 			d = strtod(arg, &end);
418d5e0a182SSimon J. Gerraty 			p = end;
41998875883SSimon J. Gerraty 		} else
420d5e0a182SSimon J. Gerraty 			d = 0.0;
421d5e0a182SSimon J. Gerraty 		if (d > 0.0) {
42298875883SSimon J. Gerraty 			p = "";
42398875883SSimon J. Gerraty 			opts.maxJobs = (int)sysconf(_SC_NPROCESSORS_ONLN);
42498875883SSimon J. Gerraty 			opts.maxJobs = (int)(d * (double)opts.maxJobs);
42598875883SSimon J. Gerraty 		}
42698875883SSimon J. Gerraty 	}
42798875883SSimon J. Gerraty #endif
428956e45f6SSimon J. Gerraty 	if (*p != '\0' || opts.maxJobs < 1) {
429956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
43098875883SSimon J. Gerraty 		    "%s: argument '%s' to option '-j' "
43198875883SSimon J. Gerraty 		    "must be a positive number\n",
43298875883SSimon J. Gerraty 		    progname, arg);
43306b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
434956e45f6SSimon J. Gerraty 	}
43598875883SSimon J. Gerraty 	snprintf(v, sizeof(v), "%d", opts.maxJobs);
436dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-j");
43798875883SSimon J. Gerraty 	Global_Append(MAKEFLAGS, v);
43898875883SSimon J. Gerraty 	Global_Set(".MAKE.JOBS", v);
439956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
440956e45f6SSimon J. Gerraty }
441956e45f6SSimon J. Gerraty 
442956e45f6SSimon J. Gerraty static void
443956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue)
444956e45f6SSimon J. Gerraty {
445d5e0a182SSimon J. Gerraty 	if (strncmp(argvalue, ".../", 4) == 0) {
446956e45f6SSimon J. Gerraty 		char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
447956e45f6SSimon J. Gerraty 		if (found_path == NULL)
448956e45f6SSimon J. Gerraty 			return;
449dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, found_path);
450956e45f6SSimon J. Gerraty 		free(found_path);
451956e45f6SSimon J. Gerraty 	} else {
452dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, argvalue);
453956e45f6SSimon J. Gerraty 	}
454dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-m");
455dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, argvalue);
4564fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
457956e45f6SSimon J. Gerraty }
458956e45f6SSimon J. Gerraty 
459b0c40a00SSimon J. Gerraty static bool
4608c973ee2SSimon J. Gerraty MainParseOption(char c, const char *argvalue)
461956e45f6SSimon J. Gerraty {
462956e45f6SSimon J. Gerraty 	switch (c) {
463956e45f6SSimon J. Gerraty 	case '\0':
464956e45f6SSimon J. Gerraty 		break;
465956e45f6SSimon J. Gerraty 	case 'B':
466b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
467dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-B");
4688c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.MODE", "compat");
469956e45f6SSimon J. Gerraty 		break;
470956e45f6SSimon J. Gerraty 	case 'C':
471956e45f6SSimon J. Gerraty 		MainParseArgChdir(argvalue);
472956e45f6SSimon J. Gerraty 		break;
473956e45f6SSimon J. Gerraty 	case 'D':
4749f45a3c8SSimon J. Gerraty 		if (argvalue[0] == '\0')
4759f45a3c8SSimon J. Gerraty 			return false;
4769f45a3c8SSimon J. Gerraty 		Var_SetExpand(SCOPE_GLOBAL, argvalue, "1");
477dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-D");
478dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
479956e45f6SSimon J. Gerraty 		break;
480956e45f6SSimon J. Gerraty 	case 'I':
481d5e0a182SSimon J. Gerraty 		SearchPath_Add(parseIncPath, argvalue);
482dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-I");
483dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
484956e45f6SSimon J. Gerraty 		break;
485956e45f6SSimon J. Gerraty 	case 'J':
486956e45f6SSimon J. Gerraty 		MainParseArgJobsInternal(argvalue);
487956e45f6SSimon J. Gerraty 		break;
488956e45f6SSimon J. Gerraty 	case 'N':
489b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
490b0c40a00SSimon J. Gerraty 		opts.noRecursiveExecute = true;
491dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-N");
492956e45f6SSimon J. Gerraty 		break;
493956e45f6SSimon J. Gerraty 	case 'S':
494b0c40a00SSimon J. Gerraty 		opts.keepgoing = false;
495dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-S");
496956e45f6SSimon J. Gerraty 		break;
497956e45f6SSimon J. Gerraty 	case 'T':
498956e45f6SSimon J. Gerraty 		tracefile = bmake_strdup(argvalue);
499dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-T");
500dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
501956e45f6SSimon J. Gerraty 		break;
502956e45f6SSimon J. Gerraty 	case 'V':
503956e45f6SSimon J. Gerraty 	case 'v':
504e2eeea75SSimon J. Gerraty 		opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
50506b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.variables, bmake_strdup(argvalue));
506956e45f6SSimon J. Gerraty 		/* XXX: Why always -V? */
507dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-V");
508dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
509956e45f6SSimon J. Gerraty 		break;
510956e45f6SSimon J. Gerraty 	case 'W':
511b0c40a00SSimon J. Gerraty 		opts.parseWarnFatal = true;
5129f45a3c8SSimon J. Gerraty 		/* XXX: why no Global_Append? */
513956e45f6SSimon J. Gerraty 		break;
514956e45f6SSimon J. Gerraty 	case 'X':
515b0c40a00SSimon J. Gerraty 		opts.varNoExportEnv = true;
516dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-X");
517956e45f6SSimon J. Gerraty 		break;
518956e45f6SSimon J. Gerraty 	case 'd':
519956e45f6SSimon J. Gerraty 		/* If '-d-opts' don't pass to children */
520956e45f6SSimon J. Gerraty 		if (argvalue[0] == '-')
521956e45f6SSimon J. Gerraty 			argvalue++;
522956e45f6SSimon J. Gerraty 		else {
523dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, "-d");
524dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, argvalue);
525956e45f6SSimon J. Gerraty 		}
526dba7b0efSSimon J. Gerraty 		MainParseArgDebug(argvalue);
527956e45f6SSimon J. Gerraty 		break;
528956e45f6SSimon J. Gerraty 	case 'e':
529b0c40a00SSimon J. Gerraty 		opts.checkEnvFirst = true;
530dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-e");
531956e45f6SSimon J. Gerraty 		break;
532956e45f6SSimon J. Gerraty 	case 'f':
53306b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.makefiles, bmake_strdup(argvalue));
534956e45f6SSimon J. Gerraty 		break;
535956e45f6SSimon J. Gerraty 	case 'i':
536b0c40a00SSimon J. Gerraty 		opts.ignoreErrors = true;
537dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-i");
538956e45f6SSimon J. Gerraty 		break;
539956e45f6SSimon J. Gerraty 	case 'j':
540956e45f6SSimon J. Gerraty 		MainParseArgJobs(argvalue);
541956e45f6SSimon J. Gerraty 		break;
542956e45f6SSimon J. Gerraty 	case 'k':
543b0c40a00SSimon J. Gerraty 		opts.keepgoing = true;
544dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-k");
545956e45f6SSimon J. Gerraty 		break;
546956e45f6SSimon J. Gerraty 	case 'm':
547956e45f6SSimon J. Gerraty 		MainParseArgSysInc(argvalue);
548e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
549956e45f6SSimon J. Gerraty 		break;
550956e45f6SSimon J. Gerraty 	case 'n':
551b0c40a00SSimon J. Gerraty 		opts.noExecute = true;
552dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-n");
553956e45f6SSimon J. Gerraty 		break;
554956e45f6SSimon J. Gerraty 	case 'q':
5559f45a3c8SSimon J. Gerraty 		opts.query = true;
556956e45f6SSimon J. Gerraty 		/* Kind of nonsensical, wot? */
557dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-q");
558956e45f6SSimon J. Gerraty 		break;
559956e45f6SSimon J. Gerraty 	case 'r':
560b0c40a00SSimon J. Gerraty 		opts.noBuiltins = true;
561dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-r");
562956e45f6SSimon J. Gerraty 		break;
563956e45f6SSimon J. Gerraty 	case 's':
5649f45a3c8SSimon J. Gerraty 		opts.silent = true;
565dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-s");
566956e45f6SSimon J. Gerraty 		break;
567956e45f6SSimon J. Gerraty 	case 't':
5689f45a3c8SSimon J. Gerraty 		opts.touch = true;
569dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-t");
570956e45f6SSimon J. Gerraty 		break;
571956e45f6SSimon J. Gerraty 	case 'w':
572b0c40a00SSimon J. Gerraty 		opts.enterFlag = true;
573dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-w");
574956e45f6SSimon J. Gerraty 		break;
575956e45f6SSimon J. Gerraty 	default:
576956e45f6SSimon J. Gerraty 		usage();
577956e45f6SSimon J. Gerraty 	}
578b0c40a00SSimon J. Gerraty 	return true;
579956e45f6SSimon J. Gerraty }
580956e45f6SSimon J. Gerraty 
58106b9b3e0SSimon J. Gerraty /*
58206b9b3e0SSimon J. Gerraty  * Parse the given arguments.  Called from main() and from
5833955d011SMarcel Moolenaar  * Main_ParseArgLine() when the .MAKEFLAGS target is used.
5843955d011SMarcel Moolenaar  *
585956e45f6SSimon J. Gerraty  * The arguments must be treated as read-only and will be freed after the
586956e45f6SSimon J. Gerraty  * call.
5873955d011SMarcel Moolenaar  *
58806b9b3e0SSimon J. Gerraty  * XXX: Deal with command line overriding .MAKEFLAGS in makefile
58906b9b3e0SSimon J. Gerraty  */
5903955d011SMarcel Moolenaar static void
5913955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv)
5923955d011SMarcel Moolenaar {
593956e45f6SSimon J. Gerraty 	char c;
5943955d011SMarcel Moolenaar 	int arginc;
5953955d011SMarcel Moolenaar 	char *argvalue;
5963955d011SMarcel Moolenaar 	char *optscan;
597b0c40a00SSimon J. Gerraty 	bool inOption, dashDash = false;
5983955d011SMarcel Moolenaar 
599956e45f6SSimon J. Gerraty 	const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
6003955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */
6013955d011SMarcel Moolenaar 
6023955d011SMarcel Moolenaar rearg:
603b0c40a00SSimon J. Gerraty 	inOption = false;
6043955d011SMarcel Moolenaar 	optscan = NULL;
6053955d011SMarcel Moolenaar 	while (argc > 1) {
606956e45f6SSimon J. Gerraty 		const char *optspec;
6073955d011SMarcel Moolenaar 		if (!inOption)
6083955d011SMarcel Moolenaar 			optscan = argv[1];
6093955d011SMarcel Moolenaar 		c = *optscan++;
6103955d011SMarcel Moolenaar 		arginc = 0;
6113955d011SMarcel Moolenaar 		if (inOption) {
6123955d011SMarcel Moolenaar 			if (c == '\0') {
613e2eeea75SSimon J. Gerraty 				argv++;
614e2eeea75SSimon J. Gerraty 				argc--;
615b0c40a00SSimon J. Gerraty 				inOption = false;
6163955d011SMarcel Moolenaar 				continue;
6173955d011SMarcel Moolenaar 			}
6183955d011SMarcel Moolenaar 		} else {
6193955d011SMarcel Moolenaar 			if (c != '-' || dashDash)
6203955d011SMarcel Moolenaar 				break;
621b0c40a00SSimon J. Gerraty 			inOption = true;
6223955d011SMarcel Moolenaar 			c = *optscan++;
6233955d011SMarcel Moolenaar 		}
6243955d011SMarcel Moolenaar 		/* '-' found at some earlier point */
625956e45f6SSimon J. Gerraty 		optspec = strchr(optspecs, c);
626956e45f6SSimon J. Gerraty 		if (c != '\0' && optspec != NULL && optspec[1] == ':') {
6279f45a3c8SSimon J. Gerraty 			/*
6289f45a3c8SSimon J. Gerraty 			 * -<something> found, and <something> should have an
6299f45a3c8SSimon J. Gerraty 			 * argument
6309f45a3c8SSimon J. Gerraty 			 */
631b0c40a00SSimon J. Gerraty 			inOption = false;
6323955d011SMarcel Moolenaar 			arginc = 1;
6333955d011SMarcel Moolenaar 			argvalue = optscan;
6343955d011SMarcel Moolenaar 			if (*argvalue == '\0') {
6353955d011SMarcel Moolenaar 				if (argc < 3)
6363955d011SMarcel Moolenaar 					goto noarg;
6373955d011SMarcel Moolenaar 				argvalue = argv[2];
6383955d011SMarcel Moolenaar 				arginc = 2;
6393955d011SMarcel Moolenaar 			}
6403955d011SMarcel Moolenaar 		} else {
6413955d011SMarcel Moolenaar 			argvalue = NULL;
6423955d011SMarcel Moolenaar 		}
6433955d011SMarcel Moolenaar 		switch (c) {
6443955d011SMarcel Moolenaar 		case '\0':
6453955d011SMarcel Moolenaar 			arginc = 1;
646b0c40a00SSimon J. Gerraty 			inOption = false;
6473955d011SMarcel Moolenaar 			break;
6483955d011SMarcel Moolenaar 		case '-':
649b0c40a00SSimon J. Gerraty 			dashDash = true;
6503955d011SMarcel Moolenaar 			break;
6513955d011SMarcel Moolenaar 		default:
6528c973ee2SSimon J. Gerraty 			if (!MainParseOption(c, argvalue))
653956e45f6SSimon J. Gerraty 				goto noarg;
6543955d011SMarcel Moolenaar 		}
6553955d011SMarcel Moolenaar 		argv += arginc;
6563955d011SMarcel Moolenaar 		argc -= arginc;
6573955d011SMarcel Moolenaar 	}
6583955d011SMarcel Moolenaar 
6593955d011SMarcel Moolenaar 	/*
6603955d011SMarcel Moolenaar 	 * See if the rest of the arguments are variable assignments and
6613955d011SMarcel Moolenaar 	 * perform them if so. Else take them to be targets and stuff them
6623955d011SMarcel Moolenaar 	 * on the end of the "create" list.
6633955d011SMarcel Moolenaar 	 */
664dba7b0efSSimon J. Gerraty 	for (; argc > 1; argv++, argc--) {
6659f45a3c8SSimon J. Gerraty 		if (!Parse_VarAssign(argv[1], false, SCOPE_CMDLINE)) {
666e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '\0')
6673955d011SMarcel Moolenaar 				Punt("illegal (null) argument.");
668e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '-' && !dashDash)
6693955d011SMarcel Moolenaar 				goto rearg;
67006b9b3e0SSimon J. Gerraty 			Lst_Append(&opts.create, bmake_strdup(argv[1]));
671956e45f6SSimon J. Gerraty 		}
6723955d011SMarcel Moolenaar 	}
6733955d011SMarcel Moolenaar 
6743955d011SMarcel Moolenaar 	return;
6753955d011SMarcel Moolenaar noarg:
6763955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
6773955d011SMarcel Moolenaar 	    progname, c);
6783955d011SMarcel Moolenaar 	usage();
6793955d011SMarcel Moolenaar }
6803955d011SMarcel Moolenaar 
68106b9b3e0SSimon J. Gerraty /*
68206b9b3e0SSimon J. Gerraty  * Break a line of arguments into words and parse them.
6833955d011SMarcel Moolenaar  *
684956e45f6SSimon J. Gerraty  * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
68506b9b3e0SSimon J. Gerraty  * by main() when reading the MAKEFLAGS environment variable.
68606b9b3e0SSimon J. Gerraty  */
6873955d011SMarcel Moolenaar void
6883955d011SMarcel Moolenaar Main_ParseArgLine(const char *line)
6893955d011SMarcel Moolenaar {
6902c3632d1SSimon J. Gerraty 	Words words;
6912c3632d1SSimon J. Gerraty 	char *buf;
692d5e0a182SSimon J. Gerraty 	const char *p;
6933955d011SMarcel Moolenaar 
6943955d011SMarcel Moolenaar 	if (line == NULL)
6953955d011SMarcel Moolenaar 		return;
696d5e0a182SSimon J. Gerraty 	for (p = line; *p == ' '; p++)
6973955d011SMarcel Moolenaar 		continue;
698d5e0a182SSimon J. Gerraty 	if (p[0] == '\0')
6993955d011SMarcel Moolenaar 		return;
7003955d011SMarcel Moolenaar 
701e2eeea75SSimon J. Gerraty 	{
702dba7b0efSSimon J. Gerraty 		FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE");
703d5e0a182SSimon J. Gerraty 		buf = str_concat3(argv0.str, " ", p);
70406b9b3e0SSimon J. Gerraty 		FStr_Done(&argv0);
705e2eeea75SSimon J. Gerraty 	}
7063955d011SMarcel Moolenaar 
707b0c40a00SSimon J. Gerraty 	words = Str_Words(buf, true);
7082c3632d1SSimon J. Gerraty 	if (words.words == NULL) {
7093955d011SMarcel Moolenaar 		Error("Unterminated quoted string [%s]", buf);
7103955d011SMarcel Moolenaar 		free(buf);
7113955d011SMarcel Moolenaar 		return;
7123955d011SMarcel Moolenaar 	}
7133955d011SMarcel Moolenaar 	free(buf);
7142c3632d1SSimon J. Gerraty 	MainParseArgs((int)words.len, words.words);
7153955d011SMarcel Moolenaar 
7162c3632d1SSimon J. Gerraty 	Words_Free(words);
7173955d011SMarcel Moolenaar }
7183955d011SMarcel Moolenaar 
719b0c40a00SSimon J. Gerraty bool
720b0c40a00SSimon J. Gerraty Main_SetObjdir(bool writable, const char *fmt, ...)
7213955d011SMarcel Moolenaar {
7223955d011SMarcel Moolenaar 	struct stat sb;
723b46b9039SSimon J. Gerraty 	char *path;
724b46b9039SSimon J. Gerraty 	char buf[MAXPATHLEN + 1];
725e23f3f6eSSimon J. Gerraty 	char buf2[MAXPATHLEN + 1];
72645447996SSimon J. Gerraty 	va_list ap;
72745447996SSimon J. Gerraty 
72845447996SSimon J. Gerraty 	va_start(ap, fmt);
729b46b9039SSimon J. Gerraty 	vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
73045447996SSimon J. Gerraty 	va_end(ap);
7313955d011SMarcel Moolenaar 
7323955d011SMarcel Moolenaar 	if (path[0] != '/') {
7334fde40d9SSimon J. Gerraty 		if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN)
734e1cee40dSSimon J. Gerraty 			path = buf2;
7354fde40d9SSimon J. Gerraty 		else
7364fde40d9SSimon J. Gerraty 			return false;
7373955d011SMarcel Moolenaar 	}
7383955d011SMarcel Moolenaar 
7393955d011SMarcel Moolenaar 	/* look for the directory and try to chdir there */
7409f45a3c8SSimon J. Gerraty 	if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))
7419f45a3c8SSimon J. Gerraty 		return false;
7429f45a3c8SSimon J. Gerraty 
7439f45a3c8SSimon J. Gerraty 	if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
7441d3f2ddcSSimon J. Gerraty 		(void)fprintf(stderr, "%s: warning: %s: %s.\n",
745e2eeea75SSimon J. Gerraty 		    progname, path, strerror(errno));
7469f45a3c8SSimon J. Gerraty 		return false;
7479f45a3c8SSimon J. Gerraty 	}
7489f45a3c8SSimon J. Gerraty 
7492c3632d1SSimon J. Gerraty 	snprintf(objdir, sizeof objdir, "%s", path);
750dba7b0efSSimon J. Gerraty 	Global_Set(".OBJDIR", objdir);
7513955d011SMarcel Moolenaar 	setenv("PWD", objdir, 1);
7523955d011SMarcel Moolenaar 	Dir_InitDot();
753e2eeea75SSimon J. Gerraty 	purge_relative_cached_realpaths();
754956e45f6SSimon J. Gerraty 	if (opts.enterFlag && strcmp(objdir, curdir) != 0)
755b0c40a00SSimon J. Gerraty 		enterFlagObj = true;
7569f45a3c8SSimon J. Gerraty 	return true;
7573955d011SMarcel Moolenaar }
7583955d011SMarcel Moolenaar 
759b0c40a00SSimon J. Gerraty static bool
760b0c40a00SSimon J. Gerraty SetVarObjdir(bool writable, const char *var, const char *suffix)
76145447996SSimon J. Gerraty {
762dba7b0efSSimon J. Gerraty 	FStr path = Var_Value(SCOPE_CMDLINE, var);
763b46b9039SSimon J. Gerraty 
76406b9b3e0SSimon J. Gerraty 	if (path.str == NULL || path.str[0] == '\0') {
76506b9b3e0SSimon J. Gerraty 		FStr_Done(&path);
766b0c40a00SSimon J. Gerraty 		return false;
7672c3632d1SSimon J. Gerraty 	}
76845447996SSimon J. Gerraty 
7699f45a3c8SSimon J. Gerraty 	Var_Expand(&path, SCOPE_GLOBAL, VARE_WANTRES);
770b46b9039SSimon J. Gerraty 
7719f45a3c8SSimon J. Gerraty 	(void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
772b46b9039SSimon J. Gerraty 
77306b9b3e0SSimon J. Gerraty 	FStr_Done(&path);
774b0c40a00SSimon J. Gerraty 	return true;
77545447996SSimon J. Gerraty }
77645447996SSimon J. Gerraty 
77706b9b3e0SSimon J. Gerraty /*
778d5e0a182SSimon J. Gerraty  * Splits str into words (in-place, modifying it), adding them to the list.
77906b9b3e0SSimon J. Gerraty  * The string must be kept alive as long as the list.
78006b9b3e0SSimon J. Gerraty  */
781d5e0a182SSimon J. Gerraty void
782d5e0a182SSimon J. Gerraty AppendWords(StringList *lp, char *str)
7833955d011SMarcel Moolenaar {
784d5e0a182SSimon J. Gerraty 	char *p;
785e2eeea75SSimon J. Gerraty 	const char *sep = " \t";
7863955d011SMarcel Moolenaar 
787d5e0a182SSimon J. Gerraty 	for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep))
788d5e0a182SSimon J. Gerraty 		Lst_Append(lp, p);
7893955d011SMarcel Moolenaar }
7903955d011SMarcel Moolenaar 
7913955d011SMarcel Moolenaar #ifdef SIGINFO
7923955d011SMarcel Moolenaar /*ARGSUSED*/
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 {
8118c973ee2SSimon J. Gerraty 	char *mode = Var_Subst("${.MAKE.MODE:tl}",
8128c973ee2SSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_WANTRES);
813956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
8143955d011SMarcel Moolenaar 
815dba7b0efSSimon J. Gerraty 	if (mode[0] != '\0') {
816dba7b0efSSimon J. Gerraty 		if (strstr(mode, "compat") != NULL) {
817b0c40a00SSimon J. Gerraty 			opts.compatMake = true;
818b0c40a00SSimon J. Gerraty 			forceJobs = false;
8193955d011SMarcel Moolenaar 		}
8203955d011SMarcel Moolenaar #if USE_META
821dba7b0efSSimon J. Gerraty 		if (strstr(mode, "meta") != NULL)
822dba7b0efSSimon J. Gerraty 			meta_mode_init(mode);
8233955d011SMarcel Moolenaar #endif
824954401e6SSimon J. Gerraty 		if (strstr(mode, "randomize-targets") != NULL)
825954401e6SSimon J. Gerraty 			opts.randomizeTargets = true;
8263955d011SMarcel Moolenaar 	}
827be19d90bSSimon J. Gerraty 
828dba7b0efSSimon J. Gerraty 	free(mode);
8293955d011SMarcel Moolenaar }
8303955d011SMarcel Moolenaar 
8318695518cSSimon J. Gerraty static void
832b0c40a00SSimon J. Gerraty PrintVar(const char *varname, bool expandVars)
833956e45f6SSimon J. Gerraty {
83406b9b3e0SSimon J. Gerraty 	if (strchr(varname, '$') != NULL) {
8358c973ee2SSimon J. Gerraty 		char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES);
836956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
837956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8389f45a3c8SSimon J. Gerraty 		free(evalue);
839956e45f6SSimon J. Gerraty 
840956e45f6SSimon J. Gerraty 	} else if (expandVars) {
841956e45f6SSimon J. Gerraty 		char *expr = str_concat3("${", varname, "}");
8428c973ee2SSimon J. Gerraty 		char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
843956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
844956e45f6SSimon J. Gerraty 		free(expr);
845956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
8469f45a3c8SSimon J. Gerraty 		free(evalue);
847956e45f6SSimon J. Gerraty 
848956e45f6SSimon J. Gerraty 	} else {
849dba7b0efSSimon J. Gerraty 		FStr value = Var_Value(SCOPE_GLOBAL, varname);
85006b9b3e0SSimon J. Gerraty 		printf("%s\n", value.str != NULL ? value.str : "");
85106b9b3e0SSimon J. Gerraty 		FStr_Done(&value);
852956e45f6SSimon J. Gerraty 	}
853956e45f6SSimon J. Gerraty }
854956e45f6SSimon J. Gerraty 
855e2eeea75SSimon J. Gerraty /*
856b0c40a00SSimon J. Gerraty  * Return a bool based on a variable.
857e2eeea75SSimon J. Gerraty  *
858e2eeea75SSimon J. Gerraty  * If the knob is not set, return the fallback.
859e2eeea75SSimon J. Gerraty  * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
860b0c40a00SSimon J. Gerraty  * is false, otherwise true.
861e2eeea75SSimon J. Gerraty  */
862b0c40a00SSimon J. Gerraty bool
863b0c40a00SSimon J. Gerraty GetBooleanExpr(const char *expr, bool fallback)
864e2eeea75SSimon J. Gerraty {
865e2eeea75SSimon J. Gerraty 	char *value;
866b0c40a00SSimon J. Gerraty 	bool res;
867e2eeea75SSimon J. Gerraty 
8688c973ee2SSimon J. Gerraty 	value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
869e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
870e2eeea75SSimon J. Gerraty 	res = ParseBoolean(value, fallback);
871e2eeea75SSimon J. Gerraty 	free(value);
872e2eeea75SSimon J. Gerraty 	return res;
873e2eeea75SSimon J. Gerraty }
874e2eeea75SSimon J. Gerraty 
875956e45f6SSimon J. Gerraty static void
8768695518cSSimon J. Gerraty doPrintVars(void)
8778695518cSSimon J. Gerraty {
878956e45f6SSimon J. Gerraty 	StringListNode *ln;
879b0c40a00SSimon J. Gerraty 	bool expandVars;
8808695518cSSimon J. Gerraty 
881e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_EXPANDED)
882b0c40a00SSimon J. Gerraty 		expandVars = true;
883956e45f6SSimon J. Gerraty 	else if (opts.debugVflag)
884b0c40a00SSimon J. Gerraty 		expandVars = false;
8858695518cSSimon J. Gerraty 	else
886b0c40a00SSimon J. Gerraty 		expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}",
887b0c40a00SSimon J. Gerraty 		    false);
8888695518cSSimon J. Gerraty 
88906b9b3e0SSimon J. Gerraty 	for (ln = opts.variables.first; ln != NULL; ln = ln->next) {
890956e45f6SSimon J. Gerraty 		const char *varname = ln->datum;
891956e45f6SSimon J. Gerraty 		PrintVar(varname, expandVars);
8928695518cSSimon J. Gerraty 	}
8938695518cSSimon J. Gerraty }
8948695518cSSimon J. Gerraty 
895b0c40a00SSimon J. Gerraty static bool
8968695518cSSimon J. Gerraty runTargets(void)
8978695518cSSimon J. Gerraty {
89806b9b3e0SSimon J. Gerraty 	GNodeList targs = LST_INIT;	/* target nodes to create */
899b0c40a00SSimon J. Gerraty 	bool outOfDate;		/* false if all targets up to date */
9008695518cSSimon J. Gerraty 
9018695518cSSimon J. Gerraty 	/*
9028695518cSSimon J. Gerraty 	 * Have now read the entire graph and need to make a list of
9038695518cSSimon J. Gerraty 	 * targets to create. If none was given on the command line,
9048695518cSSimon J. Gerraty 	 * we consult the parsing module to find the main target(s)
9058695518cSSimon J. Gerraty 	 * to create.
9068695518cSSimon J. Gerraty 	 */
90706b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create))
90806b9b3e0SSimon J. Gerraty 		Parse_MainName(&targs);
9098695518cSSimon J. Gerraty 	else
91006b9b3e0SSimon J. Gerraty 		Targ_FindList(&targs, &opts.create);
9118695518cSSimon J. Gerraty 
912956e45f6SSimon J. Gerraty 	if (!opts.compatMake) {
9138695518cSSimon J. Gerraty 		/*
9148695518cSSimon J. Gerraty 		 * Initialize job module before traversing the graph
9158695518cSSimon J. Gerraty 		 * now that any .BEGIN and .END targets have been read.
9168695518cSSimon J. Gerraty 		 * This is done only if the -q flag wasn't given
9178695518cSSimon J. Gerraty 		 * (to prevent the .BEGIN from being executed should
9188695518cSSimon J. Gerraty 		 * it exist).
9198695518cSSimon J. Gerraty 		 */
9209f45a3c8SSimon J. Gerraty 		if (!opts.query) {
9218695518cSSimon J. Gerraty 			Job_Init();
922b0c40a00SSimon J. Gerraty 			jobsRunning = true;
9238695518cSSimon J. Gerraty 		}
9248695518cSSimon J. Gerraty 
9258695518cSSimon J. Gerraty 		/* Traverse the graph, checking on all the targets */
92606b9b3e0SSimon J. Gerraty 		outOfDate = Make_Run(&targs);
9278695518cSSimon J. Gerraty 	} else {
928954401e6SSimon J. Gerraty 		Compat_MakeAll(&targs);
929b0c40a00SSimon J. Gerraty 		outOfDate = false;
9308695518cSSimon J. Gerraty 	}
931dba7b0efSSimon J. Gerraty 	Lst_Done(&targs);	/* Don't free the targets themselves. */
9328695518cSSimon J. Gerraty 	return outOfDate;
9338695518cSSimon J. Gerraty }
9348695518cSSimon J. Gerraty 
935956e45f6SSimon J. Gerraty /*
9369f45a3c8SSimon J. Gerraty  * Set up the .TARGETS variable to contain the list of targets to be created.
9379f45a3c8SSimon J. Gerraty  * If none specified, make the variable empty for now, the parser will fill
9389f45a3c8SSimon J. Gerraty  * in the default or .MAIN target later.
939956e45f6SSimon J. Gerraty  */
940956e45f6SSimon J. Gerraty static void
941956e45f6SSimon J. Gerraty InitVarTargets(void)
942956e45f6SSimon J. Gerraty {
943956e45f6SSimon J. Gerraty 	StringListNode *ln;
944956e45f6SSimon J. Gerraty 
94506b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create)) {
946dba7b0efSSimon J. Gerraty 		Global_Set(".TARGETS", "");
947956e45f6SSimon J. Gerraty 		return;
948956e45f6SSimon J. Gerraty 	}
949956e45f6SSimon J. Gerraty 
95006b9b3e0SSimon J. Gerraty 	for (ln = opts.create.first; ln != NULL; ln = ln->next) {
951dba7b0efSSimon J. Gerraty 		const char *name = ln->datum;
952dba7b0efSSimon J. Gerraty 		Global_Append(".TARGETS", name);
953956e45f6SSimon J. Gerraty 	}
954956e45f6SSimon J. Gerraty }
955956e45f6SSimon J. Gerraty 
956956e45f6SSimon J. Gerraty static void
957956e45f6SSimon J. Gerraty InitRandom(void)
958956e45f6SSimon J. Gerraty {
959956e45f6SSimon J. Gerraty 	struct timeval tv;
960956e45f6SSimon J. Gerraty 
961956e45f6SSimon J. Gerraty 	gettimeofday(&tv, NULL);
962956e45f6SSimon J. Gerraty 	srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
963956e45f6SSimon J. Gerraty }
964956e45f6SSimon J. Gerraty 
965956e45f6SSimon J. Gerraty static const char *
966dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED)
967956e45f6SSimon J. Gerraty {
968956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE
969e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE;
970956e45f6SSimon J. Gerraty #else
971956e45f6SSimon J. Gerraty     	const char *machine = getenv("MACHINE");
972e2eeea75SSimon J. Gerraty 
973956e45f6SSimon J. Gerraty 	if (machine != NULL)
974956e45f6SSimon J. Gerraty 		return machine;
975956e45f6SSimon J. Gerraty 
976e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE)
977956e45f6SSimon J. Gerraty 	return utsname->machine;
978e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE)
979956e45f6SSimon J. Gerraty 	return MAKE_MACHINE;
980956e45f6SSimon J. Gerraty #else
981956e45f6SSimon J. Gerraty 	return "unknown";
982956e45f6SSimon J. Gerraty #endif
983956e45f6SSimon J. Gerraty #endif
984956e45f6SSimon J. Gerraty }
985956e45f6SSimon J. Gerraty 
986956e45f6SSimon J. Gerraty static const char *
987e2eeea75SSimon J. Gerraty InitVarMachineArch(void)
988956e45f6SSimon J. Gerraty {
989e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH
990e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE_ARCH;
991e2eeea75SSimon J. Gerraty #else
992956e45f6SSimon J. Gerraty 	const char *env = getenv("MACHINE_ARCH");
993956e45f6SSimon J. Gerraty 	if (env != NULL)
994956e45f6SSimon J. Gerraty 		return env;
995956e45f6SSimon J. Gerraty 
996956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW)
997956e45f6SSimon J. Gerraty 	{
998956e45f6SSimon J. Gerraty 		struct utsname utsname;
999e2eeea75SSimon J. Gerraty 		static char machine_arch_buf[sizeof utsname.machine];
1000956e45f6SSimon J. Gerraty 		const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
1001e2eeea75SSimon J. Gerraty 		size_t len = sizeof machine_arch_buf;
1002956e45f6SSimon J. Gerraty 
100306b9b3e0SSimon J. Gerraty 		if (sysctl(mib, (unsigned int)__arraycount(mib),
100406b9b3e0SSimon J. Gerraty 		    machine_arch_buf, &len, NULL, 0) < 0) {
100506b9b3e0SSimon J. Gerraty 			(void)fprintf(stderr, "%s: sysctl failed (%s).\n",
100606b9b3e0SSimon J. Gerraty 			    progname, strerror(errno));
1007956e45f6SSimon J. Gerraty 			exit(2);
1008956e45f6SSimon J. Gerraty 		}
1009956e45f6SSimon J. Gerraty 
1010956e45f6SSimon J. Gerraty 		return machine_arch_buf;
1011956e45f6SSimon J. Gerraty 	}
1012e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH)
1013e2eeea75SSimon J. Gerraty 	return MACHINE_ARCH;
1014e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH)
1015956e45f6SSimon J. Gerraty 	return MAKE_MACHINE_ARCH;
1016956e45f6SSimon J. Gerraty #else
1017956e45f6SSimon J. Gerraty 	return "unknown";
1018956e45f6SSimon J. Gerraty #endif
1019956e45f6SSimon J. Gerraty #endif
1020956e45f6SSimon J. Gerraty }
1021956e45f6SSimon J. Gerraty 
1022956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE
1023956e45f6SSimon J. Gerraty /*
1024956e45f6SSimon J. Gerraty  * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1025956e45f6SSimon J. Gerraty  * since the value of curdir can vary depending on how we got
1026d5e0a182SSimon J. Gerraty  * here.  That is, sitting at a shell prompt (shell that provides $PWD)
1027d5e0a182SSimon J. Gerraty  * or via subdir.mk, in which case it's likely a shell which does
1028956e45f6SSimon J. Gerraty  * not provide it.
1029956e45f6SSimon J. Gerraty  *
1030956e45f6SSimon J. Gerraty  * So, to stop it breaking this case only, we ignore PWD if
1031d5e0a182SSimon J. Gerraty  * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression.
1032956e45f6SSimon J. Gerraty  */
1033956e45f6SSimon J. Gerraty static void
1034956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st)
1035956e45f6SSimon J. Gerraty {
1036956e45f6SSimon J. Gerraty 	char *pwd;
10379f45a3c8SSimon J. Gerraty 	FStr makeobjdir;
1038956e45f6SSimon J. Gerraty 	struct stat pwd_st;
1039956e45f6SSimon J. Gerraty 
1040956e45f6SSimon J. Gerraty 	if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1041956e45f6SSimon J. Gerraty 		return;
1042956e45f6SSimon J. Gerraty 
10439f45a3c8SSimon J. Gerraty 	if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"))
1044956e45f6SSimon J. Gerraty 		return;
1045956e45f6SSimon J. Gerraty 
1046dba7b0efSSimon J. Gerraty 	makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR");
104706b9b3e0SSimon J. Gerraty 	if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
1048956e45f6SSimon J. Gerraty 		goto ignore_pwd;
1049956e45f6SSimon J. Gerraty 
1050956e45f6SSimon J. Gerraty 	if (stat(pwd, &pwd_st) == 0 &&
1051956e45f6SSimon J. Gerraty 	    curdir_st->st_ino == pwd_st.st_ino &&
1052956e45f6SSimon J. Gerraty 	    curdir_st->st_dev == pwd_st.st_dev)
1053956e45f6SSimon J. Gerraty 		(void)strncpy(curdir, pwd, MAXPATHLEN);
1054956e45f6SSimon J. Gerraty 
1055956e45f6SSimon J. Gerraty ignore_pwd:
105606b9b3e0SSimon J. Gerraty 	FStr_Done(&makeobjdir);
1057956e45f6SSimon J. Gerraty }
1058956e45f6SSimon J. Gerraty #endif
1059956e45f6SSimon J. Gerraty 
1060956e45f6SSimon J. Gerraty /*
10619f45a3c8SSimon J. Gerraty  * Find the .OBJDIR.  If MAKEOBJDIRPREFIX, or failing that, MAKEOBJDIR is set
10629f45a3c8SSimon J. Gerraty  * in the environment, try only that value and fall back to .CURDIR if it
10639f45a3c8SSimon J. Gerraty  * does not exist.
1064956e45f6SSimon J. Gerraty  *
1065956e45f6SSimon J. Gerraty  * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
10669f45a3c8SSimon J. Gerraty  * and finally _PATH_OBJDIRPREFIX`pwd`, in that order.  If none of these
10679f45a3c8SSimon J. Gerraty  * paths exist, just use .CURDIR.
1068956e45f6SSimon J. Gerraty  */
1069956e45f6SSimon J. Gerraty static void
1070956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch)
1071956e45f6SSimon J. Gerraty {
1072b0c40a00SSimon J. Gerraty 	bool writable;
1073956e45f6SSimon J. Gerraty 
107406b9b3e0SSimon J. Gerraty 	Dir_InitCur(curdir);
1075b0c40a00SSimon J. Gerraty 	writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true);
1076b0c40a00SSimon J. Gerraty 	(void)Main_SetObjdir(false, "%s", curdir);
1077e2eeea75SSimon J. Gerraty 
1078e2eeea75SSimon J. Gerraty 	if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
1079e2eeea75SSimon J. Gerraty 	    !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
1080e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1081e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
1082e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
1083e2eeea75SSimon J. Gerraty 		(void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
1084956e45f6SSimon J. Gerraty }
1085956e45f6SSimon J. Gerraty 
1086956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */
1087956e45f6SSimon J. Gerraty static void
1088956e45f6SSimon J. Gerraty UnlimitFiles(void)
1089956e45f6SSimon J. Gerraty {
109012904384SSimon J. Gerraty #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
1091956e45f6SSimon J. Gerraty 	struct rlimit rl;
1092956e45f6SSimon J. Gerraty 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1093956e45f6SSimon J. Gerraty 	    rl.rlim_cur != rl.rlim_max) {
10948c973ee2SSimon J. Gerraty #ifdef BMAKE_NOFILE_MAX
10958c973ee2SSimon J. Gerraty 		if (BMAKE_NOFILE_MAX < rl.rlim_max)
10968c973ee2SSimon J. Gerraty 			rl.rlim_cur = BMAKE_NOFILE_MAX;
10978c973ee2SSimon J. Gerraty 		else
10988c973ee2SSimon J. Gerraty #endif
1099956e45f6SSimon J. Gerraty 		rl.rlim_cur = rl.rlim_max;
1100956e45f6SSimon J. Gerraty 		(void)setrlimit(RLIMIT_NOFILE, &rl);
1101956e45f6SSimon J. Gerraty 	}
1102956e45f6SSimon J. Gerraty #endif
1103956e45f6SSimon J. Gerraty }
1104956e45f6SSimon J. Gerraty 
1105956e45f6SSimon J. Gerraty static void
1106956e45f6SSimon J. Gerraty CmdOpts_Init(void)
1107956e45f6SSimon J. Gerraty {
1108b0c40a00SSimon J. Gerraty 	opts.compatMake = false;
11099f45a3c8SSimon J. Gerraty 	memset(&opts.debug, 0, sizeof(opts.debug));
1110dba7b0efSSimon J. Gerraty 	/* opts.debug_file has already been initialized earlier */
1111b0c40a00SSimon J. Gerraty 	opts.strict = false;
1112b0c40a00SSimon J. Gerraty 	opts.debugVflag = false;
1113b0c40a00SSimon J. Gerraty 	opts.checkEnvFirst = false;
111406b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.makefiles);
1115b0c40a00SSimon J. Gerraty 	opts.ignoreErrors = false;	/* Pay attention to non-zero returns */
111606b9b3e0SSimon J. Gerraty 	opts.maxJobs = 1;
1117b0c40a00SSimon J. Gerraty 	opts.keepgoing = false;		/* Stop on error */
1118b0c40a00SSimon J. Gerraty 	opts.noRecursiveExecute = false; /* Execute all .MAKE targets */
1119b0c40a00SSimon J. Gerraty 	opts.noExecute = false;		/* Execute all commands */
11209f45a3c8SSimon J. Gerraty 	opts.query = false;
1121b0c40a00SSimon J. Gerraty 	opts.noBuiltins = false;	/* Read the built-in rules */
11229f45a3c8SSimon J. Gerraty 	opts.silent = false;		/* Print commands as executed */
11239f45a3c8SSimon J. Gerraty 	opts.touch = false;
1124e2eeea75SSimon J. Gerraty 	opts.printVars = PVM_NONE;
112506b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.variables);
1126b0c40a00SSimon J. Gerraty 	opts.parseWarnFatal = false;
1127b0c40a00SSimon J. Gerraty 	opts.enterFlag = false;
1128b0c40a00SSimon J. Gerraty 	opts.varNoExportEnv = false;
112906b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.create);
1130956e45f6SSimon J. Gerraty }
1131956e45f6SSimon J. Gerraty 
113206b9b3e0SSimon J. Gerraty /*
113306b9b3e0SSimon J. Gerraty  * Initialize MAKE and .MAKE to the path of the executable, so that it can be
1134956e45f6SSimon J. Gerraty  * found by execvp(3) and the shells, even after a chdir.
1135956e45f6SSimon J. Gerraty  *
1136956e45f6SSimon J. Gerraty  * If it's a relative path and contains a '/', resolve it to an absolute path.
113706b9b3e0SSimon J. Gerraty  * Otherwise keep it as is, assuming it will be found in the PATH.
113806b9b3e0SSimon J. Gerraty  */
1139956e45f6SSimon J. Gerraty static void
1140956e45f6SSimon J. Gerraty InitVarMake(const char *argv0)
1141956e45f6SSimon J. Gerraty {
1142956e45f6SSimon J. Gerraty 	const char *make = argv0;
1143956e45f6SSimon J. Gerraty 
1144956e45f6SSimon J. Gerraty 	if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
1145956e45f6SSimon J. Gerraty 		char pathbuf[MAXPATHLEN];
114606b9b3e0SSimon J. Gerraty 		const char *abspath = cached_realpath(argv0, pathbuf);
1147956e45f6SSimon J. Gerraty 		struct stat st;
114806b9b3e0SSimon J. Gerraty 		if (abspath != NULL && abspath[0] == '/' &&
114906b9b3e0SSimon J. Gerraty 		    stat(make, &st) == 0)
115006b9b3e0SSimon J. Gerraty 			make = abspath;
1151956e45f6SSimon J. Gerraty 	}
1152956e45f6SSimon J. Gerraty 
1153dba7b0efSSimon J. Gerraty 	Global_Set("MAKE", make);
1154dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE", make);
1155956e45f6SSimon J. Gerraty }
1156956e45f6SSimon J. Gerraty 
115706b9b3e0SSimon J. Gerraty /*
115806b9b3e0SSimon J. Gerraty  * Add the directories from the colon-separated syspath to defSysIncPath.
115906b9b3e0SSimon J. Gerraty  * After returning, the contents of syspath is unspecified.
116006b9b3e0SSimon J. Gerraty  */
1161956e45f6SSimon J. Gerraty static void
1162956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath)
1163956e45f6SSimon J. Gerraty {
1164956e45f6SSimon J. Gerraty 	static char defsyspath[] = _PATH_DEFSYSPATH;
1165d5e0a182SSimon J. Gerraty 	char *start, *p;
1166956e45f6SSimon J. Gerraty 
1167956e45f6SSimon J. Gerraty 	/*
1168956e45f6SSimon J. Gerraty 	 * If no user-supplied system path was given (through the -m option)
1169956e45f6SSimon J. Gerraty 	 * add the directories from the DEFSYSPATH (more than one may be given
1170956e45f6SSimon J. Gerraty 	 * as dir1:...:dirn) to the system include path.
1171956e45f6SSimon J. Gerraty 	 */
1172956e45f6SSimon J. Gerraty 	if (syspath == NULL || syspath[0] == '\0')
1173956e45f6SSimon J. Gerraty 		syspath = defsyspath;
1174956e45f6SSimon J. Gerraty 	else
1175956e45f6SSimon J. Gerraty 		syspath = bmake_strdup(syspath);
1176956e45f6SSimon J. Gerraty 
1177d5e0a182SSimon J. Gerraty 	for (start = syspath; *start != '\0'; start = p) {
1178d5e0a182SSimon J. Gerraty 		for (p = start; *p != '\0' && *p != ':'; p++)
1179956e45f6SSimon J. Gerraty 			continue;
1180d5e0a182SSimon J. Gerraty 		if (*p == ':')
1181d5e0a182SSimon J. Gerraty 			*p++ = '\0';
1182e2eeea75SSimon J. Gerraty 
1183956e45f6SSimon J. Gerraty 		/* look for magic parent directory search string */
1184e2eeea75SSimon J. Gerraty 		if (strncmp(start, ".../", 4) == 0) {
1185956e45f6SSimon J. Gerraty 			char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1186956e45f6SSimon J. Gerraty 			if (dir != NULL) {
1187dba7b0efSSimon J. Gerraty 				(void)SearchPath_Add(defSysIncPath, dir);
1188956e45f6SSimon J. Gerraty 				free(dir);
1189956e45f6SSimon J. Gerraty 			}
1190e2eeea75SSimon J. Gerraty 		} else {
1191dba7b0efSSimon J. Gerraty 			(void)SearchPath_Add(defSysIncPath, start);
1192956e45f6SSimon J. Gerraty 		}
1193956e45f6SSimon J. Gerraty 	}
1194956e45f6SSimon J. Gerraty 
1195956e45f6SSimon J. Gerraty 	if (syspath != defsyspath)
1196956e45f6SSimon J. Gerraty 		free(syspath);
1197956e45f6SSimon J. Gerraty }
1198956e45f6SSimon J. Gerraty 
1199956e45f6SSimon J. Gerraty static void
1200956e45f6SSimon J. Gerraty ReadBuiltinRules(void)
1201956e45f6SSimon J. Gerraty {
1202e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1203dba7b0efSSimon J. Gerraty 	StringList sysMkFiles = LST_INIT;
1204e2eeea75SSimon J. Gerraty 
1205dba7b0efSSimon J. Gerraty 	SearchPath_Expand(
1206dba7b0efSSimon J. Gerraty 	    Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath,
1207dba7b0efSSimon J. Gerraty 	    _PATH_DEFSYSMK,
1208dba7b0efSSimon J. Gerraty 	    &sysMkFiles);
1209dba7b0efSSimon J. Gerraty 	if (Lst_IsEmpty(&sysMkFiles))
1210956e45f6SSimon J. Gerraty 		Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1211e2eeea75SSimon J. Gerraty 
1212dba7b0efSSimon J. Gerraty 	for (ln = sysMkFiles.first; ln != NULL; ln = ln->next)
12139f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1214e2eeea75SSimon J. Gerraty 			break;
1215e2eeea75SSimon J. Gerraty 
1216e2eeea75SSimon J. Gerraty 	if (ln == NULL)
1217e2eeea75SSimon J. Gerraty 		Fatal("%s: cannot open %s.",
1218dba7b0efSSimon J. Gerraty 		    progname, (const char *)sysMkFiles.first->datum);
1219e2eeea75SSimon J. Gerraty 
12209f45a3c8SSimon J. Gerraty 	Lst_DoneCall(&sysMkFiles, free);
1221956e45f6SSimon J. Gerraty }
1222956e45f6SSimon J. Gerraty 
1223956e45f6SSimon J. Gerraty static void
1224956e45f6SSimon J. Gerraty InitMaxJobs(void)
1225956e45f6SSimon J. Gerraty {
1226956e45f6SSimon J. Gerraty 	char *value;
1227956e45f6SSimon J. Gerraty 	int n;
1228956e45f6SSimon J. Gerraty 
1229956e45f6SSimon J. Gerraty 	if (forceJobs || opts.compatMake ||
1230dba7b0efSSimon J. Gerraty 	    !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
1231956e45f6SSimon J. Gerraty 		return;
1232956e45f6SSimon J. Gerraty 
12338c973ee2SSimon J. Gerraty 	value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES);
1234956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1235956e45f6SSimon J. Gerraty 	n = (int)strtol(value, NULL, 0);
1236956e45f6SSimon J. Gerraty 	if (n < 1) {
1237956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
1238956e45f6SSimon J. Gerraty 		    "%s: illegal value for .MAKE.JOBS "
1239956e45f6SSimon J. Gerraty 		    "-- must be positive integer!\n",
1240956e45f6SSimon J. Gerraty 		    progname);
124106b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
1242956e45f6SSimon J. Gerraty 	}
1243956e45f6SSimon J. Gerraty 
1244956e45f6SSimon J. Gerraty 	if (n != opts.maxJobs) {
1245dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-j");
1246dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, value);
1247956e45f6SSimon J. Gerraty 	}
1248956e45f6SSimon J. Gerraty 
1249956e45f6SSimon J. Gerraty 	opts.maxJobs = n;
1250956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1251b0c40a00SSimon J. Gerraty 	forceJobs = true;
1252956e45f6SSimon J. Gerraty 	free(value);
1253956e45f6SSimon J. Gerraty }
1254956e45f6SSimon J. Gerraty 
1255956e45f6SSimon J. Gerraty /*
1256956e45f6SSimon J. Gerraty  * For compatibility, look at the directories in the VPATH variable
1257956e45f6SSimon J. Gerraty  * and add them to the search path, if the variable is defined. The
1258956e45f6SSimon J. Gerraty  * variable's value is in the same format as the PATH environment
1259956e45f6SSimon J. Gerraty  * variable, i.e. <directory>:<directory>:<directory>...
1260956e45f6SSimon J. Gerraty  */
1261956e45f6SSimon J. Gerraty static void
1262956e45f6SSimon J. Gerraty InitVpath(void)
1263956e45f6SSimon J. Gerraty {
1264956e45f6SSimon J. Gerraty 	char *vpath, savec, *path;
1265dba7b0efSSimon J. Gerraty 	if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
1266956e45f6SSimon J. Gerraty 		return;
1267956e45f6SSimon J. Gerraty 
12688c973ee2SSimon J. Gerraty 	vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES);
1269956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1270956e45f6SSimon J. Gerraty 	path = vpath;
1271956e45f6SSimon J. Gerraty 	do {
1272d5e0a182SSimon J. Gerraty 		char *p;
1273956e45f6SSimon J. Gerraty 		/* skip to end of directory */
1274d5e0a182SSimon J. Gerraty 		for (p = path; *p != ':' && *p != '\0'; p++)
1275956e45f6SSimon J. Gerraty 			continue;
1276956e45f6SSimon J. Gerraty 		/* Save terminator character so know when to stop */
1277d5e0a182SSimon J. Gerraty 		savec = *p;
1278d5e0a182SSimon J. Gerraty 		*p = '\0';
1279956e45f6SSimon J. Gerraty 		/* Add directory to search path */
1280dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(&dirSearchPath, path);
1281d5e0a182SSimon J. Gerraty 		*p = savec;
1282d5e0a182SSimon J. Gerraty 		path = p + 1;
1283956e45f6SSimon J. Gerraty 	} while (savec == ':');
1284956e45f6SSimon J. Gerraty 	free(vpath);
1285956e45f6SSimon J. Gerraty }
1286956e45f6SSimon J. Gerraty 
1287956e45f6SSimon J. Gerraty static void
12889f45a3c8SSimon J. Gerraty ReadAllMakefiles(const StringList *makefiles)
1289956e45f6SSimon J. Gerraty {
1290956e45f6SSimon J. Gerraty 	StringListNode *ln;
1291956e45f6SSimon J. Gerraty 
1292e2eeea75SSimon J. Gerraty 	for (ln = makefiles->first; ln != NULL; ln = ln->next) {
1293e2eeea75SSimon J. Gerraty 		const char *fname = ln->datum;
12949f45a3c8SSimon J. Gerraty 		if (!ReadMakefile(fname))
1295e2eeea75SSimon J. Gerraty 			Fatal("%s: cannot open %s.", progname, fname);
1296956e45f6SSimon J. Gerraty 	}
1297956e45f6SSimon J. Gerraty }
1298956e45f6SSimon J. Gerraty 
1299956e45f6SSimon J. Gerraty static void
1300e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void)
1301956e45f6SSimon J. Gerraty {
13029f45a3c8SSimon J. Gerraty 	StringList makefiles = LST_INIT;
1303e2eeea75SSimon J. Gerraty 	StringListNode *ln;
13048c973ee2SSimon J. Gerraty 	char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
13058c973ee2SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_WANTRES);
1306e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
1307956e45f6SSimon J. Gerraty 
1308d5e0a182SSimon J. Gerraty 	AppendWords(&makefiles, prefs);
1309956e45f6SSimon J. Gerraty 
13109f45a3c8SSimon J. Gerraty 	for (ln = makefiles.first; ln != NULL; ln = ln->next)
13119f45a3c8SSimon J. Gerraty 		if (ReadMakefile(ln->datum))
1312e2eeea75SSimon J. Gerraty 			break;
1313956e45f6SSimon J. Gerraty 
13149f45a3c8SSimon J. Gerraty 	Lst_Done(&makefiles);
1315e2eeea75SSimon J. Gerraty 	free(prefs);
1316956e45f6SSimon J. Gerraty }
1317956e45f6SSimon J. Gerraty 
131806b9b3e0SSimon J. Gerraty /*
131906b9b3e0SSimon J. Gerraty  * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
1320e2eeea75SSimon J. Gerraty  * Initialize a few modules.
132106b9b3e0SSimon J. Gerraty  * Parse the arguments from MAKEFLAGS and the command line.
132206b9b3e0SSimon J. Gerraty  */
1323e2eeea75SSimon J. Gerraty static void
1324e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv)
13253955d011SMarcel Moolenaar {
1326956e45f6SSimon J. Gerraty 	struct stat sa;
1327956e45f6SSimon J. Gerraty 	const char *machine;
1328956e45f6SSimon J. Gerraty 	const char *machine_arch;
13293955d011SMarcel Moolenaar 	char *syspath = getenv("MAKESYSPATH");
13303955d011SMarcel Moolenaar 	struct utsname utsname;
13313955d011SMarcel Moolenaar 
13323955d011SMarcel Moolenaar 	/* default to writing debug to stderr */
1333956e45f6SSimon J. Gerraty 	opts.debug_file = stderr;
13343955d011SMarcel Moolenaar 
13359f45a3c8SSimon J. Gerraty 	Str_Intern_Init();
1336e2eeea75SSimon J. Gerraty 	HashTable_Init(&cached_realpaths);
1337e2eeea75SSimon J. Gerraty 
13383955d011SMarcel Moolenaar #ifdef SIGINFO
13393955d011SMarcel Moolenaar 	(void)bmake_signal(SIGINFO, siginfo);
13403955d011SMarcel Moolenaar #endif
1341956e45f6SSimon J. Gerraty 
1342956e45f6SSimon J. Gerraty 	InitRandom();
13433955d011SMarcel Moolenaar 
134406b9b3e0SSimon J. Gerraty 	progname = str_basename(argv[0]);
1345956e45f6SSimon J. Gerraty 
1346956e45f6SSimon J. Gerraty 	UnlimitFiles();
13473955d011SMarcel Moolenaar 
13481748de26SSimon J. Gerraty 	if (uname(&utsname) == -1) {
13491748de26SSimon J. Gerraty 		(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
13501748de26SSimon J. Gerraty 		    strerror(errno));
13511748de26SSimon J. Gerraty 		exit(2);
13521748de26SSimon J. Gerraty 	}
13531748de26SSimon J. Gerraty 
1354e2eeea75SSimon J. Gerraty 	machine = InitVarMachine(&utsname);
1355e2eeea75SSimon J. Gerraty 	machine_arch = InitVarMachineArch();
13563955d011SMarcel Moolenaar 
13573955d011SMarcel Moolenaar 	myPid = getpid();	/* remember this for vFork() */
13583955d011SMarcel Moolenaar 
1359d5e0a182SSimon J. Gerraty 	/* Just in case MAKEOBJDIR wants us to do something tricky. */
1360e2eeea75SSimon J. Gerraty 	Targ_Init();
1361e2eeea75SSimon J. Gerraty 	Var_Init();
13624fde40d9SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.OS", utsname.sysname);
1363dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE", machine);
1364dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE_ARCH", machine_arch);
13653955d011SMarcel Moolenaar #ifdef MAKE_VERSION
1366dba7b0efSSimon J. Gerraty 	Global_Set("MAKE_VERSION", MAKE_VERSION);
13673955d011SMarcel Moolenaar #endif
1368d5e0a182SSimon J. Gerraty 	Global_Set_ReadOnly(".newline", "\n");
13693955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST
13709f45a3c8SSimon J. Gerraty 	/* This is the traditional preference for makefiles. */
13713955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
13723955d011SMarcel Moolenaar #endif
13738c973ee2SSimon J. Gerraty 	Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST);
13744fde40d9SSimon J. Gerraty 	Global_Set(".MAKE.DEPENDFILE", ".depend");
137598875883SSimon J. Gerraty 	/* Tell makefiles like jobs.mk whether we support -jC */
137698875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN
137798875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "yes");
137898875883SSimon J. Gerraty #else
137998875883SSimon J. Gerraty 	Global_Set_ReadOnly(".MAKE.JOBS.C", "no");
138098875883SSimon J. Gerraty #endif
13813955d011SMarcel Moolenaar 
1382956e45f6SSimon J. Gerraty 	CmdOpts_Init();
1383b0c40a00SSimon J. Gerraty 	allPrecious = false;	/* Remove targets when interrupted */
1384b0c40a00SSimon J. Gerraty 	deleteOnError = false;	/* Historical default behavior */
1385b0c40a00SSimon J. Gerraty 	jobsRunning = false;
13863955d011SMarcel Moolenaar 
1387956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1388b0c40a00SSimon J. Gerraty 	ignorePWD = false;
13893955d011SMarcel Moolenaar 
13903955d011SMarcel Moolenaar 	/*
13913955d011SMarcel Moolenaar 	 * Initialize the parsing, directory and variable modules to prepare
13923955d011SMarcel Moolenaar 	 * for the reading of inclusion paths and variable settings on the
13933955d011SMarcel Moolenaar 	 * command line
13943955d011SMarcel Moolenaar 	 */
13953955d011SMarcel Moolenaar 
13963955d011SMarcel Moolenaar 	/*
13973955d011SMarcel Moolenaar 	 * Initialize various variables.
13983955d011SMarcel Moolenaar 	 *	MAKE also gets this name, for compatibility
13993955d011SMarcel Moolenaar 	 *	.MAKEFLAGS gets set to the empty string just in case.
14003955d011SMarcel Moolenaar 	 *	MFLAGS also gets initialized empty, for compatibility.
14013955d011SMarcel Moolenaar 	 */
14023955d011SMarcel Moolenaar 	Parse_Init();
1403956e45f6SSimon J. Gerraty 	InitVarMake(argv[0]);
1404dba7b0efSSimon J. Gerraty 	Global_Set(MAKEFLAGS, "");
14058c973ee2SSimon J. Gerraty 	Global_Set(".MAKEOVERRIDES", "");
1406dba7b0efSSimon J. Gerraty 	Global_Set("MFLAGS", "");
1407dba7b0efSSimon J. Gerraty 	Global_Set(".ALLTARGETS", "");
14084fde40d9SSimon J. Gerraty 	Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV);
14093955d011SMarcel Moolenaar 
1410e2eeea75SSimon J. Gerraty 	/* Set some other useful variables. */
14113955d011SMarcel Moolenaar 	{
14129f45a3c8SSimon J. Gerraty 		char buf[64], *ep = getenv(MAKE_LEVEL_ENV);
14133955d011SMarcel Moolenaar 
1414e2eeea75SSimon J. Gerraty 		makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
141551ee2c1cSSimon J. Gerraty 		if (makelevel < 0)
141651ee2c1cSSimon J. Gerraty 			makelevel = 0;
14179f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%d", makelevel);
14188c973ee2SSimon J. Gerraty 		Global_Set(".MAKE.LEVEL", buf);
14199f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", myPid);
14204fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PID", buf);
14219f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getppid());
14224fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.PPID", buf);
14239f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getuid());
14244fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.UID", buf);
14259f45a3c8SSimon J. Gerraty 		snprintf(buf, sizeof buf, "%u", getgid());
14264fde40d9SSimon J. Gerraty 		Global_Set_ReadOnly(".MAKE.GID", buf);
14273955d011SMarcel Moolenaar 	}
142851ee2c1cSSimon J. Gerraty 	if (makelevel > 0) {
142951ee2c1cSSimon J. Gerraty 		char pn[1024];
1430e2eeea75SSimon J. Gerraty 		snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
143151ee2c1cSSimon J. Gerraty 		progname = bmake_strdup(pn);
143251ee2c1cSSimon J. Gerraty 	}
14333955d011SMarcel Moolenaar 
14341748de26SSimon J. Gerraty #ifdef USE_META
14351748de26SSimon J. Gerraty 	meta_init();
14361748de26SSimon J. Gerraty #endif
14372c3632d1SSimon J. Gerraty 	Dir_Init();
14381ce939a7SSimon J. Gerraty 
14399f45a3c8SSimon J. Gerraty 	{
14409f45a3c8SSimon J. Gerraty 		char *makeflags = explode(getenv("MAKEFLAGS"));
14419f45a3c8SSimon J. Gerraty 		Main_ParseArgLine(makeflags);
14429f45a3c8SSimon J. Gerraty 		free(makeflags);
14439f45a3c8SSimon J. Gerraty 	}
14443955d011SMarcel Moolenaar 
14453955d011SMarcel Moolenaar 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
14463955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: getcwd: %s.\n",
14473955d011SMarcel Moolenaar 		    progname, strerror(errno));
14483955d011SMarcel Moolenaar 		exit(2);
14493955d011SMarcel Moolenaar 	}
14503955d011SMarcel Moolenaar 
14513955d011SMarcel Moolenaar 	MainParseArgs(argc, argv);
14523955d011SMarcel Moolenaar 
1453956e45f6SSimon J. Gerraty 	if (opts.enterFlag)
145451ee2c1cSSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, curdir);
145551ee2c1cSSimon J. Gerraty 
14563955d011SMarcel Moolenaar 	if (stat(curdir, &sa) == -1) {
14573955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: %s: %s.\n",
14583955d011SMarcel Moolenaar 		    progname, curdir, strerror(errno));
14593955d011SMarcel Moolenaar 		exit(2);
14603955d011SMarcel Moolenaar 	}
14613955d011SMarcel Moolenaar 
14623955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE
1463956e45f6SSimon J. Gerraty 	HandlePWD(&sa);
14643955d011SMarcel Moolenaar #endif
1465dba7b0efSSimon J. Gerraty 	Global_Set(".CURDIR", curdir);
14663955d011SMarcel Moolenaar 
1467956e45f6SSimon J. Gerraty 	InitObjdir(machine, machine_arch);
14683955d011SMarcel Moolenaar 
14693955d011SMarcel Moolenaar 	Arch_Init();
14703955d011SMarcel Moolenaar 	Suff_Init();
14713955d011SMarcel Moolenaar 	Trace_Init(tracefile);
14723955d011SMarcel Moolenaar 
1473e2eeea75SSimon J. Gerraty 	defaultNode = NULL;
14743955d011SMarcel Moolenaar 	(void)time(&now);
14753955d011SMarcel Moolenaar 
14763955d011SMarcel Moolenaar 	Trace_Log(MAKESTART, NULL);
14773955d011SMarcel Moolenaar 
1478956e45f6SSimon J. Gerraty 	InitVarTargets();
14793955d011SMarcel Moolenaar 
1480956e45f6SSimon J. Gerraty 	InitDefSysIncPath(syspath);
1481e2eeea75SSimon J. Gerraty }
14823955d011SMarcel Moolenaar 
148306b9b3e0SSimon J. Gerraty /*
148406b9b3e0SSimon J. Gerraty  * Read the system makefile followed by either makefile, Makefile or the
148506b9b3e0SSimon J. Gerraty  * files given by the -f option. Exit on parse errors.
148606b9b3e0SSimon J. Gerraty  */
1487e2eeea75SSimon J. Gerraty static void
1488e2eeea75SSimon J. Gerraty main_ReadFiles(void)
1489e2eeea75SSimon J. Gerraty {
1490e2eeea75SSimon J. Gerraty 
14914fde40d9SSimon J. Gerraty 	if (Lst_IsEmpty(&sysIncPath->dirs))
14924fde40d9SSimon J. Gerraty 		SearchPath_AddAll(sysIncPath, defSysIncPath);
14934fde40d9SSimon J. Gerraty 
14944fde40d9SSimon J. Gerraty 	Dir_SetSYSPATH();
1495956e45f6SSimon J. Gerraty 	if (!opts.noBuiltins)
1496956e45f6SSimon J. Gerraty 		ReadBuiltinRules();
14973955d011SMarcel Moolenaar 
14982f2a5ecdSSimon J. Gerraty 	posix_state = PS_MAYBE_NEXT_LINE;
149906b9b3e0SSimon J. Gerraty 	if (!Lst_IsEmpty(&opts.makefiles))
150006b9b3e0SSimon J. Gerraty 		ReadAllMakefiles(&opts.makefiles);
1501e2eeea75SSimon J. Gerraty 	else
1502e2eeea75SSimon J. Gerraty 		ReadFirstDefaultMakefile();
1503e2eeea75SSimon J. Gerraty }
1504e2eeea75SSimon J. Gerraty 
1505e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */
1506e2eeea75SSimon J. Gerraty static void
1507e2eeea75SSimon J. Gerraty main_PrepareMaking(void)
1508e2eeea75SSimon J. Gerraty {
15093955d011SMarcel Moolenaar 	/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1510e2eeea75SSimon J. Gerraty 	if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
15118c973ee2SSimon J. Gerraty 		makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
15128c973ee2SSimon J. Gerraty 		    SCOPE_CMDLINE, VARE_WANTRES);
1513956e45f6SSimon J. Gerraty 		if (makeDependfile[0] != '\0') {
1514956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
1515b0c40a00SSimon J. Gerraty 			doing_depend = true;
15162c3632d1SSimon J. Gerraty 			(void)ReadMakefile(makeDependfile);
1517b0c40a00SSimon J. Gerraty 			doing_depend = false;
15183955d011SMarcel Moolenaar 		}
1519956e45f6SSimon J. Gerraty 	}
15203955d011SMarcel Moolenaar 
15214c620fe5SSimon J. Gerraty 	if (enterFlagObj)
15224c620fe5SSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, objdir);
15234c620fe5SSimon J. Gerraty 
152406b9b3e0SSimon J. Gerraty 	MakeMode();
15253955d011SMarcel Moolenaar 
1526956e45f6SSimon J. Gerraty 	{
1527dba7b0efSSimon J. Gerraty 		FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS);
1528dba7b0efSSimon J. Gerraty 		Global_Append("MFLAGS", makeflags.str);
152906b9b3e0SSimon J. Gerraty 		FStr_Done(&makeflags);
1530956e45f6SSimon J. Gerraty 	}
1531e48f47ddSSimon J. Gerraty 
1532956e45f6SSimon J. Gerraty 	InitMaxJobs();
1533e48f47ddSSimon J. Gerraty 
1534e2eeea75SSimon J. Gerraty 	if (!opts.compatMake && !forceJobs)
1535b0c40a00SSimon J. Gerraty 		opts.compatMake = true;
1536e48f47ddSSimon J. Gerraty 
1537956e45f6SSimon J. Gerraty 	if (!opts.compatMake)
15383955d011SMarcel Moolenaar 		Job_ServerStart(maxJobTokens, jp_0, jp_1);
1539956e45f6SSimon J. Gerraty 	DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1540956e45f6SSimon J. Gerraty 	    jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
15413955d011SMarcel Moolenaar 
1542e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_NONE)
1543b0c40a00SSimon J. Gerraty 		Main_ExportMAKEFLAGS(true);	/* initial export */
15443955d011SMarcel Moolenaar 
1545956e45f6SSimon J. Gerraty 	InitVpath();
15463955d011SMarcel Moolenaar 
15473955d011SMarcel Moolenaar 	/*
15483955d011SMarcel Moolenaar 	 * Now that all search paths have been read for suffixes et al, it's
15493955d011SMarcel Moolenaar 	 * time to add the default search path to their lists...
15503955d011SMarcel Moolenaar 	 */
1551b0c40a00SSimon J. Gerraty 	Suff_ExtendPaths();
15523955d011SMarcel Moolenaar 
15533955d011SMarcel Moolenaar 	/*
15543955d011SMarcel Moolenaar 	 * Propagate attributes through :: dependency lists.
15553955d011SMarcel Moolenaar 	 */
15563955d011SMarcel Moolenaar 	Targ_Propagate();
15573955d011SMarcel Moolenaar 
15583955d011SMarcel Moolenaar 	/* print the initial graph, if the user requested it */
15593955d011SMarcel Moolenaar 	if (DEBUG(GRAPH1))
15603955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
15613955d011SMarcel Moolenaar }
15623955d011SMarcel Moolenaar 
156306b9b3e0SSimon J. Gerraty /*
156406b9b3e0SSimon J. Gerraty  * Make the targets.
1565e2eeea75SSimon J. Gerraty  * If the -v or -V options are given, print variables instead.
156606b9b3e0SSimon J. Gerraty  * Return whether any of the targets is out-of-date.
156706b9b3e0SSimon J. Gerraty  */
1568b0c40a00SSimon J. Gerraty static bool
1569e2eeea75SSimon J. Gerraty main_Run(void)
1570e2eeea75SSimon J. Gerraty {
1571e2eeea75SSimon J. Gerraty 	if (opts.printVars != PVM_NONE) {
1572e2eeea75SSimon J. Gerraty 		/* print the values of any variables requested by the user */
1573e2eeea75SSimon J. Gerraty 		doPrintVars();
1574b0c40a00SSimon J. Gerraty 		return false;
1575e2eeea75SSimon J. Gerraty 	} else {
1576e2eeea75SSimon J. Gerraty 		return runTargets();
1577e2eeea75SSimon J. Gerraty 	}
1578e2eeea75SSimon J. Gerraty }
15793955d011SMarcel Moolenaar 
1580e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */
1581e2eeea75SSimon J. Gerraty static void
1582e2eeea75SSimon J. Gerraty main_CleanUp(void)
1583e2eeea75SSimon J. Gerraty {
1584e2eeea75SSimon J. Gerraty #ifdef CLEANUP
158506b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.variables, free);
15869f45a3c8SSimon J. Gerraty 	Lst_DoneCall(&opts.makefiles, free);
158706b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.create, free);
1588e2eeea75SSimon J. Gerraty #endif
1589e2eeea75SSimon J. Gerraty 
1590e2eeea75SSimon J. Gerraty 	if (DEBUG(GRAPH2))
1591e2eeea75SSimon J. Gerraty 		Targ_PrintGraph(2);
1592e2eeea75SSimon J. Gerraty 
1593e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEEND, NULL);
1594e2eeea75SSimon J. Gerraty 
1595e2eeea75SSimon J. Gerraty 	if (enterFlagObj)
1596e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, objdir);
1597e2eeea75SSimon J. Gerraty 	if (opts.enterFlag)
1598e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, curdir);
1599e2eeea75SSimon J. Gerraty 
1600e2eeea75SSimon J. Gerraty #ifdef USE_META
1601e2eeea75SSimon J. Gerraty 	meta_finish();
1602e2eeea75SSimon J. Gerraty #endif
1603e2eeea75SSimon J. Gerraty 	Suff_End();
1604e2eeea75SSimon J. Gerraty 	Targ_End();
1605e2eeea75SSimon J. Gerraty 	Arch_End();
1606e2eeea75SSimon J. Gerraty 	Var_End();
1607e2eeea75SSimon J. Gerraty 	Parse_End();
1608e2eeea75SSimon J. Gerraty 	Dir_End();
1609e2eeea75SSimon J. Gerraty 	Job_End();
1610e2eeea75SSimon J. Gerraty 	Trace_End();
16119f45a3c8SSimon J. Gerraty 	Str_Intern_End();
1612e2eeea75SSimon J. Gerraty }
1613e2eeea75SSimon J. Gerraty 
1614e2eeea75SSimon J. Gerraty /* Determine the exit code. */
1615e2eeea75SSimon J. Gerraty static int
1616b0c40a00SSimon J. Gerraty main_Exit(bool outOfDate)
1617e2eeea75SSimon J. Gerraty {
161812904384SSimon J. Gerraty 	if (opts.strict && (main_errors > 0 || Parse_NumErrors() > 0))
1619956e45f6SSimon J. Gerraty 		return 2;	/* Not 1 so -q can distinguish error */
16203955d011SMarcel Moolenaar 	return outOfDate ? 1 : 0;
16213955d011SMarcel Moolenaar }
16223955d011SMarcel Moolenaar 
1623e2eeea75SSimon J. Gerraty int
1624e2eeea75SSimon J. Gerraty main(int argc, char **argv)
1625e2eeea75SSimon J. Gerraty {
1626b0c40a00SSimon J. Gerraty 	bool outOfDate;
1627e2eeea75SSimon J. Gerraty 
1628e2eeea75SSimon J. Gerraty 	main_Init(argc, argv);
1629e2eeea75SSimon J. Gerraty 	main_ReadFiles();
1630e2eeea75SSimon J. Gerraty 	main_PrepareMaking();
1631e2eeea75SSimon J. Gerraty 	outOfDate = main_Run();
1632e2eeea75SSimon J. Gerraty 	main_CleanUp();
1633e2eeea75SSimon J. Gerraty 	return main_Exit(outOfDate);
1634e2eeea75SSimon J. Gerraty }
1635e2eeea75SSimon J. Gerraty 
163606b9b3e0SSimon J. Gerraty /*
163706b9b3e0SSimon J. Gerraty  * Open and parse the given makefile, with all its side effects.
16389f45a3c8SSimon J. Gerraty  * Return false if the file could not be opened.
16393955d011SMarcel Moolenaar  */
16409f45a3c8SSimon J. Gerraty static bool
16412c3632d1SSimon J. Gerraty ReadMakefile(const char *fname)
16423955d011SMarcel Moolenaar {
16433955d011SMarcel Moolenaar 	int fd;
16442c3632d1SSimon J. Gerraty 	char *name, *path = NULL;
16453955d011SMarcel Moolenaar 
1646e2eeea75SSimon J. Gerraty 	if (strcmp(fname, "-") == 0) {
16479f45a3c8SSimon J. Gerraty 		Parse_File("(stdin)", -1);
1648dba7b0efSSimon J. Gerraty 		Var_Set(SCOPE_INTERNAL, "MAKEFILE", "");
16493955d011SMarcel Moolenaar 	} else {
16503955d011SMarcel Moolenaar 		/* if we've chdir'd, rebuild the path name */
1651e2eeea75SSimon J. Gerraty 		if (strcmp(curdir, objdir) != 0 && *fname != '/') {
16522c3632d1SSimon J. Gerraty 			path = str_concat3(curdir, "/", fname);
16533955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16543955d011SMarcel Moolenaar 			if (fd != -1) {
16553955d011SMarcel Moolenaar 				fname = path;
16563955d011SMarcel Moolenaar 				goto found;
16573955d011SMarcel Moolenaar 			}
16582c3632d1SSimon J. Gerraty 			free(path);
16593955d011SMarcel Moolenaar 
16603955d011SMarcel Moolenaar 			/* If curdir failed, try objdir (ala .depend) */
16612c3632d1SSimon J. Gerraty 			path = str_concat3(objdir, "/", fname);
16623955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
16633955d011SMarcel Moolenaar 			if (fd != -1) {
16643955d011SMarcel Moolenaar 				fname = path;
16653955d011SMarcel Moolenaar 				goto found;
16663955d011SMarcel Moolenaar 			}
16673955d011SMarcel Moolenaar 		} else {
16683955d011SMarcel Moolenaar 			fd = open(fname, O_RDONLY);
16693955d011SMarcel Moolenaar 			if (fd != -1)
16703955d011SMarcel Moolenaar 				goto found;
16713955d011SMarcel Moolenaar 		}
16723955d011SMarcel Moolenaar 		/* look in -I and system include directories. */
16733955d011SMarcel Moolenaar 		name = Dir_FindFile(fname, parseIncPath);
1674e2eeea75SSimon J. Gerraty 		if (name == NULL) {
1675dba7b0efSSimon J. Gerraty 			SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs)
1676956e45f6SSimon J. Gerraty 			    ? defSysIncPath : sysIncPath;
1677956e45f6SSimon J. Gerraty 			name = Dir_FindFile(fname, sysInc);
1678956e45f6SSimon J. Gerraty 		}
1679e2eeea75SSimon J. Gerraty 		if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
16803955d011SMarcel Moolenaar 			free(name);
16813955d011SMarcel Moolenaar 			free(path);
16829f45a3c8SSimon J. Gerraty 			return false;
16833955d011SMarcel Moolenaar 		}
16843955d011SMarcel Moolenaar 		fname = name;
16853955d011SMarcel Moolenaar 		/*
16863955d011SMarcel Moolenaar 		 * set the MAKEFILE variable desired by System V fans -- the
16873955d011SMarcel Moolenaar 		 * placement of the setting here means it gets set to the last
16883955d011SMarcel Moolenaar 		 * makefile specified, as it is set by SysV make.
16893955d011SMarcel Moolenaar 		 */
16903955d011SMarcel Moolenaar found:
16913955d011SMarcel Moolenaar 		if (!doing_depend)
1692dba7b0efSSimon J. Gerraty 			Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname);
16933955d011SMarcel Moolenaar 		Parse_File(fname, fd);
16943955d011SMarcel Moolenaar 	}
16953955d011SMarcel Moolenaar 	free(path);
16969f45a3c8SSimon J. Gerraty 	return true;
16973955d011SMarcel Moolenaar }
16983955d011SMarcel Moolenaar 
1699dba7b0efSSimon J. Gerraty /*
17009f45a3c8SSimon J. Gerraty  * Execute the command in cmd, and return its output (only stdout, not
17019f45a3c8SSimon J. Gerraty  * stderr, possibly empty).  In the output, replace newlines with spaces.
17023955d011SMarcel Moolenaar  */
17033955d011SMarcel Moolenaar char *
17049f45a3c8SSimon J. Gerraty Cmd_Exec(const char *cmd, char **error)
17053955d011SMarcel Moolenaar {
17069f45a3c8SSimon J. Gerraty 	const char *args[4];	/* Arguments for invoking the shell */
170706b9b3e0SSimon J. Gerraty 	int pipefds[2];
17083955d011SMarcel Moolenaar 	int cpid;		/* Child PID */
17093955d011SMarcel Moolenaar 	int pid;		/* PID from wait() */
1710e2eeea75SSimon J. Gerraty 	int status;		/* command exit status */
17113955d011SMarcel Moolenaar 	Buffer buf;		/* buffer to store the result */
17122c3632d1SSimon J. Gerraty 	ssize_t bytes_read;
17139f45a3c8SSimon J. Gerraty 	char *output;
1714d5e0a182SSimon J. Gerraty 	char *p;
17159f45a3c8SSimon J. Gerraty 	int saved_errno;
1716d5e0a182SSimon J. Gerraty 	char cmd_file[MAXPATHLEN];
1717d5e0a182SSimon J. Gerraty 	size_t cmd_len;
1718d5e0a182SSimon J. Gerraty 	int cmd_fd = -1;
17193955d011SMarcel Moolenaar 
1720d5e0a182SSimon J. Gerraty 	if (shellPath == NULL)
17213955d011SMarcel Moolenaar 		Shell_Init();
17229f45a3c8SSimon J. Gerraty 
1723d5e0a182SSimon J. Gerraty 	cmd_len = strlen(cmd);
1724d5e0a182SSimon J. Gerraty 	if (cmd_len > 1000) {
1725d5e0a182SSimon J. Gerraty 		cmd_fd = mkTempFile(NULL, cmd_file, sizeof(cmd_file));
1726d5e0a182SSimon J. Gerraty 		if (cmd_fd >= 0) {
1727d5e0a182SSimon J. Gerraty 			ssize_t n;
1728d5e0a182SSimon J. Gerraty 
1729d5e0a182SSimon J. Gerraty 			n = write(cmd_fd, cmd, cmd_len);
1730d5e0a182SSimon J. Gerraty 			close(cmd_fd);
1731d5e0a182SSimon J. Gerraty 			if (n < (ssize_t)cmd_len) {
1732d5e0a182SSimon J. Gerraty 				unlink(cmd_file);
1733d5e0a182SSimon J. Gerraty 				cmd_fd = -1;
1734d5e0a182SSimon J. Gerraty 			}
1735d5e0a182SSimon J. Gerraty 		}
1736d5e0a182SSimon J. Gerraty 	}
1737d5e0a182SSimon J. Gerraty 
17383955d011SMarcel Moolenaar 	args[0] = shellName;
1739d5e0a182SSimon J. Gerraty 	if (cmd_fd >= 0) {
1740d5e0a182SSimon J. Gerraty 		args[1] = cmd_file;
1741d5e0a182SSimon J. Gerraty 		args[2] = NULL;
1742d5e0a182SSimon J. Gerraty 	} else {
1743d5e0a182SSimon J. Gerraty 		cmd_file[0] = '\0';
17443955d011SMarcel Moolenaar 		args[1] = "-c";
17453955d011SMarcel Moolenaar 		args[2] = cmd;
17463955d011SMarcel Moolenaar 		args[3] = NULL;
1747d5e0a182SSimon J. Gerraty 	}
17489f45a3c8SSimon J. Gerraty 	DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
17493955d011SMarcel Moolenaar 
175006b9b3e0SSimon J. Gerraty 	if (pipe(pipefds) == -1) {
17519f45a3c8SSimon J. Gerraty 		*error = str_concat3(
17529f45a3c8SSimon J. Gerraty 		    "Couldn't create pipe for \"", cmd, "\"");
17539f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17543955d011SMarcel Moolenaar 	}
17553955d011SMarcel Moolenaar 
1756*c59c3bf3SSimon J. Gerraty 	Var_ReexportVars(SCOPE_GLOBAL);
175706b9b3e0SSimon J. Gerraty 
1758dba7b0efSSimon J. Gerraty 	switch (cpid = vfork()) {
17593955d011SMarcel Moolenaar 	case 0:
17609f45a3c8SSimon J. Gerraty 		(void)close(pipefds[0]);
17619f45a3c8SSimon J. Gerraty 		(void)dup2(pipefds[1], STDOUT_FILENO);
176206b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]);
17633955d011SMarcel Moolenaar 
17643955d011SMarcel Moolenaar 		(void)execv(shellPath, UNCONST(args));
17653955d011SMarcel Moolenaar 		_exit(1);
17663955d011SMarcel Moolenaar 		/* NOTREACHED */
17673955d011SMarcel Moolenaar 
17683955d011SMarcel Moolenaar 	case -1:
17699f45a3c8SSimon J. Gerraty 		*error = str_concat3("Couldn't exec \"", cmd, "\"");
17709f45a3c8SSimon J. Gerraty 		return bmake_strdup("");
17719f45a3c8SSimon J. Gerraty 	}
17723955d011SMarcel Moolenaar 
177306b9b3e0SSimon J. Gerraty 	(void)close(pipefds[1]);	/* No need for the writing half */
17743955d011SMarcel Moolenaar 
17759f45a3c8SSimon J. Gerraty 	saved_errno = 0;
1776e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
17773955d011SMarcel Moolenaar 
17783955d011SMarcel Moolenaar 	do {
17793955d011SMarcel Moolenaar 		char result[BUFSIZ];
178006b9b3e0SSimon J. Gerraty 		bytes_read = read(pipefds[0], result, sizeof result);
17812c3632d1SSimon J. Gerraty 		if (bytes_read > 0)
17822c3632d1SSimon J. Gerraty 			Buf_AddBytes(&buf, result, (size_t)bytes_read);
17839f45a3c8SSimon J. Gerraty 	} while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
17842c3632d1SSimon J. Gerraty 	if (bytes_read == -1)
17859f45a3c8SSimon J. Gerraty 		saved_errno = errno;
17863955d011SMarcel Moolenaar 
178706b9b3e0SSimon J. Gerraty 	(void)close(pipefds[0]); /* Close the input side of the pipe. */
17883955d011SMarcel Moolenaar 
1789e2eeea75SSimon J. Gerraty 	while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
1790b0c40a00SSimon J. Gerraty 		JobReapChild(pid, status, false);
1791e2eeea75SSimon J. Gerraty 
17929f45a3c8SSimon J. Gerraty 	if (Buf_EndsWith(&buf, '\n'))
17939f45a3c8SSimon J. Gerraty 		buf.data[buf.len - 1] = '\0';
17943955d011SMarcel Moolenaar 
17959f45a3c8SSimon J. Gerraty 	output = Buf_DoneData(&buf);
1796d5e0a182SSimon J. Gerraty 	for (p = output; *p != '\0'; p++)
1797d5e0a182SSimon J. Gerraty 		if (*p == '\n')
1798d5e0a182SSimon J. Gerraty 			*p = ' ';
17999f45a3c8SSimon J. Gerraty 
18009f45a3c8SSimon J. Gerraty 	if (WIFSIGNALED(status))
18019f45a3c8SSimon J. Gerraty 		*error = str_concat3("\"", cmd, "\" exited on a signal");
18029f45a3c8SSimon J. Gerraty 	else if (WEXITSTATUS(status) != 0)
18039f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18049f45a3c8SSimon J. Gerraty 		    "\"", cmd, "\" returned non-zero status");
18059f45a3c8SSimon J. Gerraty 	else if (saved_errno != 0)
18069f45a3c8SSimon J. Gerraty 		*error = str_concat3(
18079f45a3c8SSimon J. Gerraty 		    "Couldn't read shell's output for \"", cmd, "\"");
18089f45a3c8SSimon J. Gerraty 	else
18099f45a3c8SSimon J. Gerraty 		*error = NULL;
1810d5e0a182SSimon J. Gerraty 	if (cmd_file[0] != '\0')
1811d5e0a182SSimon J. Gerraty 		unlink(cmd_file);
18129f45a3c8SSimon J. Gerraty 	return output;
18133955d011SMarcel Moolenaar }
18143955d011SMarcel Moolenaar 
181506b9b3e0SSimon J. Gerraty /*
181606b9b3e0SSimon J. Gerraty  * Print a printf-style error message.
18173955d011SMarcel Moolenaar  *
18189f45a3c8SSimon J. Gerraty  * In default mode, this error message has no consequences, for compatibility
18199f45a3c8SSimon J. Gerraty  * reasons, in particular it does not affect the exit status.  Only in lint
18209f45a3c8SSimon J. Gerraty  * mode (-dL) it does.
182106b9b3e0SSimon J. Gerraty  */
18223955d011SMarcel Moolenaar void
18233955d011SMarcel Moolenaar Error(const char *fmt, ...)
18243955d011SMarcel Moolenaar {
18253955d011SMarcel Moolenaar 	va_list ap;
18269f45a3c8SSimon J. Gerraty 	FILE *f;
18273955d011SMarcel Moolenaar 
18289f45a3c8SSimon J. Gerraty 	f = opts.debug_file;
18299f45a3c8SSimon J. Gerraty 	if (f == stdout)
18309f45a3c8SSimon J. Gerraty 		f = stderr;
18313955d011SMarcel Moolenaar 	(void)fflush(stdout);
18329f45a3c8SSimon J. Gerraty 
18333955d011SMarcel Moolenaar 	for (;;) {
18349f45a3c8SSimon J. Gerraty 		fprintf(f, "%s: ", progname);
18353955d011SMarcel Moolenaar 		va_start(ap, fmt);
18369f45a3c8SSimon J. Gerraty 		(void)vfprintf(f, fmt, ap);
18373955d011SMarcel Moolenaar 		va_end(ap);
18389f45a3c8SSimon J. Gerraty 		(void)fprintf(f, "\n");
18399f45a3c8SSimon J. Gerraty 		(void)fflush(f);
18409f45a3c8SSimon J. Gerraty 		if (f == stderr)
18413955d011SMarcel Moolenaar 			break;
18429f45a3c8SSimon J. Gerraty 		f = stderr;
18433955d011SMarcel Moolenaar 	}
184406b9b3e0SSimon J. Gerraty 	main_errors++;
18453955d011SMarcel Moolenaar }
18463955d011SMarcel Moolenaar 
184706b9b3e0SSimon J. Gerraty /*
184806b9b3e0SSimon J. Gerraty  * Wait for any running jobs to finish, then produce an error message,
1849e2eeea75SSimon J. Gerraty  * finally exit immediately.
18503955d011SMarcel Moolenaar  *
1851e2eeea75SSimon J. Gerraty  * Exiting immediately differs from Parse_Error, which exits only after the
185206b9b3e0SSimon J. Gerraty  * current top-level makefile has been parsed completely.
185306b9b3e0SSimon J. Gerraty  */
18543955d011SMarcel Moolenaar void
18553955d011SMarcel Moolenaar Fatal(const char *fmt, ...)
18563955d011SMarcel Moolenaar {
18573955d011SMarcel Moolenaar 	va_list ap;
18583955d011SMarcel Moolenaar 
18593955d011SMarcel Moolenaar 	if (jobsRunning)
18603955d011SMarcel Moolenaar 		Job_Wait();
18613955d011SMarcel Moolenaar 
18623955d011SMarcel Moolenaar 	(void)fflush(stdout);
1863d5e0a182SSimon J. Gerraty 	fprintf(stderr, "%s: ", progname);
1864e2eeea75SSimon J. Gerraty 	va_start(ap, fmt);
18653955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
18663955d011SMarcel Moolenaar 	va_end(ap);
18673955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
18683955d011SMarcel Moolenaar 	(void)fflush(stderr);
18699f45a3c8SSimon J. Gerraty 	PrintStackTrace(true);
18703955d011SMarcel Moolenaar 
18719f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
18723955d011SMarcel Moolenaar 
18733955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
18743955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1875e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
18763955d011SMarcel Moolenaar 	exit(2);		/* Not 1 so -q can distinguish error */
18773955d011SMarcel Moolenaar }
18783955d011SMarcel Moolenaar 
187906b9b3e0SSimon J. Gerraty /*
188006b9b3e0SSimon J. Gerraty  * Major exception once jobs are being created.
188106b9b3e0SSimon J. Gerraty  * Kills all jobs, prints a message and exits.
188206b9b3e0SSimon J. Gerraty  */
18833955d011SMarcel Moolenaar void
18843955d011SMarcel Moolenaar Punt(const char *fmt, ...)
18853955d011SMarcel Moolenaar {
18863955d011SMarcel Moolenaar 	va_list ap;
18873955d011SMarcel Moolenaar 
18883955d011SMarcel Moolenaar 	(void)fflush(stdout);
18893955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: ", progname);
18909f45a3c8SSimon J. Gerraty 	va_start(ap, fmt);
18913955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
18923955d011SMarcel Moolenaar 	va_end(ap);
18933955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
18943955d011SMarcel Moolenaar 	(void)fflush(stderr);
18953955d011SMarcel Moolenaar 
18969f45a3c8SSimon J. Gerraty 	PrintOnError(NULL, "\n");
18973955d011SMarcel Moolenaar 
18983955d011SMarcel Moolenaar 	DieHorribly();
18993955d011SMarcel Moolenaar }
19003955d011SMarcel Moolenaar 
1901956e45f6SSimon J. Gerraty /* Exit without giving a message. */
19023955d011SMarcel Moolenaar void
19033955d011SMarcel Moolenaar DieHorribly(void)
19043955d011SMarcel Moolenaar {
19053955d011SMarcel Moolenaar 	if (jobsRunning)
19063955d011SMarcel Moolenaar 		Job_AbortAll();
19073955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2))
19083955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1909e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
191006b9b3e0SSimon J. Gerraty 	exit(2);		/* Not 1 so -q can distinguish error */
19113955d011SMarcel Moolenaar }
19123955d011SMarcel Moolenaar 
191306b9b3e0SSimon J. Gerraty /*
191406b9b3e0SSimon J. Gerraty  * Called when aborting due to errors in child shell to signal abnormal exit.
1915956e45f6SSimon J. Gerraty  * The program exits.
191606b9b3e0SSimon J. Gerraty  * Errors is the number of errors encountered in Make_Make.
191706b9b3e0SSimon J. Gerraty  */
19183955d011SMarcel Moolenaar void
1919956e45f6SSimon J. Gerraty Finish(int errs)
19203955d011SMarcel Moolenaar {
1921e2eeea75SSimon J. Gerraty 	if (shouldDieQuietly(NULL, -1))
19223841c287SSimon J. Gerraty 		exit(2);
1923956e45f6SSimon J. Gerraty 	Fatal("%d error%s", errs, errs == 1 ? "" : "s");
19243955d011SMarcel Moolenaar }
19253955d011SMarcel Moolenaar 
19264fde40d9SSimon J. Gerraty int
19279f45a3c8SSimon J. Gerraty unlink_file(const char *file)
19283955d011SMarcel Moolenaar {
19293955d011SMarcel Moolenaar 	struct stat st;
19303955d011SMarcel Moolenaar 
19313955d011SMarcel Moolenaar 	if (lstat(file, &st) == -1)
19324fde40d9SSimon J. Gerraty 		return -1;
19333955d011SMarcel Moolenaar 
19343955d011SMarcel Moolenaar 	if (S_ISDIR(st.st_mode)) {
19354fde40d9SSimon J. Gerraty 		/*
19364fde40d9SSimon J. Gerraty 		 * POSIX says for unlink: "The path argument shall not name
19374fde40d9SSimon J. Gerraty 		 * a directory unless [...]".
19384fde40d9SSimon J. Gerraty 		 */
19393955d011SMarcel Moolenaar 		errno = EISDIR;
19404fde40d9SSimon J. Gerraty 		return -1;
19413955d011SMarcel Moolenaar 	}
19424fde40d9SSimon J. Gerraty 	return unlink(file);
19433955d011SMarcel Moolenaar }
19443955d011SMarcel Moolenaar 
1945956e45f6SSimon J. Gerraty static void
1946956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n)
1947956e45f6SSimon J. Gerraty {
1948956e45f6SSimon J. Gerraty 	const char *mem = data;
1949956e45f6SSimon J. Gerraty 
1950956e45f6SSimon J. Gerraty 	while (n > 0) {
1951956e45f6SSimon J. Gerraty 		ssize_t written = write(fd, mem, n);
19529f45a3c8SSimon J. Gerraty 		/* XXX: Should this EAGAIN be EINTR? */
1953956e45f6SSimon J. Gerraty 		if (written == -1 && errno == EAGAIN)
1954956e45f6SSimon J. Gerraty 			continue;
1955956e45f6SSimon J. Gerraty 		if (written == -1)
1956956e45f6SSimon J. Gerraty 			break;
1957956e45f6SSimon J. Gerraty 		mem += written;
1958956e45f6SSimon J. Gerraty 		n -= (size_t)written;
1959956e45f6SSimon J. Gerraty 	}
1960956e45f6SSimon J. Gerraty }
1961956e45f6SSimon J. Gerraty 
19629f45a3c8SSimon J. Gerraty /* Print why exec failed, avoiding stdio. */
1963956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD
1964956e45f6SSimon J. Gerraty execDie(const char *af, const char *av)
19653955d011SMarcel Moolenaar {
1966956e45f6SSimon J. Gerraty 	Buffer buf;
19673955d011SMarcel Moolenaar 
1968e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
1969956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, progname);
1970956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ": ");
1971956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, af);
1972956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, "(");
1973956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, av);
1974956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ") failed (");
1975956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, strerror(errno));
1976956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ")\n");
19773955d011SMarcel Moolenaar 
1978dba7b0efSSimon J. Gerraty 	write_all(STDERR_FILENO, buf.data, buf.len);
1979956e45f6SSimon J. Gerraty 
1980dba7b0efSSimon J. Gerraty 	Buf_Done(&buf);
1981956e45f6SSimon J. Gerraty 	_exit(1);
19823955d011SMarcel Moolenaar }
19833955d011SMarcel Moolenaar 
1984e1cee40dSSimon J. Gerraty static void
1985e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void)
1986e1cee40dSSimon J. Gerraty {
1987d5e0a182SSimon J. Gerraty 	HashEntry *he, *next;
1988956e45f6SSimon J. Gerraty 	HashIter hi;
1989b778b302SSimon J. Gerraty 
1990e2eeea75SSimon J. Gerraty 	HashIter_Init(&hi, &cached_realpaths);
1991956e45f6SSimon J. Gerraty 	he = HashIter_Next(&hi);
1992956e45f6SSimon J. Gerraty 	while (he != NULL) {
1993d5e0a182SSimon J. Gerraty 		next = HashIter_Next(&hi);
1994956e45f6SSimon J. Gerraty 		if (he->key[0] != '/') {
1995e2eeea75SSimon J. Gerraty 			DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
1996e2eeea75SSimon J. Gerraty 			HashTable_DeleteEntry(&cached_realpaths, he);
19979f45a3c8SSimon J. Gerraty 			/*
19989f45a3c8SSimon J. Gerraty 			 * XXX: What about the allocated he->value? Either
19999f45a3c8SSimon J. Gerraty 			 * free them or document why they cannot be freed.
20009f45a3c8SSimon J. Gerraty 			 */
2001b46b9039SSimon J. Gerraty 		}
2002d5e0a182SSimon J. Gerraty 		he = next;
2003b46b9039SSimon J. Gerraty 	}
2004b46b9039SSimon J. Gerraty }
2005e1cee40dSSimon J. Gerraty 
20069f45a3c8SSimon J. Gerraty const char *
2007e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved)
2008e1cee40dSSimon J. Gerraty {
20092c3632d1SSimon J. Gerraty 	const char *rp;
2010e1cee40dSSimon J. Gerraty 
2011e2eeea75SSimon J. Gerraty 	if (pathname == NULL || pathname[0] == '\0')
2012e1cee40dSSimon J. Gerraty 		return NULL;
2013e1cee40dSSimon J. Gerraty 
2014e2eeea75SSimon J. Gerraty 	rp = HashTable_FindValue(&cached_realpaths, pathname);
2015e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2016b778b302SSimon J. Gerraty 		/* a hit */
2017e2eeea75SSimon J. Gerraty 		strncpy(resolved, rp, MAXPATHLEN);
2018e2eeea75SSimon J. Gerraty 		resolved[MAXPATHLEN - 1] = '\0';
2019e2eeea75SSimon J. Gerraty 		return resolved;
2020e2eeea75SSimon J. Gerraty 	}
20213841c287SSimon J. Gerraty 
2022e2eeea75SSimon J. Gerraty 	rp = realpath(pathname, resolved);
2023e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2024e2eeea75SSimon J. Gerraty 		HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
2025e2eeea75SSimon J. Gerraty 		DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
2026e2eeea75SSimon J. Gerraty 		return resolved;
2027e2eeea75SSimon J. Gerraty 	}
2028e2eeea75SSimon J. Gerraty 
2029e2eeea75SSimon J. Gerraty 	/* should we negative-cache? */
2030e2eeea75SSimon J. Gerraty 	return NULL;
2031b778b302SSimon J. Gerraty }
2032b778b302SSimon J. Gerraty 
20333841c287SSimon J. Gerraty /*
20343841c287SSimon J. Gerraty  * Return true if we should die without noise.
2035e2eeea75SSimon J. Gerraty  * For example our failing child was a sub-make or failure happened elsewhere.
20363841c287SSimon J. Gerraty  */
2037b0c40a00SSimon J. Gerraty bool
2038e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf)
20393841c287SSimon J. Gerraty {
20403841c287SSimon J. Gerraty 	static int quietly = -1;
20413841c287SSimon J. Gerraty 
20423841c287SSimon J. Gerraty 	if (quietly < 0) {
2043b0c40a00SSimon J. Gerraty 		if (DEBUG(JOB) ||
2044b0c40a00SSimon J. Gerraty 		    !GetBooleanExpr("${.MAKE.DIE_QUIETLY}", true))
20453841c287SSimon J. Gerraty 			quietly = 0;
20463841c287SSimon J. Gerraty 		else if (bf >= 0)
20473841c287SSimon J. Gerraty 			quietly = bf;
20483841c287SSimon J. Gerraty 		else
204906b9b3e0SSimon J. Gerraty 			quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
20503841c287SSimon J. Gerraty 	}
2051dba7b0efSSimon J. Gerraty 	return quietly != 0;
20523841c287SSimon J. Gerraty }
20533841c287SSimon J. Gerraty 
2054956e45f6SSimon J. Gerraty static void
2055956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn)
2056956e45f6SSimon J. Gerraty {
2057956e45f6SSimon J. Gerraty 	StringListNode *ln;
2058*c59c3bf3SSimon J. Gerraty 	char sts[16];
2059956e45f6SSimon J. Gerraty 
2060956e45f6SSimon J. Gerraty 	/*
2061956e45f6SSimon J. Gerraty 	 * We can print this even if there is no .ERROR target.
2062956e45f6SSimon J. Gerraty 	 */
2063*c59c3bf3SSimon J. Gerraty 	snprintf(sts, sizeof(sts), "%d", gn->exit_status);
2064*c59c3bf3SSimon J. Gerraty 	Global_Set(".ERROR_EXIT", sts);
2065dba7b0efSSimon J. Gerraty 	Global_Set(".ERROR_TARGET", gn->name);
2066dba7b0efSSimon J. Gerraty 	Global_Delete(".ERROR_CMD");
2067956e45f6SSimon J. Gerraty 
206806b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
2069956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
2070956e45f6SSimon J. Gerraty 
2071956e45f6SSimon J. Gerraty 		if (cmd == NULL)
2072956e45f6SSimon J. Gerraty 			break;
2073dba7b0efSSimon J. Gerraty 		Global_Append(".ERROR_CMD", cmd);
2074956e45f6SSimon J. Gerraty 	}
2075956e45f6SSimon J. Gerraty }
2076956e45f6SSimon J. Gerraty 
207706b9b3e0SSimon J. Gerraty /*
207806b9b3e0SSimon J. Gerraty  * Print some helpful information in case of an error.
207906b9b3e0SSimon J. Gerraty  * The caller should exit soon after calling this function.
208006b9b3e0SSimon J. Gerraty  */
20813955d011SMarcel Moolenaar void
2082e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg)
20833955d011SMarcel Moolenaar {
2084e2eeea75SSimon J. Gerraty 	static GNode *errorNode = NULL;
20853955d011SMarcel Moolenaar 
20862c3632d1SSimon J. Gerraty 	if (DEBUG(HASH)) {
20872c3632d1SSimon J. Gerraty 		Targ_Stats();
20882c3632d1SSimon J. Gerraty 		Var_Stats();
20892c3632d1SSimon J. Gerraty 	}
20902c3632d1SSimon J. Gerraty 
209106b9b3e0SSimon J. Gerraty 	if (errorNode != NULL)
209206b9b3e0SSimon J. Gerraty 		return;		/* we've been here! */
20933841c287SSimon J. Gerraty 
20949f45a3c8SSimon J. Gerraty 	printf("%s%s: stopped in %s\n", msg, progname, curdir);
20953955d011SMarcel Moolenaar 
209606b9b3e0SSimon J. Gerraty 	/* we generally want to keep quiet if a sub-make died */
209706b9b3e0SSimon J. Gerraty 	if (shouldDieQuietly(gn, -1))
209806b9b3e0SSimon J. Gerraty 		return;
2099e2eeea75SSimon J. Gerraty 
2100e2eeea75SSimon J. Gerraty 	if (gn != NULL)
2101956e45f6SSimon J. Gerraty 		SetErrorVars(gn);
2102e2eeea75SSimon J. Gerraty 
2103e2eeea75SSimon J. Gerraty 	{
21048c973ee2SSimon J. Gerraty 		char *errorVarsValues = Var_Subst(
21058c973ee2SSimon J. Gerraty 		    "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
21068c973ee2SSimon J. Gerraty 		    SCOPE_GLOBAL, VARE_WANTRES);
2107956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
2108e2eeea75SSimon J. Gerraty 		printf("%s", errorVarsValues);
2109e2eeea75SSimon J. Gerraty 		free(errorVarsValues);
2110e2eeea75SSimon J. Gerraty 	}
2111e2eeea75SSimon J. Gerraty 
2112ac3446e9SSimon J. Gerraty 	fflush(stdout);
2113ac3446e9SSimon J. Gerraty 
21143955d011SMarcel Moolenaar 	/*
21153955d011SMarcel Moolenaar 	 * Finally, see if there is a .ERROR target, and run it if so.
21163955d011SMarcel Moolenaar 	 */
2117e2eeea75SSimon J. Gerraty 	errorNode = Targ_FindNode(".ERROR");
2118e2eeea75SSimon J. Gerraty 	if (errorNode != NULL) {
2119e2eeea75SSimon J. Gerraty 		errorNode->type |= OP_SPECIAL;
2120e2eeea75SSimon J. Gerraty 		Compat_Make(errorNode, errorNode);
21213955d011SMarcel Moolenaar 	}
21223955d011SMarcel Moolenaar }
21233955d011SMarcel Moolenaar 
21243955d011SMarcel Moolenaar void
2125b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(bool first)
21263955d011SMarcel Moolenaar {
2127b0c40a00SSimon J. Gerraty 	static bool once = true;
21289f45a3c8SSimon J. Gerraty 	char *flags;
21293955d011SMarcel Moolenaar 
21303955d011SMarcel Moolenaar 	if (once != first)
21313955d011SMarcel Moolenaar 		return;
2132b0c40a00SSimon J. Gerraty 	once = false;
21333955d011SMarcel Moolenaar 
21348c973ee2SSimon J. Gerraty 	flags = Var_Subst(
21359f45a3c8SSimon J. Gerraty 	    "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
21368c973ee2SSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_WANTRES);
2137956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2138*c59c3bf3SSimon J. Gerraty 	if (flags[0] != '\0')
21399f45a3c8SSimon J. Gerraty 		setenv("MAKEFLAGS", flags, 1);
21403955d011SMarcel Moolenaar }
21413955d011SMarcel Moolenaar 
21423955d011SMarcel Moolenaar char *
21433955d011SMarcel Moolenaar getTmpdir(void)
21443955d011SMarcel Moolenaar {
21453955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
21463955d011SMarcel Moolenaar 	struct stat st;
21473955d011SMarcel Moolenaar 
2148e2eeea75SSimon J. Gerraty 	if (tmpdir != NULL)
2149e2eeea75SSimon J. Gerraty 		return tmpdir;
2150e2eeea75SSimon J. Gerraty 
21519f45a3c8SSimon J. Gerraty 	/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
21528c973ee2SSimon J. Gerraty 	tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
21538c973ee2SSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_WANTRES);
2154956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2155e2eeea75SSimon J. Gerraty 
21563955d011SMarcel Moolenaar 	if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
21573955d011SMarcel Moolenaar 		free(tmpdir);
21583955d011SMarcel Moolenaar 		tmpdir = bmake_strdup(_PATH_TMP);
21593955d011SMarcel Moolenaar 	}
21603955d011SMarcel Moolenaar 	return tmpdir;
21613955d011SMarcel Moolenaar }
21623955d011SMarcel Moolenaar 
21633955d011SMarcel Moolenaar /*
21643955d011SMarcel Moolenaar  * Create and open a temp file using "pattern".
2165d5e0a182SSimon J. Gerraty  * If tfile is provided, set it to a copy of the filename created.
21663955d011SMarcel Moolenaar  * Otherwise unlink the file once open.
21673955d011SMarcel Moolenaar  */
21683955d011SMarcel Moolenaar int
2169dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz)
21703955d011SMarcel Moolenaar {
21713955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
2172dba7b0efSSimon J. Gerraty 	char tbuf[MAXPATHLEN];
21733955d011SMarcel Moolenaar 	int fd;
21743955d011SMarcel Moolenaar 
2175e2eeea75SSimon J. Gerraty 	if (pattern == NULL)
21763955d011SMarcel Moolenaar 		pattern = TMPPAT;
2177956e45f6SSimon J. Gerraty 	if (tmpdir == NULL)
21783955d011SMarcel Moolenaar 		tmpdir = getTmpdir();
2179dba7b0efSSimon J. Gerraty 	if (tfile == NULL) {
2180dba7b0efSSimon J. Gerraty 		tfile = tbuf;
2181dba7b0efSSimon J. Gerraty 		tfile_sz = sizeof tbuf;
2182dba7b0efSSimon J. Gerraty 	}
21839f45a3c8SSimon J. Gerraty 
21849f45a3c8SSimon J. Gerraty 	if (pattern[0] == '/')
2185dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s", pattern);
21869f45a3c8SSimon J. Gerraty 	else
2187dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern);
21889f45a3c8SSimon J. Gerraty 
21893955d011SMarcel Moolenaar 	if ((fd = mkstemp(tfile)) < 0)
2190e2eeea75SSimon J. Gerraty 		Punt("Could not create temporary file %s: %s", tfile,
2191e2eeea75SSimon J. Gerraty 		    strerror(errno));
21929f45a3c8SSimon J. Gerraty 	if (tfile == tbuf)
219306b9b3e0SSimon J. Gerraty 		unlink(tfile);	/* we just want the descriptor */
21949f45a3c8SSimon J. Gerraty 
21953955d011SMarcel Moolenaar 	return fd;
21963955d011SMarcel Moolenaar }
21973955d011SMarcel Moolenaar 
2198be19d90bSSimon J. Gerraty /*
2199e2eeea75SSimon J. Gerraty  * Convert a string representation of a boolean into a boolean value.
2200b0c40a00SSimon J. Gerraty  * Anything that looks like "No", "False", "Off", "0" etc. is false,
2201b0c40a00SSimon J. Gerraty  * the empty string is the fallback, everything else is true.
2202be19d90bSSimon J. Gerraty  */
2203b0c40a00SSimon J. Gerraty bool
2204b0c40a00SSimon J. Gerraty ParseBoolean(const char *s, bool fallback)
2205be19d90bSSimon J. Gerraty {
2206e2eeea75SSimon J. Gerraty 	char ch = ch_tolower(s[0]);
2207e2eeea75SSimon J. Gerraty 	if (ch == '\0')
2208e2eeea75SSimon J. Gerraty 		return fallback;
2209e2eeea75SSimon J. Gerraty 	if (ch == '0' || ch == 'f' || ch == 'n')
2210b0c40a00SSimon J. Gerraty 		return false;
2211e2eeea75SSimon J. Gerraty 	if (ch == 'o')
2212e2eeea75SSimon J. Gerraty 		return ch_tolower(s[1]) != 'f';
2213b0c40a00SSimon J. Gerraty 	return true;
2214be19d90bSSimon J. Gerraty }
2215