xref: /freebsd/contrib/bmake/main.c (revision dba7b0ef928af88caa38728a73657b837aeeac93)
1*dba7b0efSSimon J. Gerraty /*	$NetBSD: main.c,v 1.533 2021/02/05 19:19:17 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  *
76*dba7b0efSSimon J. Gerraty  *	Main_ParseArgLine
77*dba7b0efSSimon J. Gerraty  *			Parse and process command line arguments from a
78*dba7b0efSSimon J. Gerraty  *			single string.  Used to implement the special targets
79*dba7b0efSSimon 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  *
87*dba7b0efSSimon J. Gerraty  *	Finish		Finish things up by printing the number of errors
88*dba7b0efSSimon 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*dba7b0efSSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.533 2021/02/05 19:19:17 sjg Exp $");
115956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && !defined(lint)
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 */
1283955d011SMarcel Moolenaar Boolean allPrecious;		/* .PRECIOUS given on line by itself */
12945447996SSimon J. Gerraty Boolean deleteOnError;		/* .DELETE_ON_ERROR: set */
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar static int maxJobTokens;	/* -j argument */
1324c620fe5SSimon J. Gerraty Boolean enterFlagObj;		/* -w and objdir != srcdir */
133956e45f6SSimon J. Gerraty 
1343955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
1353955d011SMarcel Moolenaar Boolean doing_depend;		/* Set while reading .depend */
1363955d011SMarcel Moolenaar static Boolean jobsRunning;	/* TRUE if the jobs might be running */
1373955d011SMarcel Moolenaar static const char *tracefile;
1382c3632d1SSimon J. Gerraty static int ReadMakefile(const char *);
139e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void);
1403955d011SMarcel Moolenaar 
1413955d011SMarcel Moolenaar static Boolean 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 
1493955d011SMarcel Moolenaar Boolean 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 {
16051ee2c1cSSimon J. Gerraty 	size_t len;
16151ee2c1cSSimon J. Gerraty 	char *nf, *st;
16251ee2c1cSSimon J. Gerraty 	const char *f;
16351ee2c1cSSimon J. Gerraty 
16451ee2c1cSSimon J. Gerraty 	if (flags == NULL)
16551ee2c1cSSimon J. Gerraty 		return NULL;
16651ee2c1cSSimon J. Gerraty 
16706b9b3e0SSimon J. Gerraty 	for (f = flags; *f != '\0'; f++)
168956e45f6SSimon J. Gerraty 		if (!ch_isalpha(*f))
16951ee2c1cSSimon J. Gerraty 			break;
17051ee2c1cSSimon J. Gerraty 
17106b9b3e0SSimon J. Gerraty 	if (*f != '\0')
17251ee2c1cSSimon J. Gerraty 		return bmake_strdup(flags);
17351ee2c1cSSimon J. Gerraty 
17451ee2c1cSSimon J. Gerraty 	len = strlen(flags);
17551ee2c1cSSimon J. Gerraty 	st = nf = bmake_malloc(len * 3 + 1);
17606b9b3e0SSimon J. Gerraty 	while (*flags != '\0') {
17751ee2c1cSSimon J. Gerraty 		*nf++ = '-';
17851ee2c1cSSimon J. Gerraty 		*nf++ = *flags++;
17951ee2c1cSSimon J. Gerraty 		*nf++ = ' ';
18051ee2c1cSSimon J. Gerraty 	}
18151ee2c1cSSimon J. Gerraty 	*nf = '\0';
18251ee2c1cSSimon J. Gerraty 	return st;
18351ee2c1cSSimon J. Gerraty }
18451ee2c1cSSimon J. Gerraty 
185e2eeea75SSimon J. Gerraty /*
186e2eeea75SSimon J. Gerraty  * usage --
187e2eeea75SSimon J. Gerraty  *	exit with usage message
188e2eeea75SSimon J. Gerraty  */
189e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void
190e2eeea75SSimon J. Gerraty usage(void)
191e2eeea75SSimon J. Gerraty {
192e2eeea75SSimon J. Gerraty 	size_t prognameLen = strcspn(progname, "[");
193e2eeea75SSimon J. Gerraty 
194e2eeea75SSimon J. Gerraty 	(void)fprintf(stderr,
195e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n"
196e2eeea75SSimon J. Gerraty "            [-C directory] [-D variable] [-d flags] [-f makefile]\n"
197e2eeea75SSimon J. Gerraty "            [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
198e2eeea75SSimon J. Gerraty "            [-V variable] [-v variable] [variable=value] [target ...]\n",
199e2eeea75SSimon J. Gerraty 	    (int)prognameLen, progname);
200e2eeea75SSimon J. Gerraty 	exit(2);
201e2eeea75SSimon J. Gerraty }
202e2eeea75SSimon J. Gerraty 
2033955d011SMarcel Moolenaar static void
204*dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg)
2053955d011SMarcel Moolenaar {
2063955d011SMarcel Moolenaar 	const char *mode;
207956e45f6SSimon J. Gerraty 	size_t len;
2083955d011SMarcel Moolenaar 	char *fname;
2093955d011SMarcel Moolenaar 
210956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout && opts.debug_file != stderr)
211956e45f6SSimon J. Gerraty 		fclose(opts.debug_file);
212956e45f6SSimon J. Gerraty 
213*dba7b0efSSimon J. Gerraty 	if (*arg == '+') {
214*dba7b0efSSimon J. Gerraty 		arg++;
2153955d011SMarcel Moolenaar 		mode = "a";
2163955d011SMarcel Moolenaar 	} else
2173955d011SMarcel Moolenaar 		mode = "w";
218956e45f6SSimon J. Gerraty 
219*dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stdout") == 0) {
220956e45f6SSimon J. Gerraty 		opts.debug_file = stdout;
221956e45f6SSimon J. Gerraty 		return;
2223955d011SMarcel Moolenaar 	}
223*dba7b0efSSimon J. Gerraty 	if (strcmp(arg, "stderr") == 0) {
224956e45f6SSimon J. Gerraty 		opts.debug_file = stderr;
225956e45f6SSimon J. Gerraty 		return;
2263955d011SMarcel Moolenaar 	}
227956e45f6SSimon J. Gerraty 
228*dba7b0efSSimon J. Gerraty 	len = strlen(arg);
229e1cee40dSSimon J. Gerraty 	fname = bmake_malloc(len + 20);
230*dba7b0efSSimon J. Gerraty 	memcpy(fname, arg, len + 1);
231956e45f6SSimon J. Gerraty 
2323955d011SMarcel Moolenaar 	/* Let the filename be modified by the pid */
2333955d011SMarcel Moolenaar 	if (strcmp(fname + len - 3, ".%d") == 0)
2343955d011SMarcel Moolenaar 		snprintf(fname + len - 2, 20, "%d", getpid());
235956e45f6SSimon J. Gerraty 
236956e45f6SSimon J. Gerraty 	opts.debug_file = fopen(fname, mode);
237e2eeea75SSimon J. Gerraty 	if (opts.debug_file == NULL) {
2383955d011SMarcel Moolenaar 		fprintf(stderr, "Cannot open debug file %s\n",
2393955d011SMarcel Moolenaar 		    fname);
2403955d011SMarcel Moolenaar 		usage();
2413955d011SMarcel Moolenaar 	}
2423955d011SMarcel Moolenaar 	free(fname);
243956e45f6SSimon J. Gerraty }
244956e45f6SSimon J. Gerraty 
245956e45f6SSimon J. Gerraty static void
246*dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue)
247956e45f6SSimon J. Gerraty {
248956e45f6SSimon J. Gerraty 	const char *modules;
249e2eeea75SSimon J. Gerraty 	DebugFlags debug = opts.debug;
250956e45f6SSimon J. Gerraty 
251*dba7b0efSSimon J. Gerraty 	for (modules = argvalue; *modules != '\0'; modules++) {
252956e45f6SSimon J. Gerraty 		switch (*modules) {
253956e45f6SSimon J. Gerraty 		case '0':	/* undocumented, only intended for tests */
254e2eeea75SSimon J. Gerraty 			debug = DEBUG_NONE;
255956e45f6SSimon J. Gerraty 			break;
256956e45f6SSimon J. Gerraty 		case 'A':
257e2eeea75SSimon J. Gerraty 			debug = DEBUG_ALL;
258956e45f6SSimon J. Gerraty 			break;
259956e45f6SSimon J. Gerraty 		case 'a':
260e2eeea75SSimon J. Gerraty 			debug |= DEBUG_ARCH;
261956e45f6SSimon J. Gerraty 			break;
262956e45f6SSimon J. Gerraty 		case 'C':
263e2eeea75SSimon J. Gerraty 			debug |= DEBUG_CWD;
264956e45f6SSimon J. Gerraty 			break;
265956e45f6SSimon J. Gerraty 		case 'c':
266e2eeea75SSimon J. Gerraty 			debug |= DEBUG_COND;
267956e45f6SSimon J. Gerraty 			break;
268956e45f6SSimon J. Gerraty 		case 'd':
269e2eeea75SSimon J. Gerraty 			debug |= DEBUG_DIR;
270956e45f6SSimon J. Gerraty 			break;
271956e45f6SSimon J. Gerraty 		case 'e':
272e2eeea75SSimon J. Gerraty 			debug |= DEBUG_ERROR;
273956e45f6SSimon J. Gerraty 			break;
274956e45f6SSimon J. Gerraty 		case 'f':
275e2eeea75SSimon J. Gerraty 			debug |= DEBUG_FOR;
276956e45f6SSimon J. Gerraty 			break;
277956e45f6SSimon J. Gerraty 		case 'g':
278956e45f6SSimon J. Gerraty 			if (modules[1] == '1') {
279e2eeea75SSimon J. Gerraty 				debug |= DEBUG_GRAPH1;
280e2eeea75SSimon J. Gerraty 				modules++;
281e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '2') {
282e2eeea75SSimon J. Gerraty 				debug |= DEBUG_GRAPH2;
283e2eeea75SSimon J. Gerraty 				modules++;
284e2eeea75SSimon J. Gerraty 			} else if (modules[1] == '3') {
285e2eeea75SSimon J. Gerraty 				debug |= DEBUG_GRAPH3;
286e2eeea75SSimon J. Gerraty 				modules++;
287956e45f6SSimon J. Gerraty 			}
288956e45f6SSimon J. Gerraty 			break;
289956e45f6SSimon J. Gerraty 		case 'h':
290e2eeea75SSimon J. Gerraty 			debug |= DEBUG_HASH;
291956e45f6SSimon J. Gerraty 			break;
292956e45f6SSimon J. Gerraty 		case 'j':
293e2eeea75SSimon J. Gerraty 			debug |= DEBUG_JOB;
294956e45f6SSimon J. Gerraty 			break;
295956e45f6SSimon J. Gerraty 		case 'L':
29606b9b3e0SSimon J. Gerraty 			opts.strict = TRUE;
297956e45f6SSimon J. Gerraty 			break;
298956e45f6SSimon J. Gerraty 		case 'l':
299e2eeea75SSimon J. Gerraty 			debug |= DEBUG_LOUD;
300956e45f6SSimon J. Gerraty 			break;
301956e45f6SSimon J. Gerraty 		case 'M':
302e2eeea75SSimon J. Gerraty 			debug |= DEBUG_META;
303956e45f6SSimon J. Gerraty 			break;
304956e45f6SSimon J. Gerraty 		case 'm':
305e2eeea75SSimon J. Gerraty 			debug |= DEBUG_MAKE;
306956e45f6SSimon J. Gerraty 			break;
307956e45f6SSimon J. Gerraty 		case 'n':
308e2eeea75SSimon J. Gerraty 			debug |= DEBUG_SCRIPT;
309956e45f6SSimon J. Gerraty 			break;
310956e45f6SSimon J. Gerraty 		case 'p':
311e2eeea75SSimon J. Gerraty 			debug |= DEBUG_PARSE;
312956e45f6SSimon J. Gerraty 			break;
313956e45f6SSimon J. Gerraty 		case 's':
314e2eeea75SSimon J. Gerraty 			debug |= DEBUG_SUFF;
315956e45f6SSimon J. Gerraty 			break;
316956e45f6SSimon J. Gerraty 		case 't':
317e2eeea75SSimon J. Gerraty 			debug |= DEBUG_TARG;
318956e45f6SSimon J. Gerraty 			break;
319956e45f6SSimon J. Gerraty 		case 'V':
320956e45f6SSimon J. Gerraty 			opts.debugVflag = TRUE;
321956e45f6SSimon J. Gerraty 			break;
322956e45f6SSimon J. Gerraty 		case 'v':
323e2eeea75SSimon J. Gerraty 			debug |= DEBUG_VAR;
324956e45f6SSimon J. Gerraty 			break;
325956e45f6SSimon J. Gerraty 		case 'x':
326e2eeea75SSimon J. Gerraty 			debug |= DEBUG_SHELL;
327956e45f6SSimon J. Gerraty 			break;
328956e45f6SSimon J. Gerraty 		case 'F':
329*dba7b0efSSimon J. Gerraty 			MainParseArgDebugFile(modules + 1);
3303955d011SMarcel Moolenaar 			goto debug_setbuf;
3313955d011SMarcel Moolenaar 		default:
3323955d011SMarcel Moolenaar 			(void)fprintf(stderr,
3333955d011SMarcel Moolenaar 			    "%s: illegal argument to d option -- %c\n",
3343955d011SMarcel Moolenaar 			    progname, *modules);
3353955d011SMarcel Moolenaar 			usage();
3363955d011SMarcel Moolenaar 		}
3373955d011SMarcel Moolenaar 	}
338e2eeea75SSimon J. Gerraty 
3393955d011SMarcel Moolenaar debug_setbuf:
340e2eeea75SSimon J. Gerraty 	opts.debug = debug;
341e2eeea75SSimon J. Gerraty 
3423955d011SMarcel Moolenaar 	/*
3433955d011SMarcel Moolenaar 	 * Make the debug_file unbuffered, and make
3443955d011SMarcel Moolenaar 	 * stdout line buffered (unless debugfile == stdout).
3453955d011SMarcel Moolenaar 	 */
346956e45f6SSimon J. Gerraty 	setvbuf(opts.debug_file, NULL, _IONBF, 0);
347956e45f6SSimon J. Gerraty 	if (opts.debug_file != stdout) {
3483955d011SMarcel Moolenaar 		setvbuf(stdout, NULL, _IOLBF, 0);
3493955d011SMarcel Moolenaar 	}
3503955d011SMarcel Moolenaar }
3513955d011SMarcel Moolenaar 
352*dba7b0efSSimon J. Gerraty /* Is path relative, or does it contain any relative component "." or ".."? */
3532c3632d1SSimon J. Gerraty static Boolean
354*dba7b0efSSimon J. Gerraty IsRelativePath(const char *path)
355e1cee40dSSimon J. Gerraty {
356e1cee40dSSimon J. Gerraty 	const char *cp;
357e1cee40dSSimon J. Gerraty 
358e1cee40dSSimon J. Gerraty 	if (path[0] != '/')
359e1cee40dSSimon J. Gerraty 		return TRUE;
360e1cee40dSSimon J. Gerraty 	cp = path;
3612c3632d1SSimon J. Gerraty 	while ((cp = strstr(cp, "/.")) != NULL) {
362e1cee40dSSimon J. Gerraty 		cp += 2;
363e2eeea75SSimon J. Gerraty 		if (*cp == '.')
364e2eeea75SSimon J. Gerraty 			cp++;
365e1cee40dSSimon J. Gerraty 		if (cp[0] == '/' || cp[0] == '\0')
366e1cee40dSSimon J. Gerraty 			return TRUE;
3672c3632d1SSimon J. Gerraty 	}
368e1cee40dSSimon J. Gerraty 	return FALSE;
369e1cee40dSSimon J. Gerraty }
370e1cee40dSSimon J. Gerraty 
371956e45f6SSimon J. Gerraty static void
372956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue)
373956e45f6SSimon J. Gerraty {
374956e45f6SSimon J. Gerraty 	struct stat sa, sb;
375956e45f6SSimon J. Gerraty 
376956e45f6SSimon J. Gerraty 	if (chdir(argvalue) == -1) {
377956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: chdir %s: %s\n",
378956e45f6SSimon J. Gerraty 		    progname, argvalue, strerror(errno));
37906b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
380956e45f6SSimon J. Gerraty 	}
381956e45f6SSimon J. Gerraty 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
382956e45f6SSimon J. Gerraty 		(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
383956e45f6SSimon J. Gerraty 		exit(2);
384956e45f6SSimon J. Gerraty 	}
385*dba7b0efSSimon J. Gerraty 	if (!IsRelativePath(argvalue) &&
386956e45f6SSimon J. Gerraty 	    stat(argvalue, &sa) != -1 &&
387956e45f6SSimon J. Gerraty 	    stat(curdir, &sb) != -1 &&
388956e45f6SSimon J. Gerraty 	    sa.st_ino == sb.st_ino &&
389956e45f6SSimon J. Gerraty 	    sa.st_dev == sb.st_dev)
390956e45f6SSimon J. Gerraty 		strncpy(curdir, argvalue, MAXPATHLEN);
391956e45f6SSimon J. Gerraty 	ignorePWD = TRUE;
392956e45f6SSimon J. Gerraty }
393956e45f6SSimon J. Gerraty 
394956e45f6SSimon J. Gerraty static void
395956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue)
396956e45f6SSimon J. Gerraty {
397e2eeea75SSimon J. Gerraty 	char end;
398e2eeea75SSimon J. Gerraty 	if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
399956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
400956e45f6SSimon J. Gerraty 		    "%s: internal error -- J option malformed (%s)\n",
401956e45f6SSimon J. Gerraty 		    progname, argvalue);
402956e45f6SSimon J. Gerraty 		usage();
403956e45f6SSimon J. Gerraty 	}
404956e45f6SSimon J. Gerraty 	if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
405956e45f6SSimon J. Gerraty 	    (fcntl(jp_1, F_GETFD, 0) < 0)) {
406956e45f6SSimon J. Gerraty #if 0
407956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
408956e45f6SSimon J. Gerraty 		    "%s: ###### warning -- J descriptors were closed!\n",
409956e45f6SSimon J. Gerraty 		    progname);
410956e45f6SSimon J. Gerraty 		exit(2);
411956e45f6SSimon J. Gerraty #endif
412956e45f6SSimon J. Gerraty 		jp_0 = -1;
413956e45f6SSimon J. Gerraty 		jp_1 = -1;
414956e45f6SSimon J. Gerraty 		opts.compatMake = TRUE;
415956e45f6SSimon J. Gerraty 	} else {
416*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-J");
417*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
418956e45f6SSimon J. Gerraty 	}
419956e45f6SSimon J. Gerraty }
420956e45f6SSimon J. Gerraty 
421956e45f6SSimon J. Gerraty static void
422956e45f6SSimon J. Gerraty MainParseArgJobs(const char *argvalue)
423956e45f6SSimon J. Gerraty {
424956e45f6SSimon J. Gerraty 	char *p;
425956e45f6SSimon J. Gerraty 
426956e45f6SSimon J. Gerraty 	forceJobs = TRUE;
427956e45f6SSimon J. Gerraty 	opts.maxJobs = (int)strtol(argvalue, &p, 0);
428956e45f6SSimon J. Gerraty 	if (*p != '\0' || opts.maxJobs < 1) {
429956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
430956e45f6SSimon J. Gerraty 		    "%s: illegal argument to -j -- must be positive integer!\n",
431956e45f6SSimon J. Gerraty 		    progname);
43206b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
433956e45f6SSimon J. Gerraty 	}
434*dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-j");
435*dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, argvalue);
436*dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE.JOBS", argvalue);
437956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
438956e45f6SSimon J. Gerraty }
439956e45f6SSimon J. Gerraty 
440956e45f6SSimon J. Gerraty static void
441956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue)
442956e45f6SSimon J. Gerraty {
443956e45f6SSimon J. Gerraty 	/* look for magic parent directory search string */
444956e45f6SSimon J. Gerraty 	if (strncmp(".../", argvalue, 4) == 0) {
445956e45f6SSimon J. Gerraty 		char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
446956e45f6SSimon J. Gerraty 		if (found_path == NULL)
447956e45f6SSimon J. Gerraty 			return;
448*dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, found_path);
449956e45f6SSimon J. Gerraty 		free(found_path);
450956e45f6SSimon J. Gerraty 	} else {
451*dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(sysIncPath, argvalue);
452956e45f6SSimon J. Gerraty 	}
453*dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, "-m");
454*dba7b0efSSimon J. Gerraty 	Global_Append(MAKEFLAGS, argvalue);
455956e45f6SSimon J. Gerraty }
456956e45f6SSimon J. Gerraty 
457956e45f6SSimon J. Gerraty static Boolean
458956e45f6SSimon J. Gerraty MainParseArg(char c, const char *argvalue)
459956e45f6SSimon J. Gerraty {
460956e45f6SSimon J. Gerraty 	switch (c) {
461956e45f6SSimon J. Gerraty 	case '\0':
462956e45f6SSimon J. Gerraty 		break;
463956e45f6SSimon J. Gerraty 	case 'B':
464956e45f6SSimon J. Gerraty 		opts.compatMake = TRUE;
465*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-B");
466*dba7b0efSSimon J. Gerraty 		Global_Set(MAKE_MODE, "compat");
467956e45f6SSimon J. Gerraty 		break;
468956e45f6SSimon J. Gerraty 	case 'C':
469956e45f6SSimon J. Gerraty 		MainParseArgChdir(argvalue);
470956e45f6SSimon J. Gerraty 		break;
471956e45f6SSimon J. Gerraty 	case 'D':
472956e45f6SSimon J. Gerraty 		if (argvalue[0] == '\0') return FALSE;
473*dba7b0efSSimon J. Gerraty 		Global_SetExpand(argvalue, "1");
474*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-D");
475*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
476956e45f6SSimon J. Gerraty 		break;
477956e45f6SSimon J. Gerraty 	case 'I':
478956e45f6SSimon J. Gerraty 		Parse_AddIncludeDir(argvalue);
479*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-I");
480*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
481956e45f6SSimon J. Gerraty 		break;
482956e45f6SSimon J. Gerraty 	case 'J':
483956e45f6SSimon J. Gerraty 		MainParseArgJobsInternal(argvalue);
484956e45f6SSimon J. Gerraty 		break;
485956e45f6SSimon J. Gerraty 	case 'N':
486956e45f6SSimon J. Gerraty 		opts.noExecute = TRUE;
487956e45f6SSimon J. Gerraty 		opts.noRecursiveExecute = TRUE;
488*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-N");
489956e45f6SSimon J. Gerraty 		break;
490956e45f6SSimon J. Gerraty 	case 'S':
491956e45f6SSimon J. Gerraty 		opts.keepgoing = FALSE;
492*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-S");
493956e45f6SSimon J. Gerraty 		break;
494956e45f6SSimon J. Gerraty 	case 'T':
495956e45f6SSimon J. Gerraty 		tracefile = bmake_strdup(argvalue);
496*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-T");
497*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
498956e45f6SSimon J. Gerraty 		break;
499956e45f6SSimon J. Gerraty 	case 'V':
500956e45f6SSimon J. Gerraty 	case 'v':
501e2eeea75SSimon J. Gerraty 		opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
50206b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.variables, bmake_strdup(argvalue));
503956e45f6SSimon J. Gerraty 		/* XXX: Why always -V? */
504*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-V");
505*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, argvalue);
506956e45f6SSimon J. Gerraty 		break;
507956e45f6SSimon J. Gerraty 	case 'W':
508956e45f6SSimon J. Gerraty 		opts.parseWarnFatal = TRUE;
509e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
510956e45f6SSimon J. Gerraty 		break;
511956e45f6SSimon J. Gerraty 	case 'X':
512956e45f6SSimon J. Gerraty 		opts.varNoExportEnv = TRUE;
513*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-X");
514956e45f6SSimon J. Gerraty 		break;
515956e45f6SSimon J. Gerraty 	case 'd':
516956e45f6SSimon J. Gerraty 		/* If '-d-opts' don't pass to children */
517956e45f6SSimon J. Gerraty 		if (argvalue[0] == '-')
518956e45f6SSimon J. Gerraty 			argvalue++;
519956e45f6SSimon J. Gerraty 		else {
520*dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, "-d");
521*dba7b0efSSimon J. Gerraty 			Global_Append(MAKEFLAGS, argvalue);
522956e45f6SSimon J. Gerraty 		}
523*dba7b0efSSimon J. Gerraty 		MainParseArgDebug(argvalue);
524956e45f6SSimon J. Gerraty 		break;
525956e45f6SSimon J. Gerraty 	case 'e':
526956e45f6SSimon J. Gerraty 		opts.checkEnvFirst = TRUE;
527*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-e");
528956e45f6SSimon J. Gerraty 		break;
529956e45f6SSimon J. Gerraty 	case 'f':
53006b9b3e0SSimon J. Gerraty 		Lst_Append(&opts.makefiles, bmake_strdup(argvalue));
531956e45f6SSimon J. Gerraty 		break;
532956e45f6SSimon J. Gerraty 	case 'i':
533956e45f6SSimon J. Gerraty 		opts.ignoreErrors = TRUE;
534*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-i");
535956e45f6SSimon J. Gerraty 		break;
536956e45f6SSimon J. Gerraty 	case 'j':
537956e45f6SSimon J. Gerraty 		MainParseArgJobs(argvalue);
538956e45f6SSimon J. Gerraty 		break;
539956e45f6SSimon J. Gerraty 	case 'k':
540956e45f6SSimon J. Gerraty 		opts.keepgoing = TRUE;
541*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-k");
542956e45f6SSimon J. Gerraty 		break;
543956e45f6SSimon J. Gerraty 	case 'm':
544956e45f6SSimon J. Gerraty 		MainParseArgSysInc(argvalue);
545e2eeea75SSimon J. Gerraty 		/* XXX: why no Var_Append? */
546956e45f6SSimon J. Gerraty 		break;
547956e45f6SSimon J. Gerraty 	case 'n':
548956e45f6SSimon J. Gerraty 		opts.noExecute = TRUE;
549*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-n");
550956e45f6SSimon J. Gerraty 		break;
551956e45f6SSimon J. Gerraty 	case 'q':
552956e45f6SSimon J. Gerraty 		opts.queryFlag = TRUE;
553956e45f6SSimon J. Gerraty 		/* Kind of nonsensical, wot? */
554*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-q");
555956e45f6SSimon J. Gerraty 		break;
556956e45f6SSimon J. Gerraty 	case 'r':
557956e45f6SSimon J. Gerraty 		opts.noBuiltins = TRUE;
558*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-r");
559956e45f6SSimon J. Gerraty 		break;
560956e45f6SSimon J. Gerraty 	case 's':
561956e45f6SSimon J. Gerraty 		opts.beSilent = TRUE;
562*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-s");
563956e45f6SSimon J. Gerraty 		break;
564956e45f6SSimon J. Gerraty 	case 't':
565956e45f6SSimon J. Gerraty 		opts.touchFlag = TRUE;
566*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-t");
567956e45f6SSimon J. Gerraty 		break;
568956e45f6SSimon J. Gerraty 	case 'w':
569956e45f6SSimon J. Gerraty 		opts.enterFlag = TRUE;
570*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-w");
571956e45f6SSimon J. Gerraty 		break;
572956e45f6SSimon J. Gerraty 	default:
573956e45f6SSimon J. Gerraty 	case '?':
574956e45f6SSimon J. Gerraty 		usage();
575956e45f6SSimon J. Gerraty 	}
576956e45f6SSimon J. Gerraty 	return TRUE;
577956e45f6SSimon J. Gerraty }
578956e45f6SSimon J. Gerraty 
57906b9b3e0SSimon J. Gerraty /*
58006b9b3e0SSimon J. Gerraty  * Parse the given arguments.  Called from main() and from
5813955d011SMarcel Moolenaar  * Main_ParseArgLine() when the .MAKEFLAGS target is used.
5823955d011SMarcel Moolenaar  *
583956e45f6SSimon J. Gerraty  * The arguments must be treated as read-only and will be freed after the
584956e45f6SSimon J. Gerraty  * call.
5853955d011SMarcel Moolenaar  *
58606b9b3e0SSimon J. Gerraty  * XXX: Deal with command line overriding .MAKEFLAGS in makefile
58706b9b3e0SSimon J. Gerraty  */
5883955d011SMarcel Moolenaar static void
5893955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv)
5903955d011SMarcel Moolenaar {
591956e45f6SSimon J. Gerraty 	char c;
5923955d011SMarcel Moolenaar 	int arginc;
5933955d011SMarcel Moolenaar 	char *argvalue;
5943955d011SMarcel Moolenaar 	char *optscan;
5953955d011SMarcel Moolenaar 	Boolean inOption, dashDash = FALSE;
5963955d011SMarcel Moolenaar 
597956e45f6SSimon J. Gerraty 	const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
5983955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */
5993955d011SMarcel Moolenaar 
6003955d011SMarcel Moolenaar rearg:
6013955d011SMarcel Moolenaar 	inOption = FALSE;
6023955d011SMarcel Moolenaar 	optscan = NULL;
6033955d011SMarcel Moolenaar 	while (argc > 1) {
604956e45f6SSimon J. Gerraty 		const char *optspec;
6053955d011SMarcel Moolenaar 		if (!inOption)
6063955d011SMarcel Moolenaar 			optscan = argv[1];
6073955d011SMarcel Moolenaar 		c = *optscan++;
6083955d011SMarcel Moolenaar 		arginc = 0;
6093955d011SMarcel Moolenaar 		if (inOption) {
6103955d011SMarcel Moolenaar 			if (c == '\0') {
611e2eeea75SSimon J. Gerraty 				argv++;
612e2eeea75SSimon J. Gerraty 				argc--;
6133955d011SMarcel Moolenaar 				inOption = FALSE;
6143955d011SMarcel Moolenaar 				continue;
6153955d011SMarcel Moolenaar 			}
6163955d011SMarcel Moolenaar 		} else {
6173955d011SMarcel Moolenaar 			if (c != '-' || dashDash)
6183955d011SMarcel Moolenaar 				break;
6193955d011SMarcel Moolenaar 			inOption = TRUE;
6203955d011SMarcel Moolenaar 			c = *optscan++;
6213955d011SMarcel Moolenaar 		}
6223955d011SMarcel Moolenaar 		/* '-' found at some earlier point */
623956e45f6SSimon J. Gerraty 		optspec = strchr(optspecs, c);
624956e45f6SSimon J. Gerraty 		if (c != '\0' && optspec != NULL && optspec[1] == ':') {
6253955d011SMarcel Moolenaar 			/* -<something> found, and <something> should have an arg */
6263955d011SMarcel Moolenaar 			inOption = FALSE;
6273955d011SMarcel Moolenaar 			arginc = 1;
6283955d011SMarcel Moolenaar 			argvalue = optscan;
6293955d011SMarcel Moolenaar 			if (*argvalue == '\0') {
6303955d011SMarcel Moolenaar 				if (argc < 3)
6313955d011SMarcel Moolenaar 					goto noarg;
6323955d011SMarcel Moolenaar 				argvalue = argv[2];
6333955d011SMarcel Moolenaar 				arginc = 2;
6343955d011SMarcel Moolenaar 			}
6353955d011SMarcel Moolenaar 		} else {
6363955d011SMarcel Moolenaar 			argvalue = NULL;
6373955d011SMarcel Moolenaar 		}
6383955d011SMarcel Moolenaar 		switch (c) {
6393955d011SMarcel Moolenaar 		case '\0':
6403955d011SMarcel Moolenaar 			arginc = 1;
6413955d011SMarcel Moolenaar 			inOption = FALSE;
6423955d011SMarcel Moolenaar 			break;
6433955d011SMarcel Moolenaar 		case '-':
6443955d011SMarcel Moolenaar 			dashDash = TRUE;
6453955d011SMarcel Moolenaar 			break;
6463955d011SMarcel Moolenaar 		default:
647956e45f6SSimon J. Gerraty 			if (!MainParseArg(c, argvalue))
648956e45f6SSimon J. Gerraty 				goto noarg;
6493955d011SMarcel Moolenaar 		}
6503955d011SMarcel Moolenaar 		argv += arginc;
6513955d011SMarcel Moolenaar 		argc -= arginc;
6523955d011SMarcel Moolenaar 	}
6533955d011SMarcel Moolenaar 
6543955d011SMarcel Moolenaar 	/*
6553955d011SMarcel Moolenaar 	 * See if the rest of the arguments are variable assignments and
6563955d011SMarcel Moolenaar 	 * perform them if so. Else take them to be targets and stuff them
6573955d011SMarcel Moolenaar 	 * on the end of the "create" list.
6583955d011SMarcel Moolenaar 	 */
659*dba7b0efSSimon J. Gerraty 	for (; argc > 1; argv++, argc--) {
660956e45f6SSimon J. Gerraty 		VarAssign var;
661956e45f6SSimon J. Gerraty 		if (Parse_IsVar(argv[1], &var)) {
662*dba7b0efSSimon J. Gerraty 			Parse_DoVar(&var, SCOPE_CMDLINE);
6633955d011SMarcel Moolenaar 		} else {
664e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '\0')
6653955d011SMarcel Moolenaar 				Punt("illegal (null) argument.");
666e2eeea75SSimon J. Gerraty 			if (argv[1][0] == '-' && !dashDash)
6673955d011SMarcel Moolenaar 				goto rearg;
66806b9b3e0SSimon J. Gerraty 			Lst_Append(&opts.create, bmake_strdup(argv[1]));
669956e45f6SSimon J. Gerraty 		}
6703955d011SMarcel Moolenaar 	}
6713955d011SMarcel Moolenaar 
6723955d011SMarcel Moolenaar 	return;
6733955d011SMarcel Moolenaar noarg:
6743955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
6753955d011SMarcel Moolenaar 	    progname, c);
6763955d011SMarcel Moolenaar 	usage();
6773955d011SMarcel Moolenaar }
6783955d011SMarcel Moolenaar 
67906b9b3e0SSimon J. Gerraty /*
68006b9b3e0SSimon J. Gerraty  * Break a line of arguments into words and parse them.
6813955d011SMarcel Moolenaar  *
682956e45f6SSimon J. Gerraty  * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
68306b9b3e0SSimon J. Gerraty  * by main() when reading the MAKEFLAGS environment variable.
68406b9b3e0SSimon J. Gerraty  */
6853955d011SMarcel Moolenaar void
6863955d011SMarcel Moolenaar Main_ParseArgLine(const char *line)
6873955d011SMarcel Moolenaar {
6882c3632d1SSimon J. Gerraty 	Words words;
6892c3632d1SSimon J. Gerraty 	char *buf;
6903955d011SMarcel Moolenaar 
6913955d011SMarcel Moolenaar 	if (line == NULL)
6923955d011SMarcel Moolenaar 		return;
69306b9b3e0SSimon J. Gerraty 	/* XXX: don't use line as an iterator variable */
694*dba7b0efSSimon J. Gerraty 	for (; *line == ' '; line++)
6953955d011SMarcel Moolenaar 		continue;
696e2eeea75SSimon J. Gerraty 	if (line[0] == '\0')
6973955d011SMarcel Moolenaar 		return;
6983955d011SMarcel Moolenaar 
6993955d011SMarcel Moolenaar #ifndef POSIX
7003955d011SMarcel Moolenaar 	{
7013955d011SMarcel Moolenaar 		/*
7023955d011SMarcel Moolenaar 		 * $MAKE may simply be naming the make(1) binary
7033955d011SMarcel Moolenaar 		 */
7043955d011SMarcel Moolenaar 		char *cp;
7053955d011SMarcel Moolenaar 
7063955d011SMarcel Moolenaar 		if (!(cp = strrchr(line, '/')))
7073955d011SMarcel Moolenaar 			cp = line;
7083955d011SMarcel Moolenaar 		if ((cp = strstr(cp, "make")) &&
7093955d011SMarcel Moolenaar 		    strcmp(cp, "make") == 0)
7103955d011SMarcel Moolenaar 			return;
7113955d011SMarcel Moolenaar 	}
7123955d011SMarcel Moolenaar #endif
713e2eeea75SSimon J. Gerraty 	{
714*dba7b0efSSimon J. Gerraty 		FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE");
71506b9b3e0SSimon J. Gerraty 		buf = str_concat3(argv0.str, " ", line);
71606b9b3e0SSimon J. Gerraty 		FStr_Done(&argv0);
717e2eeea75SSimon J. Gerraty 	}
7183955d011SMarcel Moolenaar 
7192c3632d1SSimon J. Gerraty 	words = Str_Words(buf, TRUE);
7202c3632d1SSimon J. Gerraty 	if (words.words == NULL) {
7213955d011SMarcel Moolenaar 		Error("Unterminated quoted string [%s]", buf);
7223955d011SMarcel Moolenaar 		free(buf);
7233955d011SMarcel Moolenaar 		return;
7243955d011SMarcel Moolenaar 	}
7253955d011SMarcel Moolenaar 	free(buf);
7262c3632d1SSimon J. Gerraty 	MainParseArgs((int)words.len, words.words);
7273955d011SMarcel Moolenaar 
7282c3632d1SSimon J. Gerraty 	Words_Free(words);
7293955d011SMarcel Moolenaar }
7303955d011SMarcel Moolenaar 
7313955d011SMarcel Moolenaar Boolean
732e2eeea75SSimon J. Gerraty Main_SetObjdir(Boolean writable, const char *fmt, ...)
7333955d011SMarcel Moolenaar {
7343955d011SMarcel Moolenaar 	struct stat sb;
735b46b9039SSimon J. Gerraty 	char *path;
736b46b9039SSimon J. Gerraty 	char buf[MAXPATHLEN + 1];
737e23f3f6eSSimon J. Gerraty 	char buf2[MAXPATHLEN + 1];
7383955d011SMarcel Moolenaar 	Boolean rc = FALSE;
73945447996SSimon J. Gerraty 	va_list ap;
74045447996SSimon J. Gerraty 
74145447996SSimon J. Gerraty 	va_start(ap, fmt);
742b46b9039SSimon J. Gerraty 	vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
74345447996SSimon J. Gerraty 	va_end(ap);
7443955d011SMarcel Moolenaar 
7453955d011SMarcel Moolenaar 	if (path[0] != '/') {
746e1cee40dSSimon J. Gerraty 		snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path);
747e1cee40dSSimon J. Gerraty 		path = buf2;
7483955d011SMarcel Moolenaar 	}
7493955d011SMarcel Moolenaar 
7503955d011SMarcel Moolenaar 	/* look for the directory and try to chdir there */
7513955d011SMarcel Moolenaar 	if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
752e2eeea75SSimon J. Gerraty 		if ((writable && access(path, W_OK) != 0) ||
753e2eeea75SSimon J. Gerraty 		    (chdir(path) != 0)) {
754e2eeea75SSimon J. Gerraty 			(void)fprintf(stderr, "%s warning: %s: %s.\n",
755e2eeea75SSimon J. Gerraty 			    progname, path, strerror(errno));
7563955d011SMarcel Moolenaar 		} else {
7572c3632d1SSimon J. Gerraty 			snprintf(objdir, sizeof objdir, "%s", path);
758*dba7b0efSSimon J. Gerraty 			Global_Set(".OBJDIR", objdir);
7593955d011SMarcel Moolenaar 			setenv("PWD", objdir, 1);
7603955d011SMarcel Moolenaar 			Dir_InitDot();
761e2eeea75SSimon J. Gerraty 			purge_relative_cached_realpaths();
7623955d011SMarcel Moolenaar 			rc = TRUE;
763956e45f6SSimon J. Gerraty 			if (opts.enterFlag && strcmp(objdir, curdir) != 0)
7644c620fe5SSimon J. Gerraty 				enterFlagObj = TRUE;
7653955d011SMarcel Moolenaar 		}
7663955d011SMarcel Moolenaar 	}
7673955d011SMarcel Moolenaar 
7683955d011SMarcel Moolenaar 	return rc;
7693955d011SMarcel Moolenaar }
7703955d011SMarcel Moolenaar 
77145447996SSimon J. Gerraty static Boolean
772e2eeea75SSimon J. Gerraty SetVarObjdir(Boolean writable, const char *var, const char *suffix)
77345447996SSimon J. Gerraty {
774*dba7b0efSSimon J. Gerraty 	FStr path = Var_Value(SCOPE_CMDLINE, var);
77506b9b3e0SSimon J. Gerraty 	FStr xpath;
776b46b9039SSimon J. Gerraty 
77706b9b3e0SSimon J. Gerraty 	if (path.str == NULL || path.str[0] == '\0') {
77806b9b3e0SSimon J. Gerraty 		FStr_Done(&path);
77945447996SSimon J. Gerraty 		return FALSE;
7802c3632d1SSimon J. Gerraty 	}
78145447996SSimon J. Gerraty 
782b46b9039SSimon J. Gerraty 	/* expand variable substitutions */
78306b9b3e0SSimon J. Gerraty 	xpath = FStr_InitRefer(path.str);
78406b9b3e0SSimon J. Gerraty 	if (strchr(path.str, '$') != 0) {
78506b9b3e0SSimon J. Gerraty 		char *expanded;
786*dba7b0efSSimon J. Gerraty 		(void)Var_Subst(path.str, SCOPE_GLOBAL, VARE_WANTRES, &expanded);
787956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
78806b9b3e0SSimon J. Gerraty 		xpath = FStr_InitOwn(expanded);
789956e45f6SSimon J. Gerraty 	}
790b46b9039SSimon J. Gerraty 
79106b9b3e0SSimon J. Gerraty 	(void)Main_SetObjdir(writable, "%s%s", xpath.str, suffix);
792b46b9039SSimon J. Gerraty 
79306b9b3e0SSimon J. Gerraty 	FStr_Done(&xpath);
79406b9b3e0SSimon J. Gerraty 	FStr_Done(&path);
79545447996SSimon J. Gerraty 	return TRUE;
79645447996SSimon J. Gerraty }
79745447996SSimon J. Gerraty 
79806b9b3e0SSimon J. Gerraty /*
79906b9b3e0SSimon J. Gerraty  * Splits str into words, adding them to the list.
80006b9b3e0SSimon J. Gerraty  * The string must be kept alive as long as the list.
80106b9b3e0SSimon J. Gerraty  */
8023955d011SMarcel Moolenaar int
803e2eeea75SSimon J. Gerraty str2Lst_Append(StringList *lp, char *str)
8043955d011SMarcel Moolenaar {
8053955d011SMarcel Moolenaar 	char *cp;
8063955d011SMarcel Moolenaar 	int n;
8073955d011SMarcel Moolenaar 
808e2eeea75SSimon J. Gerraty 	const char *sep = " \t";
8093955d011SMarcel Moolenaar 
81006b9b3e0SSimon J. Gerraty 	for (n = 0, cp = strtok(str, sep); cp != NULL; cp = strtok(NULL, sep)) {
8112c3632d1SSimon J. Gerraty 		Lst_Append(lp, cp);
8123955d011SMarcel Moolenaar 		n++;
8133955d011SMarcel Moolenaar 	}
8143841c287SSimon J. Gerraty 	return n;
8153955d011SMarcel Moolenaar }
8163955d011SMarcel Moolenaar 
8173955d011SMarcel Moolenaar #ifdef SIGINFO
8183955d011SMarcel Moolenaar /*ARGSUSED*/
8193955d011SMarcel Moolenaar static void
8203955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED)
8213955d011SMarcel Moolenaar {
8223955d011SMarcel Moolenaar 	char dir[MAXPATHLEN];
8233955d011SMarcel Moolenaar 	char str[2 * MAXPATHLEN];
8243955d011SMarcel Moolenaar 	int len;
825e2eeea75SSimon J. Gerraty 	if (getcwd(dir, sizeof dir) == NULL)
8263955d011SMarcel Moolenaar 		return;
827e2eeea75SSimon J. Gerraty 	len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir);
8283955d011SMarcel Moolenaar 	if (len > 0)
8293955d011SMarcel Moolenaar 		(void)write(STDERR_FILENO, str, (size_t)len);
8303955d011SMarcel Moolenaar }
8313955d011SMarcel Moolenaar #endif
8323955d011SMarcel Moolenaar 
83306b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */
83406b9b3e0SSimon J. Gerraty static void
83506b9b3e0SSimon J. Gerraty MakeMode(void)
8363955d011SMarcel Moolenaar {
837*dba7b0efSSimon J. Gerraty 	char *mode;
8383955d011SMarcel Moolenaar 
839*dba7b0efSSimon J. Gerraty 	(void)Var_Subst("${" MAKE_MODE ":tl}", SCOPE_GLOBAL, VARE_WANTRES, &mode);
840956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
8413955d011SMarcel Moolenaar 
842*dba7b0efSSimon J. Gerraty 	if (mode[0] != '\0') {
843*dba7b0efSSimon J. Gerraty 		if (strstr(mode, "compat") != NULL) {
844956e45f6SSimon J. Gerraty 			opts.compatMake = TRUE;
8453955d011SMarcel Moolenaar 			forceJobs = FALSE;
8463955d011SMarcel Moolenaar 		}
8473955d011SMarcel Moolenaar #if USE_META
848*dba7b0efSSimon J. Gerraty 		if (strstr(mode, "meta") != NULL)
849*dba7b0efSSimon J. Gerraty 			meta_mode_init(mode);
8503955d011SMarcel Moolenaar #endif
8513955d011SMarcel Moolenaar 	}
852be19d90bSSimon J. Gerraty 
853*dba7b0efSSimon J. Gerraty 	free(mode);
8543955d011SMarcel Moolenaar }
8553955d011SMarcel Moolenaar 
8568695518cSSimon J. Gerraty static void
857956e45f6SSimon J. Gerraty PrintVar(const char *varname, Boolean expandVars)
858956e45f6SSimon J. Gerraty {
85906b9b3e0SSimon J. Gerraty 	if (strchr(varname, '$') != NULL) {
860956e45f6SSimon J. Gerraty 		char *evalue;
861*dba7b0efSSimon J. Gerraty 		(void)Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES, &evalue);
862956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
863956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
864956e45f6SSimon J. Gerraty 		bmake_free(evalue);
865956e45f6SSimon J. Gerraty 
866956e45f6SSimon J. Gerraty 	} else if (expandVars) {
867956e45f6SSimon J. Gerraty 		char *expr = str_concat3("${", varname, "}");
868956e45f6SSimon J. Gerraty 		char *evalue;
869*dba7b0efSSimon J. Gerraty 		(void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &evalue);
870956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
871956e45f6SSimon J. Gerraty 		free(expr);
872956e45f6SSimon J. Gerraty 		printf("%s\n", evalue);
873956e45f6SSimon J. Gerraty 		bmake_free(evalue);
874956e45f6SSimon J. Gerraty 
875956e45f6SSimon J. Gerraty 	} else {
876*dba7b0efSSimon J. Gerraty 		FStr value = Var_Value(SCOPE_GLOBAL, varname);
87706b9b3e0SSimon J. Gerraty 		printf("%s\n", value.str != NULL ? value.str : "");
87806b9b3e0SSimon J. Gerraty 		FStr_Done(&value);
879956e45f6SSimon J. Gerraty 	}
880956e45f6SSimon J. Gerraty }
881956e45f6SSimon J. Gerraty 
882e2eeea75SSimon J. Gerraty /*
883e2eeea75SSimon J. Gerraty  * Return a Boolean based on a variable.
884e2eeea75SSimon J. Gerraty  *
885e2eeea75SSimon J. Gerraty  * If the knob is not set, return the fallback.
886e2eeea75SSimon J. Gerraty  * If set, anything that looks or smells like "No", "False", "Off", "0", etc.
887e2eeea75SSimon J. Gerraty  * is FALSE, otherwise TRUE.
888e2eeea75SSimon J. Gerraty  */
889e2eeea75SSimon J. Gerraty Boolean
890e2eeea75SSimon J. Gerraty GetBooleanVar(const char *varname, Boolean fallback)
891e2eeea75SSimon J. Gerraty {
892e2eeea75SSimon J. Gerraty 	char *expr = str_concat3("${", varname, ":U}");
893e2eeea75SSimon J. Gerraty 	char *value;
894e2eeea75SSimon J. Gerraty 	Boolean res;
895e2eeea75SSimon J. Gerraty 
896*dba7b0efSSimon J. Gerraty 	(void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value);
897e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
898e2eeea75SSimon J. Gerraty 	res = ParseBoolean(value, fallback);
899e2eeea75SSimon J. Gerraty 	free(value);
900e2eeea75SSimon J. Gerraty 	free(expr);
901e2eeea75SSimon J. Gerraty 	return res;
902e2eeea75SSimon J. Gerraty }
903e2eeea75SSimon J. Gerraty 
904956e45f6SSimon J. Gerraty static void
9058695518cSSimon J. Gerraty doPrintVars(void)
9068695518cSSimon J. Gerraty {
907956e45f6SSimon J. Gerraty 	StringListNode *ln;
9088695518cSSimon J. Gerraty 	Boolean expandVars;
9098695518cSSimon J. Gerraty 
910e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_EXPANDED)
9118695518cSSimon J. Gerraty 		expandVars = TRUE;
912956e45f6SSimon J. Gerraty 	else if (opts.debugVflag)
9138695518cSSimon J. Gerraty 		expandVars = FALSE;
9148695518cSSimon J. Gerraty 	else
915e2eeea75SSimon J. Gerraty 		expandVars = GetBooleanVar(".MAKE.EXPAND_VARIABLES", FALSE);
9168695518cSSimon J. Gerraty 
91706b9b3e0SSimon J. Gerraty 	for (ln = opts.variables.first; ln != NULL; ln = ln->next) {
918956e45f6SSimon J. Gerraty 		const char *varname = ln->datum;
919956e45f6SSimon J. Gerraty 		PrintVar(varname, expandVars);
9208695518cSSimon J. Gerraty 	}
9218695518cSSimon J. Gerraty }
9228695518cSSimon J. Gerraty 
9238695518cSSimon J. Gerraty static Boolean
9248695518cSSimon J. Gerraty runTargets(void)
9258695518cSSimon J. Gerraty {
92606b9b3e0SSimon J. Gerraty 	GNodeList targs = LST_INIT;	/* target nodes to create */
9278695518cSSimon J. Gerraty 	Boolean outOfDate;	/* FALSE if all targets up to date */
9288695518cSSimon J. Gerraty 
9298695518cSSimon J. Gerraty 	/*
9308695518cSSimon J. Gerraty 	 * Have now read the entire graph and need to make a list of
9318695518cSSimon J. Gerraty 	 * targets to create. If none was given on the command line,
9328695518cSSimon J. Gerraty 	 * we consult the parsing module to find the main target(s)
9338695518cSSimon J. Gerraty 	 * to create.
9348695518cSSimon J. Gerraty 	 */
93506b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create))
93606b9b3e0SSimon J. Gerraty 		Parse_MainName(&targs);
9378695518cSSimon J. Gerraty 	else
93806b9b3e0SSimon J. Gerraty 		Targ_FindList(&targs, &opts.create);
9398695518cSSimon J. Gerraty 
940956e45f6SSimon J. Gerraty 	if (!opts.compatMake) {
9418695518cSSimon J. Gerraty 		/*
9428695518cSSimon J. Gerraty 		 * Initialize job module before traversing the graph
9438695518cSSimon J. Gerraty 		 * now that any .BEGIN and .END targets have been read.
9448695518cSSimon J. Gerraty 		 * This is done only if the -q flag wasn't given
9458695518cSSimon J. Gerraty 		 * (to prevent the .BEGIN from being executed should
9468695518cSSimon J. Gerraty 		 * it exist).
9478695518cSSimon J. Gerraty 		 */
948956e45f6SSimon J. Gerraty 		if (!opts.queryFlag) {
9498695518cSSimon J. Gerraty 			Job_Init();
9508695518cSSimon J. Gerraty 			jobsRunning = TRUE;
9518695518cSSimon J. Gerraty 		}
9528695518cSSimon J. Gerraty 
9538695518cSSimon J. Gerraty 		/* Traverse the graph, checking on all the targets */
95406b9b3e0SSimon J. Gerraty 		outOfDate = Make_Run(&targs);
9558695518cSSimon J. Gerraty 	} else {
9568695518cSSimon J. Gerraty 		/*
9578695518cSSimon J. Gerraty 		 * Compat_Init will take care of creating all the
9588695518cSSimon J. Gerraty 		 * targets as well as initializing the module.
9598695518cSSimon J. Gerraty 		 */
96006b9b3e0SSimon J. Gerraty 		Compat_Run(&targs);
9618695518cSSimon J. Gerraty 		outOfDate = FALSE;
9628695518cSSimon J. Gerraty 	}
963*dba7b0efSSimon J. Gerraty 	Lst_Done(&targs);	/* Don't free the targets themselves. */
9648695518cSSimon J. Gerraty 	return outOfDate;
9658695518cSSimon J. Gerraty }
9668695518cSSimon J. Gerraty 
967956e45f6SSimon J. Gerraty /*
968956e45f6SSimon J. Gerraty  * Set up the .TARGETS variable to contain the list of targets to be
969956e45f6SSimon J. Gerraty  * created. If none specified, make the variable empty -- the parser
970956e45f6SSimon J. Gerraty  * will fill the thing in with the default or .MAIN target.
971956e45f6SSimon J. Gerraty  */
972956e45f6SSimon J. Gerraty static void
973956e45f6SSimon J. Gerraty InitVarTargets(void)
974956e45f6SSimon J. Gerraty {
975956e45f6SSimon J. Gerraty 	StringListNode *ln;
976956e45f6SSimon J. Gerraty 
97706b9b3e0SSimon J. Gerraty 	if (Lst_IsEmpty(&opts.create)) {
978*dba7b0efSSimon J. Gerraty 		Global_Set(".TARGETS", "");
979956e45f6SSimon J. Gerraty 		return;
980956e45f6SSimon J. Gerraty 	}
981956e45f6SSimon J. Gerraty 
98206b9b3e0SSimon J. Gerraty 	for (ln = opts.create.first; ln != NULL; ln = ln->next) {
983*dba7b0efSSimon J. Gerraty 		const char *name = ln->datum;
984*dba7b0efSSimon J. Gerraty 		Global_Append(".TARGETS", name);
985956e45f6SSimon J. Gerraty 	}
986956e45f6SSimon J. Gerraty }
987956e45f6SSimon J. Gerraty 
988956e45f6SSimon J. Gerraty static void
989956e45f6SSimon J. Gerraty InitRandom(void)
990956e45f6SSimon J. Gerraty {
991956e45f6SSimon J. Gerraty 	struct timeval tv;
992956e45f6SSimon J. Gerraty 
993956e45f6SSimon J. Gerraty 	gettimeofday(&tv, NULL);
994956e45f6SSimon J. Gerraty 	srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
995956e45f6SSimon J. Gerraty }
996956e45f6SSimon J. Gerraty 
997956e45f6SSimon J. Gerraty static const char *
998*dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED)
999956e45f6SSimon J. Gerraty {
1000956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE
1001e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE;
1002956e45f6SSimon J. Gerraty #else
1003956e45f6SSimon J. Gerraty     	const char *machine = getenv("MACHINE");
1004e2eeea75SSimon J. Gerraty 
1005956e45f6SSimon J. Gerraty 	if (machine != NULL)
1006956e45f6SSimon J. Gerraty 		return machine;
1007956e45f6SSimon J. Gerraty 
1008e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE)
1009956e45f6SSimon J. Gerraty 	return utsname->machine;
1010e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE)
1011956e45f6SSimon J. Gerraty 	return MAKE_MACHINE;
1012956e45f6SSimon J. Gerraty #else
1013956e45f6SSimon J. Gerraty 	return "unknown";
1014956e45f6SSimon J. Gerraty #endif
1015956e45f6SSimon J. Gerraty #endif
1016956e45f6SSimon J. Gerraty }
1017956e45f6SSimon J. Gerraty 
1018956e45f6SSimon J. Gerraty static const char *
1019e2eeea75SSimon J. Gerraty InitVarMachineArch(void)
1020956e45f6SSimon J. Gerraty {
1021e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH
1022e2eeea75SSimon J. Gerraty 	return FORCE_MACHINE_ARCH;
1023e2eeea75SSimon J. Gerraty #else
1024956e45f6SSimon J. Gerraty 	const char *env = getenv("MACHINE_ARCH");
1025956e45f6SSimon J. Gerraty 	if (env != NULL)
1026956e45f6SSimon J. Gerraty 		return env;
1027956e45f6SSimon J. Gerraty 
1028956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW)
1029956e45f6SSimon J. Gerraty 	{
1030956e45f6SSimon J. Gerraty 		struct utsname utsname;
1031e2eeea75SSimon J. Gerraty 		static char machine_arch_buf[sizeof utsname.machine];
1032956e45f6SSimon J. Gerraty 		const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
1033e2eeea75SSimon J. Gerraty 		size_t len = sizeof machine_arch_buf;
1034956e45f6SSimon J. Gerraty 
103506b9b3e0SSimon J. Gerraty 		if (sysctl(mib, (unsigned int)__arraycount(mib),
103606b9b3e0SSimon J. Gerraty 		    machine_arch_buf, &len, NULL, 0) < 0) {
103706b9b3e0SSimon J. Gerraty 			(void)fprintf(stderr, "%s: sysctl failed (%s).\n",
103806b9b3e0SSimon J. Gerraty 			    progname, strerror(errno));
1039956e45f6SSimon J. Gerraty 			exit(2);
1040956e45f6SSimon J. Gerraty 		}
1041956e45f6SSimon J. Gerraty 
1042956e45f6SSimon J. Gerraty 		return machine_arch_buf;
1043956e45f6SSimon J. Gerraty 	}
1044e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH)
1045e2eeea75SSimon J. Gerraty 	return MACHINE_ARCH;
1046e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH)
1047956e45f6SSimon J. Gerraty 	return MAKE_MACHINE_ARCH;
1048956e45f6SSimon J. Gerraty #else
1049956e45f6SSimon J. Gerraty 	return "unknown";
1050956e45f6SSimon J. Gerraty #endif
1051956e45f6SSimon J. Gerraty #endif
1052956e45f6SSimon J. Gerraty }
1053956e45f6SSimon J. Gerraty 
1054956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE
1055956e45f6SSimon J. Gerraty /*
1056956e45f6SSimon J. Gerraty  * All this code is so that we know where we are when we start up
1057956e45f6SSimon J. Gerraty  * on a different machine with pmake.
1058956e45f6SSimon J. Gerraty  *
1059*dba7b0efSSimon J. Gerraty  * XXX: Make no longer has "local" and "remote" mode.  Is this code still
1060*dba7b0efSSimon J. Gerraty  * necessary?
1061*dba7b0efSSimon J. Gerraty  *
1062956e45f6SSimon J. Gerraty  * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1063956e45f6SSimon J. Gerraty  * since the value of curdir can vary depending on how we got
1064956e45f6SSimon J. Gerraty  * here.  Ie sitting at a shell prompt (shell that provides $PWD)
1065956e45f6SSimon J. Gerraty  * or via subdir.mk in which case its likely a shell which does
1066956e45f6SSimon J. Gerraty  * not provide it.
1067956e45f6SSimon J. Gerraty  *
1068956e45f6SSimon J. Gerraty  * So, to stop it breaking this case only, we ignore PWD if
1069956e45f6SSimon J. Gerraty  * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression.
1070956e45f6SSimon J. Gerraty  */
1071956e45f6SSimon J. Gerraty static void
1072956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st)
1073956e45f6SSimon J. Gerraty {
1074956e45f6SSimon J. Gerraty 	char *pwd;
107506b9b3e0SSimon J. Gerraty 	FStr prefix, makeobjdir;
1076956e45f6SSimon J. Gerraty 	struct stat pwd_st;
1077956e45f6SSimon J. Gerraty 
1078956e45f6SSimon J. Gerraty 	if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1079956e45f6SSimon J. Gerraty 		return;
1080956e45f6SSimon J. Gerraty 
1081*dba7b0efSSimon J. Gerraty 	prefix = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX");
108206b9b3e0SSimon J. Gerraty 	if (prefix.str != NULL) {
108306b9b3e0SSimon J. Gerraty 		FStr_Done(&prefix);
1084956e45f6SSimon J. Gerraty 		return;
1085956e45f6SSimon J. Gerraty 	}
1086956e45f6SSimon J. Gerraty 
1087*dba7b0efSSimon J. Gerraty 	makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR");
108806b9b3e0SSimon J. Gerraty 	if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
1089956e45f6SSimon J. Gerraty 		goto ignore_pwd;
1090956e45f6SSimon J. Gerraty 
1091956e45f6SSimon J. Gerraty 	if (stat(pwd, &pwd_st) == 0 &&
1092956e45f6SSimon J. Gerraty 	    curdir_st->st_ino == pwd_st.st_ino &&
1093956e45f6SSimon J. Gerraty 	    curdir_st->st_dev == pwd_st.st_dev)
1094956e45f6SSimon J. Gerraty 		(void)strncpy(curdir, pwd, MAXPATHLEN);
1095956e45f6SSimon J. Gerraty 
1096956e45f6SSimon J. Gerraty ignore_pwd:
109706b9b3e0SSimon J. Gerraty 	FStr_Done(&makeobjdir);
1098956e45f6SSimon J. Gerraty }
1099956e45f6SSimon J. Gerraty #endif
1100956e45f6SSimon J. Gerraty 
1101956e45f6SSimon J. Gerraty /*
1102956e45f6SSimon J. Gerraty  * Find the .OBJDIR.  If MAKEOBJDIRPREFIX, or failing that,
1103956e45f6SSimon J. Gerraty  * MAKEOBJDIR is set in the environment, try only that value
1104956e45f6SSimon J. Gerraty  * and fall back to .CURDIR if it does not exist.
1105956e45f6SSimon J. Gerraty  *
1106956e45f6SSimon J. Gerraty  * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
1107956e45f6SSimon J. Gerraty  * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order.  If none
1108956e45f6SSimon J. Gerraty  * of these paths exist, just use .CURDIR.
1109956e45f6SSimon J. Gerraty  */
1110956e45f6SSimon J. Gerraty static void
1111956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch)
1112956e45f6SSimon J. Gerraty {
1113e2eeea75SSimon J. Gerraty 	Boolean writable;
1114956e45f6SSimon J. Gerraty 
111506b9b3e0SSimon J. Gerraty 	Dir_InitCur(curdir);
1116e2eeea75SSimon J. Gerraty 	writable = GetBooleanVar("MAKE_OBJDIR_CHECK_WRITABLE", TRUE);
1117e2eeea75SSimon J. Gerraty 	(void)Main_SetObjdir(FALSE, "%s", curdir);
1118e2eeea75SSimon J. Gerraty 
1119e2eeea75SSimon J. Gerraty 	if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
1120e2eeea75SSimon J. Gerraty 	    !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
1121e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1122e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
1123e2eeea75SSimon J. Gerraty 	    !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
1124e2eeea75SSimon J. Gerraty 		(void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
1125956e45f6SSimon J. Gerraty }
1126956e45f6SSimon J. Gerraty 
1127956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */
1128956e45f6SSimon J. Gerraty static void
1129956e45f6SSimon J. Gerraty UnlimitFiles(void)
1130956e45f6SSimon J. Gerraty {
1131956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
1132956e45f6SSimon J. Gerraty 	struct rlimit rl;
1133956e45f6SSimon J. Gerraty 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1134956e45f6SSimon J. Gerraty 	    rl.rlim_cur != rl.rlim_max) {
1135956e45f6SSimon J. Gerraty 		rl.rlim_cur = rl.rlim_max;
1136956e45f6SSimon J. Gerraty 		(void)setrlimit(RLIMIT_NOFILE, &rl);
1137956e45f6SSimon J. Gerraty 	}
1138956e45f6SSimon J. Gerraty #endif
1139956e45f6SSimon J. Gerraty }
1140956e45f6SSimon J. Gerraty 
1141956e45f6SSimon J. Gerraty static void
1142956e45f6SSimon J. Gerraty CmdOpts_Init(void)
1143956e45f6SSimon J. Gerraty {
114406b9b3e0SSimon J. Gerraty 	opts.compatMake = FALSE;
114506b9b3e0SSimon J. Gerraty 	opts.debug = DEBUG_NONE;
1146*dba7b0efSSimon J. Gerraty 	/* opts.debug_file has already been initialized earlier */
114706b9b3e0SSimon J. Gerraty 	opts.strict = FALSE;
1148956e45f6SSimon J. Gerraty 	opts.debugVflag = FALSE;
1149956e45f6SSimon J. Gerraty 	opts.checkEnvFirst = FALSE;
115006b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.makefiles);
1151956e45f6SSimon J. Gerraty 	opts.ignoreErrors = FALSE;	/* Pay attention to non-zero returns */
115206b9b3e0SSimon J. Gerraty 	opts.maxJobs = 1;
1153956e45f6SSimon J. Gerraty 	opts.keepgoing = FALSE;		/* Stop on error */
1154956e45f6SSimon J. Gerraty 	opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */
1155956e45f6SSimon J. Gerraty 	opts.noExecute = FALSE;		/* Execute all commands */
115606b9b3e0SSimon J. Gerraty 	opts.queryFlag = FALSE;
1157956e45f6SSimon J. Gerraty 	opts.noBuiltins = FALSE;	/* Read the built-in rules */
1158956e45f6SSimon J. Gerraty 	opts.beSilent = FALSE;		/* Print commands as executed */
115906b9b3e0SSimon J. Gerraty 	opts.touchFlag = FALSE;
1160e2eeea75SSimon J. Gerraty 	opts.printVars = PVM_NONE;
116106b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.variables);
1162956e45f6SSimon J. Gerraty 	opts.parseWarnFatal = FALSE;
1163956e45f6SSimon J. Gerraty 	opts.enterFlag = FALSE;
1164956e45f6SSimon J. Gerraty 	opts.varNoExportEnv = FALSE;
116506b9b3e0SSimon J. Gerraty 	Lst_Init(&opts.create);
1166956e45f6SSimon J. Gerraty }
1167956e45f6SSimon J. Gerraty 
116806b9b3e0SSimon J. Gerraty /*
116906b9b3e0SSimon J. Gerraty  * Initialize MAKE and .MAKE to the path of the executable, so that it can be
1170956e45f6SSimon J. Gerraty  * found by execvp(3) and the shells, even after a chdir.
1171956e45f6SSimon J. Gerraty  *
1172956e45f6SSimon J. Gerraty  * If it's a relative path and contains a '/', resolve it to an absolute path.
117306b9b3e0SSimon J. Gerraty  * Otherwise keep it as is, assuming it will be found in the PATH.
117406b9b3e0SSimon J. Gerraty  */
1175956e45f6SSimon J. Gerraty static void
1176956e45f6SSimon J. Gerraty InitVarMake(const char *argv0)
1177956e45f6SSimon J. Gerraty {
1178956e45f6SSimon J. Gerraty 	const char *make = argv0;
1179956e45f6SSimon J. Gerraty 
1180956e45f6SSimon J. Gerraty 	if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
1181956e45f6SSimon J. Gerraty 		char pathbuf[MAXPATHLEN];
118206b9b3e0SSimon J. Gerraty 		const char *abspath = cached_realpath(argv0, pathbuf);
1183956e45f6SSimon J. Gerraty 		struct stat st;
118406b9b3e0SSimon J. Gerraty 		if (abspath != NULL && abspath[0] == '/' &&
118506b9b3e0SSimon J. Gerraty 		    stat(make, &st) == 0)
118606b9b3e0SSimon J. Gerraty 			make = abspath;
1187956e45f6SSimon J. Gerraty 	}
1188956e45f6SSimon J. Gerraty 
1189*dba7b0efSSimon J. Gerraty 	Global_Set("MAKE", make);
1190*dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE", make);
1191956e45f6SSimon J. Gerraty }
1192956e45f6SSimon J. Gerraty 
119306b9b3e0SSimon J. Gerraty /*
119406b9b3e0SSimon J. Gerraty  * Add the directories from the colon-separated syspath to defSysIncPath.
119506b9b3e0SSimon J. Gerraty  * After returning, the contents of syspath is unspecified.
119606b9b3e0SSimon J. Gerraty  */
1197956e45f6SSimon J. Gerraty static void
1198956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath)
1199956e45f6SSimon J. Gerraty {
1200956e45f6SSimon J. Gerraty 	static char defsyspath[] = _PATH_DEFSYSPATH;
1201956e45f6SSimon J. Gerraty 	char *start, *cp;
1202956e45f6SSimon J. Gerraty 
1203956e45f6SSimon J. Gerraty 	/*
1204956e45f6SSimon J. Gerraty 	 * If no user-supplied system path was given (through the -m option)
1205956e45f6SSimon J. Gerraty 	 * add the directories from the DEFSYSPATH (more than one may be given
1206956e45f6SSimon J. Gerraty 	 * as dir1:...:dirn) to the system include path.
1207956e45f6SSimon J. Gerraty 	 */
1208956e45f6SSimon J. Gerraty 	if (syspath == NULL || syspath[0] == '\0')
1209956e45f6SSimon J. Gerraty 		syspath = defsyspath;
1210956e45f6SSimon J. Gerraty 	else
1211956e45f6SSimon J. Gerraty 		syspath = bmake_strdup(syspath);
1212956e45f6SSimon J. Gerraty 
1213956e45f6SSimon J. Gerraty 	for (start = syspath; *start != '\0'; start = cp) {
1214956e45f6SSimon J. Gerraty 		for (cp = start; *cp != '\0' && *cp != ':'; cp++)
1215956e45f6SSimon J. Gerraty 			continue;
1216e2eeea75SSimon J. Gerraty 		if (*cp == ':')
1217956e45f6SSimon J. Gerraty 			*cp++ = '\0';
1218e2eeea75SSimon J. Gerraty 
1219956e45f6SSimon J. Gerraty 		/* look for magic parent directory search string */
1220e2eeea75SSimon J. Gerraty 		if (strncmp(start, ".../", 4) == 0) {
1221956e45f6SSimon J. Gerraty 			char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1222956e45f6SSimon J. Gerraty 			if (dir != NULL) {
1223*dba7b0efSSimon J. Gerraty 				(void)SearchPath_Add(defSysIncPath, dir);
1224956e45f6SSimon J. Gerraty 				free(dir);
1225956e45f6SSimon J. Gerraty 			}
1226e2eeea75SSimon J. Gerraty 		} else {
1227*dba7b0efSSimon J. Gerraty 			(void)SearchPath_Add(defSysIncPath, start);
1228956e45f6SSimon J. Gerraty 		}
1229956e45f6SSimon J. Gerraty 	}
1230956e45f6SSimon J. Gerraty 
1231956e45f6SSimon J. Gerraty 	if (syspath != defsyspath)
1232956e45f6SSimon J. Gerraty 		free(syspath);
1233956e45f6SSimon J. Gerraty }
1234956e45f6SSimon J. Gerraty 
1235956e45f6SSimon J. Gerraty static void
1236956e45f6SSimon J. Gerraty ReadBuiltinRules(void)
1237956e45f6SSimon J. Gerraty {
1238e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1239*dba7b0efSSimon J. Gerraty 	StringList sysMkFiles = LST_INIT;
1240e2eeea75SSimon J. Gerraty 
1241*dba7b0efSSimon J. Gerraty 	SearchPath_Expand(
1242*dba7b0efSSimon J. Gerraty 	    Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath,
1243*dba7b0efSSimon J. Gerraty 	    _PATH_DEFSYSMK,
1244*dba7b0efSSimon J. Gerraty 	    &sysMkFiles);
1245*dba7b0efSSimon J. Gerraty 	if (Lst_IsEmpty(&sysMkFiles))
1246956e45f6SSimon J. Gerraty 		Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1247e2eeea75SSimon J. Gerraty 
1248*dba7b0efSSimon J. Gerraty 	for (ln = sysMkFiles.first; ln != NULL; ln = ln->next)
1249e2eeea75SSimon J. Gerraty 		if (ReadMakefile(ln->datum) == 0)
1250e2eeea75SSimon J. Gerraty 			break;
1251e2eeea75SSimon J. Gerraty 
1252e2eeea75SSimon J. Gerraty 	if (ln == NULL)
1253e2eeea75SSimon J. Gerraty 		Fatal("%s: cannot open %s.",
1254*dba7b0efSSimon J. Gerraty 		    progname, (const char *)sysMkFiles.first->datum);
1255e2eeea75SSimon J. Gerraty 
1256*dba7b0efSSimon J. Gerraty 	/* Free the list nodes but not the actual filenames since these may
1257*dba7b0efSSimon J. Gerraty 	 * still be used in GNodes. */
1258*dba7b0efSSimon J. Gerraty 	Lst_Done(&sysMkFiles);
1259956e45f6SSimon J. Gerraty }
1260956e45f6SSimon J. Gerraty 
1261956e45f6SSimon J. Gerraty static void
1262956e45f6SSimon J. Gerraty InitMaxJobs(void)
1263956e45f6SSimon J. Gerraty {
1264956e45f6SSimon J. Gerraty 	char *value;
1265956e45f6SSimon J. Gerraty 	int n;
1266956e45f6SSimon J. Gerraty 
1267956e45f6SSimon J. Gerraty 	if (forceJobs || opts.compatMake ||
1268*dba7b0efSSimon J. Gerraty 	    !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
1269956e45f6SSimon J. Gerraty 		return;
1270956e45f6SSimon J. Gerraty 
1271*dba7b0efSSimon J. Gerraty 	(void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value);
1272956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1273956e45f6SSimon J. Gerraty 	n = (int)strtol(value, NULL, 0);
1274956e45f6SSimon J. Gerraty 	if (n < 1) {
1275956e45f6SSimon J. Gerraty 		(void)fprintf(stderr,
1276956e45f6SSimon J. Gerraty 		    "%s: illegal value for .MAKE.JOBS "
1277956e45f6SSimon J. Gerraty 		    "-- must be positive integer!\n",
1278956e45f6SSimon J. Gerraty 		    progname);
127906b9b3e0SSimon J. Gerraty 		exit(2);	/* Not 1 so -q can distinguish error */
1280956e45f6SSimon J. Gerraty 	}
1281956e45f6SSimon J. Gerraty 
1282956e45f6SSimon J. Gerraty 	if (n != opts.maxJobs) {
1283*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, "-j");
1284*dba7b0efSSimon J. Gerraty 		Global_Append(MAKEFLAGS, value);
1285956e45f6SSimon J. Gerraty 	}
1286956e45f6SSimon J. Gerraty 
1287956e45f6SSimon J. Gerraty 	opts.maxJobs = n;
1288956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
1289956e45f6SSimon J. Gerraty 	forceJobs = TRUE;
1290956e45f6SSimon J. Gerraty 	free(value);
1291956e45f6SSimon J. Gerraty }
1292956e45f6SSimon J. Gerraty 
1293956e45f6SSimon J. Gerraty /*
1294956e45f6SSimon J. Gerraty  * For compatibility, look at the directories in the VPATH variable
1295956e45f6SSimon J. Gerraty  * and add them to the search path, if the variable is defined. The
1296956e45f6SSimon J. Gerraty  * variable's value is in the same format as the PATH environment
1297956e45f6SSimon J. Gerraty  * variable, i.e. <directory>:<directory>:<directory>...
1298956e45f6SSimon J. Gerraty  */
1299956e45f6SSimon J. Gerraty static void
1300956e45f6SSimon J. Gerraty InitVpath(void)
1301956e45f6SSimon J. Gerraty {
1302956e45f6SSimon J. Gerraty 	char *vpath, savec, *path;
1303*dba7b0efSSimon J. Gerraty 	if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
1304956e45f6SSimon J. Gerraty 		return;
1305956e45f6SSimon J. Gerraty 
1306*dba7b0efSSimon J. Gerraty 	(void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath);
1307956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
1308956e45f6SSimon J. Gerraty 	path = vpath;
1309956e45f6SSimon J. Gerraty 	do {
1310956e45f6SSimon J. Gerraty 		char *cp;
1311956e45f6SSimon J. Gerraty 		/* skip to end of directory */
1312956e45f6SSimon J. Gerraty 		for (cp = path; *cp != ':' && *cp != '\0'; cp++)
1313956e45f6SSimon J. Gerraty 			continue;
1314956e45f6SSimon J. Gerraty 		/* Save terminator character so know when to stop */
1315956e45f6SSimon J. Gerraty 		savec = *cp;
1316956e45f6SSimon J. Gerraty 		*cp = '\0';
1317956e45f6SSimon J. Gerraty 		/* Add directory to search path */
1318*dba7b0efSSimon J. Gerraty 		(void)SearchPath_Add(&dirSearchPath, path);
1319956e45f6SSimon J. Gerraty 		*cp = savec;
1320956e45f6SSimon J. Gerraty 		path = cp + 1;
1321956e45f6SSimon J. Gerraty 	} while (savec == ':');
1322956e45f6SSimon J. Gerraty 	free(vpath);
1323956e45f6SSimon J. Gerraty }
1324956e45f6SSimon J. Gerraty 
1325956e45f6SSimon J. Gerraty static void
1326e2eeea75SSimon J. Gerraty ReadAllMakefiles(StringList *makefiles)
1327956e45f6SSimon J. Gerraty {
1328956e45f6SSimon J. Gerraty 	StringListNode *ln;
1329956e45f6SSimon J. Gerraty 
1330e2eeea75SSimon J. Gerraty 	for (ln = makefiles->first; ln != NULL; ln = ln->next) {
1331e2eeea75SSimon J. Gerraty 		const char *fname = ln->datum;
1332e2eeea75SSimon J. Gerraty 		if (ReadMakefile(fname) != 0)
1333e2eeea75SSimon J. Gerraty 			Fatal("%s: cannot open %s.", progname, fname);
1334956e45f6SSimon J. Gerraty 	}
1335956e45f6SSimon J. Gerraty }
1336956e45f6SSimon J. Gerraty 
1337956e45f6SSimon J. Gerraty static void
1338e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void)
1339956e45f6SSimon J. Gerraty {
1340e2eeea75SSimon J. Gerraty 	StringListNode *ln;
1341e2eeea75SSimon J. Gerraty 	char *prefs;
1342956e45f6SSimon J. Gerraty 
1343e2eeea75SSimon J. Gerraty 	(void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}",
1344*dba7b0efSSimon J. Gerraty 	    SCOPE_CMDLINE, VARE_WANTRES, &prefs);
1345e2eeea75SSimon J. Gerraty 	/* TODO: handle errors */
1346956e45f6SSimon J. Gerraty 
1347e2eeea75SSimon J. Gerraty 	/* XXX: This should use a local list instead of opts.makefiles
1348e2eeea75SSimon J. Gerraty 	 * since these makefiles do not come from the command line.  They
1349e2eeea75SSimon J. Gerraty 	 * also have different semantics in that only the first file that
1350e2eeea75SSimon J. Gerraty 	 * is found is processed.  See ReadAllMakefiles. */
135106b9b3e0SSimon J. Gerraty 	(void)str2Lst_Append(&opts.makefiles, prefs);
1352956e45f6SSimon J. Gerraty 
135306b9b3e0SSimon J. Gerraty 	for (ln = opts.makefiles.first; ln != NULL; ln = ln->next)
1354e2eeea75SSimon J. Gerraty 		if (ReadMakefile(ln->datum) == 0)
1355e2eeea75SSimon J. Gerraty 			break;
1356956e45f6SSimon J. Gerraty 
1357e2eeea75SSimon J. Gerraty 	free(prefs);
1358956e45f6SSimon J. Gerraty }
1359956e45f6SSimon J. Gerraty 
136006b9b3e0SSimon J. Gerraty /*
136106b9b3e0SSimon J. Gerraty  * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
1362e2eeea75SSimon J. Gerraty  * Initialize a few modules.
136306b9b3e0SSimon J. Gerraty  * Parse the arguments from MAKEFLAGS and the command line.
136406b9b3e0SSimon J. Gerraty  */
1365e2eeea75SSimon J. Gerraty static void
1366e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv)
13673955d011SMarcel Moolenaar {
1368956e45f6SSimon J. Gerraty 	struct stat sa;
1369956e45f6SSimon J. Gerraty 	const char *machine;
1370956e45f6SSimon J. Gerraty 	const char *machine_arch;
13713955d011SMarcel Moolenaar 	char *syspath = getenv("MAKESYSPATH");
13723955d011SMarcel Moolenaar 	struct utsname utsname;
13733955d011SMarcel Moolenaar 
13743955d011SMarcel Moolenaar 	/* default to writing debug to stderr */
1375956e45f6SSimon J. Gerraty 	opts.debug_file = stderr;
13763955d011SMarcel Moolenaar 
1377e2eeea75SSimon J. Gerraty 	HashTable_Init(&cached_realpaths);
1378e2eeea75SSimon J. Gerraty 
13793955d011SMarcel Moolenaar #ifdef SIGINFO
13803955d011SMarcel Moolenaar 	(void)bmake_signal(SIGINFO, siginfo);
13813955d011SMarcel Moolenaar #endif
1382956e45f6SSimon J. Gerraty 
1383956e45f6SSimon J. Gerraty 	InitRandom();
13843955d011SMarcel Moolenaar 
138506b9b3e0SSimon J. Gerraty 	progname = str_basename(argv[0]);
1386956e45f6SSimon J. Gerraty 
1387956e45f6SSimon J. Gerraty 	UnlimitFiles();
13883955d011SMarcel Moolenaar 
13891748de26SSimon J. Gerraty 	if (uname(&utsname) == -1) {
13901748de26SSimon J. Gerraty 		(void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
13911748de26SSimon J. Gerraty 		    strerror(errno));
13921748de26SSimon J. Gerraty 		exit(2);
13931748de26SSimon J. Gerraty 	}
13941748de26SSimon J. Gerraty 
13953955d011SMarcel Moolenaar 	/*
13963955d011SMarcel Moolenaar 	 * Get the name of this type of MACHINE from utsname
13973955d011SMarcel Moolenaar 	 * so we can share an executable for similar machines.
13983955d011SMarcel Moolenaar 	 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
13993955d011SMarcel Moolenaar 	 *
14003955d011SMarcel Moolenaar 	 * Note that both MACHINE and MACHINE_ARCH are decided at
14013955d011SMarcel Moolenaar 	 * run-time.
14023955d011SMarcel Moolenaar 	 */
1403e2eeea75SSimon J. Gerraty 	machine = InitVarMachine(&utsname);
1404e2eeea75SSimon J. Gerraty 	machine_arch = InitVarMachineArch();
14053955d011SMarcel Moolenaar 
14063955d011SMarcel Moolenaar 	myPid = getpid();	/* remember this for vFork() */
14073955d011SMarcel Moolenaar 
14083955d011SMarcel Moolenaar 	/*
14093955d011SMarcel Moolenaar 	 * Just in case MAKEOBJDIR wants us to do something tricky.
14103955d011SMarcel Moolenaar 	 */
1411e2eeea75SSimon J. Gerraty 	Targ_Init();
1412e2eeea75SSimon J. Gerraty 	Var_Init();
1413*dba7b0efSSimon J. Gerraty 	Global_Set(".MAKE.OS", utsname.sysname);
1414*dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE", machine);
1415*dba7b0efSSimon J. Gerraty 	Global_Set("MACHINE_ARCH", machine_arch);
14163955d011SMarcel Moolenaar #ifdef MAKE_VERSION
1417*dba7b0efSSimon J. Gerraty 	Global_Set("MAKE_VERSION", MAKE_VERSION);
14183955d011SMarcel Moolenaar #endif
1419*dba7b0efSSimon J. Gerraty 	Global_Set(".newline", "\n"); /* handy for :@ loops */
14203955d011SMarcel Moolenaar 	/*
14213955d011SMarcel Moolenaar 	 * This is the traditional preference for makefiles.
14223955d011SMarcel Moolenaar 	 */
14233955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST
14243955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
14253955d011SMarcel Moolenaar #endif
1426*dba7b0efSSimon J. Gerraty 	Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST);
1427*dba7b0efSSimon J. Gerraty 	Global_Set(MAKE_DEPENDFILE, ".depend");
14283955d011SMarcel Moolenaar 
1429956e45f6SSimon J. Gerraty 	CmdOpts_Init();
14303955d011SMarcel Moolenaar 	allPrecious = FALSE;	/* Remove targets when interrupted */
143145447996SSimon J. Gerraty 	deleteOnError = FALSE;	/* Historical default behavior */
14323955d011SMarcel Moolenaar 	jobsRunning = FALSE;
14333955d011SMarcel Moolenaar 
1434956e45f6SSimon J. Gerraty 	maxJobTokens = opts.maxJobs;
14353955d011SMarcel Moolenaar 	ignorePWD = FALSE;
14363955d011SMarcel Moolenaar 
14373955d011SMarcel Moolenaar 	/*
14383955d011SMarcel Moolenaar 	 * Initialize the parsing, directory and variable modules to prepare
14393955d011SMarcel Moolenaar 	 * for the reading of inclusion paths and variable settings on the
14403955d011SMarcel Moolenaar 	 * command line
14413955d011SMarcel Moolenaar 	 */
14423955d011SMarcel Moolenaar 
14433955d011SMarcel Moolenaar 	/*
14443955d011SMarcel Moolenaar 	 * Initialize various variables.
14453955d011SMarcel Moolenaar 	 *	MAKE also gets this name, for compatibility
14463955d011SMarcel Moolenaar 	 *	.MAKEFLAGS gets set to the empty string just in case.
14473955d011SMarcel Moolenaar 	 *	MFLAGS also gets initialized empty, for compatibility.
14483955d011SMarcel Moolenaar 	 */
14493955d011SMarcel Moolenaar 	Parse_Init();
1450956e45f6SSimon J. Gerraty 	InitVarMake(argv[0]);
1451*dba7b0efSSimon J. Gerraty 	Global_Set(MAKEFLAGS, "");
1452*dba7b0efSSimon J. Gerraty 	Global_Set(MAKEOVERRIDES, "");
1453*dba7b0efSSimon J. Gerraty 	Global_Set("MFLAGS", "");
1454*dba7b0efSSimon J. Gerraty 	Global_Set(".ALLTARGETS", "");
145551ee2c1cSSimon J. Gerraty 	/* some makefiles need to know this */
1456*dba7b0efSSimon J. Gerraty 	Var_Set(SCOPE_CMDLINE, MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV);
14573955d011SMarcel Moolenaar 
1458e2eeea75SSimon J. Gerraty 	/* Set some other useful variables. */
14593955d011SMarcel Moolenaar 	{
1460e2eeea75SSimon J. Gerraty 		char tmp[64], *ep = getenv(MAKE_LEVEL_ENV);
14613955d011SMarcel Moolenaar 
1462e2eeea75SSimon J. Gerraty 		makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
146351ee2c1cSSimon J. Gerraty 		if (makelevel < 0)
146451ee2c1cSSimon J. Gerraty 			makelevel = 0;
1465e2eeea75SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%d", makelevel);
1466*dba7b0efSSimon J. Gerraty 		Global_Set(MAKE_LEVEL, tmp);
1467e2eeea75SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", myPid);
1468*dba7b0efSSimon J. Gerraty 		Global_Set(".MAKE.PID", tmp);
1469e2eeea75SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", getppid());
1470*dba7b0efSSimon J. Gerraty 		Global_Set(".MAKE.PPID", tmp);
147106b9b3e0SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", getuid());
1472*dba7b0efSSimon J. Gerraty 		Global_Set(".MAKE.UID", tmp);
147306b9b3e0SSimon J. Gerraty 		snprintf(tmp, sizeof tmp, "%u", getgid());
1474*dba7b0efSSimon J. Gerraty 		Global_Set(".MAKE.GID", tmp);
14753955d011SMarcel Moolenaar 	}
147651ee2c1cSSimon J. Gerraty 	if (makelevel > 0) {
147751ee2c1cSSimon J. Gerraty 		char pn[1024];
1478e2eeea75SSimon J. Gerraty 		snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
147951ee2c1cSSimon J. Gerraty 		progname = bmake_strdup(pn);
148051ee2c1cSSimon J. Gerraty 	}
14813955d011SMarcel Moolenaar 
14821748de26SSimon J. Gerraty #ifdef USE_META
14831748de26SSimon J. Gerraty 	meta_init();
14841748de26SSimon J. Gerraty #endif
14852c3632d1SSimon J. Gerraty 	Dir_Init();
14861ce939a7SSimon J. Gerraty 
14873955d011SMarcel Moolenaar 	/*
14883955d011SMarcel Moolenaar 	 * First snag any flags out of the MAKE environment variable.
14893955d011SMarcel Moolenaar 	 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
14903955d011SMarcel Moolenaar 	 * in a different format).
14913955d011SMarcel Moolenaar 	 */
14923955d011SMarcel Moolenaar #ifdef POSIX
1493956e45f6SSimon J. Gerraty 	{
1494956e45f6SSimon J. Gerraty 		char *p1 = explode(getenv("MAKEFLAGS"));
149551ee2c1cSSimon J. Gerraty 		Main_ParseArgLine(p1);
149651ee2c1cSSimon J. Gerraty 		free(p1);
1497956e45f6SSimon J. Gerraty 	}
14983955d011SMarcel Moolenaar #else
14993955d011SMarcel Moolenaar 	Main_ParseArgLine(getenv("MAKE"));
15003955d011SMarcel Moolenaar #endif
15013955d011SMarcel Moolenaar 
15023955d011SMarcel Moolenaar 	/*
15033955d011SMarcel Moolenaar 	 * Find where we are (now).
15043955d011SMarcel Moolenaar 	 * We take care of PWD for the automounter below...
15053955d011SMarcel Moolenaar 	 */
15063955d011SMarcel Moolenaar 	if (getcwd(curdir, MAXPATHLEN) == NULL) {
15073955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: getcwd: %s.\n",
15083955d011SMarcel Moolenaar 		    progname, strerror(errno));
15093955d011SMarcel Moolenaar 		exit(2);
15103955d011SMarcel Moolenaar 	}
15113955d011SMarcel Moolenaar 
15123955d011SMarcel Moolenaar 	MainParseArgs(argc, argv);
15133955d011SMarcel Moolenaar 
1514956e45f6SSimon J. Gerraty 	if (opts.enterFlag)
151551ee2c1cSSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, curdir);
151651ee2c1cSSimon J. Gerraty 
15173955d011SMarcel Moolenaar 	/*
15183955d011SMarcel Moolenaar 	 * Verify that cwd is sane.
15193955d011SMarcel Moolenaar 	 */
15203955d011SMarcel Moolenaar 	if (stat(curdir, &sa) == -1) {
15213955d011SMarcel Moolenaar 		(void)fprintf(stderr, "%s: %s: %s.\n",
15223955d011SMarcel Moolenaar 		    progname, curdir, strerror(errno));
15233955d011SMarcel Moolenaar 		exit(2);
15243955d011SMarcel Moolenaar 	}
15253955d011SMarcel Moolenaar 
15263955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE
1527956e45f6SSimon J. Gerraty 	HandlePWD(&sa);
15283955d011SMarcel Moolenaar #endif
1529*dba7b0efSSimon J. Gerraty 	Global_Set(".CURDIR", curdir);
15303955d011SMarcel Moolenaar 
1531956e45f6SSimon J. Gerraty 	InitObjdir(machine, machine_arch);
15323955d011SMarcel Moolenaar 
15333955d011SMarcel Moolenaar 	/*
15343955d011SMarcel Moolenaar 	 * Initialize archive, target and suffix modules in preparation for
15353955d011SMarcel Moolenaar 	 * parsing the makefile(s)
15363955d011SMarcel Moolenaar 	 */
15373955d011SMarcel Moolenaar 	Arch_Init();
15383955d011SMarcel Moolenaar 	Suff_Init();
15393955d011SMarcel Moolenaar 	Trace_Init(tracefile);
15403955d011SMarcel Moolenaar 
1541e2eeea75SSimon J. Gerraty 	defaultNode = NULL;
15423955d011SMarcel Moolenaar 	(void)time(&now);
15433955d011SMarcel Moolenaar 
15443955d011SMarcel Moolenaar 	Trace_Log(MAKESTART, NULL);
15453955d011SMarcel Moolenaar 
1546956e45f6SSimon J. Gerraty 	InitVarTargets();
15473955d011SMarcel Moolenaar 
1548956e45f6SSimon J. Gerraty 	InitDefSysIncPath(syspath);
1549e2eeea75SSimon J. Gerraty }
15503955d011SMarcel Moolenaar 
155106b9b3e0SSimon J. Gerraty /*
155206b9b3e0SSimon J. Gerraty  * Read the system makefile followed by either makefile, Makefile or the
155306b9b3e0SSimon J. Gerraty  * files given by the -f option. Exit on parse errors.
155406b9b3e0SSimon J. Gerraty  */
1555e2eeea75SSimon J. Gerraty static void
1556e2eeea75SSimon J. Gerraty main_ReadFiles(void)
1557e2eeea75SSimon J. Gerraty {
1558e2eeea75SSimon J. Gerraty 
1559956e45f6SSimon J. Gerraty 	if (!opts.noBuiltins)
1560956e45f6SSimon J. Gerraty 		ReadBuiltinRules();
15613955d011SMarcel Moolenaar 
156206b9b3e0SSimon J. Gerraty 	if (!Lst_IsEmpty(&opts.makefiles))
156306b9b3e0SSimon J. Gerraty 		ReadAllMakefiles(&opts.makefiles);
1564e2eeea75SSimon J. Gerraty 	else
1565e2eeea75SSimon J. Gerraty 		ReadFirstDefaultMakefile();
1566e2eeea75SSimon J. Gerraty }
1567e2eeea75SSimon J. Gerraty 
1568e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */
1569e2eeea75SSimon J. Gerraty static void
1570e2eeea75SSimon J. Gerraty main_PrepareMaking(void)
1571e2eeea75SSimon J. Gerraty {
15723955d011SMarcel Moolenaar 	/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1573e2eeea75SSimon J. Gerraty 	if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
157406b9b3e0SSimon J. Gerraty 		(void)Var_Subst("${.MAKE.DEPENDFILE}",
1575*dba7b0efSSimon J. Gerraty 		    SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile);
1576956e45f6SSimon J. Gerraty 		if (makeDependfile[0] != '\0') {
1577956e45f6SSimon J. Gerraty 			/* TODO: handle errors */
15783955d011SMarcel Moolenaar 			doing_depend = TRUE;
15792c3632d1SSimon J. Gerraty 			(void)ReadMakefile(makeDependfile);
15803955d011SMarcel Moolenaar 			doing_depend = FALSE;
15813955d011SMarcel Moolenaar 		}
1582956e45f6SSimon J. Gerraty 	}
15833955d011SMarcel Moolenaar 
15844c620fe5SSimon J. Gerraty 	if (enterFlagObj)
15854c620fe5SSimon J. Gerraty 		printf("%s: Entering directory `%s'\n", progname, objdir);
15864c620fe5SSimon J. Gerraty 
158706b9b3e0SSimon J. Gerraty 	MakeMode();
15883955d011SMarcel Moolenaar 
1589956e45f6SSimon J. Gerraty 	{
1590*dba7b0efSSimon J. Gerraty 		FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS);
1591*dba7b0efSSimon J. Gerraty 		Global_Append("MFLAGS", makeflags.str);
159206b9b3e0SSimon J. Gerraty 		FStr_Done(&makeflags);
1593956e45f6SSimon J. Gerraty 	}
1594e48f47ddSSimon J. Gerraty 
1595956e45f6SSimon J. Gerraty 	InitMaxJobs();
1596e48f47ddSSimon J. Gerraty 
1597e48f47ddSSimon J. Gerraty 	/*
1598e2eeea75SSimon J. Gerraty 	 * Be compatible if the user did not specify -j and did not explicitly
1599e2eeea75SSimon J. Gerraty 	 * turn compatibility on.
1600e48f47ddSSimon J. Gerraty 	 */
1601e2eeea75SSimon J. Gerraty 	if (!opts.compatMake && !forceJobs)
1602956e45f6SSimon J. Gerraty 		opts.compatMake = TRUE;
1603e48f47ddSSimon J. Gerraty 
1604956e45f6SSimon J. Gerraty 	if (!opts.compatMake)
16053955d011SMarcel Moolenaar 		Job_ServerStart(maxJobTokens, jp_0, jp_1);
1606956e45f6SSimon J. Gerraty 	DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1607956e45f6SSimon J. Gerraty 	    jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
16083955d011SMarcel Moolenaar 
1609e2eeea75SSimon J. Gerraty 	if (opts.printVars == PVM_NONE)
16103955d011SMarcel Moolenaar 		Main_ExportMAKEFLAGS(TRUE);	/* initial export */
16113955d011SMarcel Moolenaar 
1612956e45f6SSimon J. Gerraty 	InitVpath();
16133955d011SMarcel Moolenaar 
16143955d011SMarcel Moolenaar 	/*
16153955d011SMarcel Moolenaar 	 * Now that all search paths have been read for suffixes et al, it's
16163955d011SMarcel Moolenaar 	 * time to add the default search path to their lists...
16173955d011SMarcel Moolenaar 	 */
16183955d011SMarcel Moolenaar 	Suff_DoPaths();
16193955d011SMarcel Moolenaar 
16203955d011SMarcel Moolenaar 	/*
16213955d011SMarcel Moolenaar 	 * Propagate attributes through :: dependency lists.
16223955d011SMarcel Moolenaar 	 */
16233955d011SMarcel Moolenaar 	Targ_Propagate();
16243955d011SMarcel Moolenaar 
16253955d011SMarcel Moolenaar 	/* print the initial graph, if the user requested it */
16263955d011SMarcel Moolenaar 	if (DEBUG(GRAPH1))
16273955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
16283955d011SMarcel Moolenaar }
16293955d011SMarcel Moolenaar 
163006b9b3e0SSimon J. Gerraty /*
163106b9b3e0SSimon J. Gerraty  * Make the targets.
1632e2eeea75SSimon J. Gerraty  * If the -v or -V options are given, print variables instead.
163306b9b3e0SSimon J. Gerraty  * Return whether any of the targets is out-of-date.
163406b9b3e0SSimon J. Gerraty  */
1635e2eeea75SSimon J. Gerraty static Boolean
1636e2eeea75SSimon J. Gerraty main_Run(void)
1637e2eeea75SSimon J. Gerraty {
1638e2eeea75SSimon J. Gerraty 	if (opts.printVars != PVM_NONE) {
1639e2eeea75SSimon J. Gerraty 		/* print the values of any variables requested by the user */
1640e2eeea75SSimon J. Gerraty 		doPrintVars();
1641e2eeea75SSimon J. Gerraty 		return FALSE;
1642e2eeea75SSimon J. Gerraty 	} else {
1643e2eeea75SSimon J. Gerraty 		return runTargets();
1644e2eeea75SSimon J. Gerraty 	}
1645e2eeea75SSimon J. Gerraty }
16463955d011SMarcel Moolenaar 
1647e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */
1648e2eeea75SSimon J. Gerraty static void
1649e2eeea75SSimon J. Gerraty main_CleanUp(void)
1650e2eeea75SSimon J. Gerraty {
1651e2eeea75SSimon J. Gerraty #ifdef CLEANUP
165206b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.variables, free);
165306b9b3e0SSimon J. Gerraty 	/*
165406b9b3e0SSimon J. Gerraty 	 * Don't free the actual strings from opts.makefiles, they may be
165506b9b3e0SSimon J. Gerraty 	 * used in GNodes.
165606b9b3e0SSimon J. Gerraty 	 */
165706b9b3e0SSimon J. Gerraty 	Lst_Done(&opts.makefiles);
165806b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&opts.create, free);
1659e2eeea75SSimon J. Gerraty #endif
1660e2eeea75SSimon J. Gerraty 
1661e2eeea75SSimon J. Gerraty 	/* print the graph now it's been processed if the user requested it */
1662e2eeea75SSimon J. Gerraty 	if (DEBUG(GRAPH2))
1663e2eeea75SSimon J. Gerraty 		Targ_PrintGraph(2);
1664e2eeea75SSimon J. Gerraty 
1665e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEEND, NULL);
1666e2eeea75SSimon J. Gerraty 
1667e2eeea75SSimon J. Gerraty 	if (enterFlagObj)
1668e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, objdir);
1669e2eeea75SSimon J. Gerraty 	if (opts.enterFlag)
1670e2eeea75SSimon J. Gerraty 		printf("%s: Leaving directory `%s'\n", progname, curdir);
1671e2eeea75SSimon J. Gerraty 
1672e2eeea75SSimon J. Gerraty #ifdef USE_META
1673e2eeea75SSimon J. Gerraty 	meta_finish();
1674e2eeea75SSimon J. Gerraty #endif
1675e2eeea75SSimon J. Gerraty 	Suff_End();
1676e2eeea75SSimon J. Gerraty 	Targ_End();
1677e2eeea75SSimon J. Gerraty 	Arch_End();
1678e2eeea75SSimon J. Gerraty 	Var_End();
1679e2eeea75SSimon J. Gerraty 	Parse_End();
1680e2eeea75SSimon J. Gerraty 	Dir_End();
1681e2eeea75SSimon J. Gerraty 	Job_End();
1682e2eeea75SSimon J. Gerraty 	Trace_End();
1683e2eeea75SSimon J. Gerraty }
1684e2eeea75SSimon J. Gerraty 
1685e2eeea75SSimon J. Gerraty /* Determine the exit code. */
1686e2eeea75SSimon J. Gerraty static int
1687e2eeea75SSimon J. Gerraty main_Exit(Boolean outOfDate)
1688e2eeea75SSimon J. Gerraty {
168906b9b3e0SSimon J. Gerraty 	if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0))
1690956e45f6SSimon J. Gerraty 		return 2;	/* Not 1 so -q can distinguish error */
16913955d011SMarcel Moolenaar 	return outOfDate ? 1 : 0;
16923955d011SMarcel Moolenaar }
16933955d011SMarcel Moolenaar 
1694e2eeea75SSimon J. Gerraty int
1695e2eeea75SSimon J. Gerraty main(int argc, char **argv)
1696e2eeea75SSimon J. Gerraty {
1697e2eeea75SSimon J. Gerraty 	Boolean outOfDate;
1698e2eeea75SSimon J. Gerraty 
1699e2eeea75SSimon J. Gerraty 	main_Init(argc, argv);
1700e2eeea75SSimon J. Gerraty 	main_ReadFiles();
1701e2eeea75SSimon J. Gerraty 	main_PrepareMaking();
1702e2eeea75SSimon J. Gerraty 	outOfDate = main_Run();
1703e2eeea75SSimon J. Gerraty 	main_CleanUp();
1704e2eeea75SSimon J. Gerraty 	return main_Exit(outOfDate);
1705e2eeea75SSimon J. Gerraty }
1706e2eeea75SSimon J. Gerraty 
170706b9b3e0SSimon J. Gerraty /*
170806b9b3e0SSimon J. Gerraty  * Open and parse the given makefile, with all its side effects.
17093955d011SMarcel Moolenaar  *
17103955d011SMarcel Moolenaar  * Results:
17113955d011SMarcel Moolenaar  *	0 if ok. -1 if couldn't open file.
17123955d011SMarcel Moolenaar  */
17133955d011SMarcel Moolenaar static int
17142c3632d1SSimon J. Gerraty ReadMakefile(const char *fname)
17153955d011SMarcel Moolenaar {
17163955d011SMarcel Moolenaar 	int fd;
17172c3632d1SSimon J. Gerraty 	char *name, *path = NULL;
17183955d011SMarcel Moolenaar 
1719e2eeea75SSimon J. Gerraty 	if (strcmp(fname, "-") == 0) {
17203955d011SMarcel Moolenaar 		Parse_File(NULL /*stdin*/, -1);
1721*dba7b0efSSimon J. Gerraty 		Var_Set(SCOPE_INTERNAL, "MAKEFILE", "");
17223955d011SMarcel Moolenaar 	} else {
17233955d011SMarcel Moolenaar 		/* if we've chdir'd, rebuild the path name */
1724e2eeea75SSimon J. Gerraty 		if (strcmp(curdir, objdir) != 0 && *fname != '/') {
17252c3632d1SSimon J. Gerraty 			path = str_concat3(curdir, "/", fname);
17263955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
17273955d011SMarcel Moolenaar 			if (fd != -1) {
17283955d011SMarcel Moolenaar 				fname = path;
17293955d011SMarcel Moolenaar 				goto found;
17303955d011SMarcel Moolenaar 			}
17312c3632d1SSimon J. Gerraty 			free(path);
17323955d011SMarcel Moolenaar 
17333955d011SMarcel Moolenaar 			/* If curdir failed, try objdir (ala .depend) */
17342c3632d1SSimon J. Gerraty 			path = str_concat3(objdir, "/", fname);
17353955d011SMarcel Moolenaar 			fd = open(path, O_RDONLY);
17363955d011SMarcel Moolenaar 			if (fd != -1) {
17373955d011SMarcel Moolenaar 				fname = path;
17383955d011SMarcel Moolenaar 				goto found;
17393955d011SMarcel Moolenaar 			}
17403955d011SMarcel Moolenaar 		} else {
17413955d011SMarcel Moolenaar 			fd = open(fname, O_RDONLY);
17423955d011SMarcel Moolenaar 			if (fd != -1)
17433955d011SMarcel Moolenaar 				goto found;
17443955d011SMarcel Moolenaar 		}
17453955d011SMarcel Moolenaar 		/* look in -I and system include directories. */
17463955d011SMarcel Moolenaar 		name = Dir_FindFile(fname, parseIncPath);
1747e2eeea75SSimon J. Gerraty 		if (name == NULL) {
1748*dba7b0efSSimon J. Gerraty 			SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs)
1749956e45f6SSimon J. Gerraty 					     ? defSysIncPath : sysIncPath;
1750956e45f6SSimon J. Gerraty 			name = Dir_FindFile(fname, sysInc);
1751956e45f6SSimon J. Gerraty 		}
1752e2eeea75SSimon J. Gerraty 		if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
17533955d011SMarcel Moolenaar 			free(name);
17543955d011SMarcel Moolenaar 			free(path);
17553841c287SSimon J. Gerraty 			return -1;
17563955d011SMarcel Moolenaar 		}
17573955d011SMarcel Moolenaar 		fname = name;
17583955d011SMarcel Moolenaar 		/*
17593955d011SMarcel Moolenaar 		 * set the MAKEFILE variable desired by System V fans -- the
17603955d011SMarcel Moolenaar 		 * placement of the setting here means it gets set to the last
17613955d011SMarcel Moolenaar 		 * makefile specified, as it is set by SysV make.
17623955d011SMarcel Moolenaar 		 */
17633955d011SMarcel Moolenaar found:
17643955d011SMarcel Moolenaar 		if (!doing_depend)
1765*dba7b0efSSimon J. Gerraty 			Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname);
17663955d011SMarcel Moolenaar 		Parse_File(fname, fd);
17673955d011SMarcel Moolenaar 	}
17683955d011SMarcel Moolenaar 	free(path);
17693841c287SSimon J. Gerraty 	return 0;
17703955d011SMarcel Moolenaar }
17713955d011SMarcel Moolenaar 
1772*dba7b0efSSimon J. Gerraty /*
17733955d011SMarcel Moolenaar  * Cmd_Exec --
17743955d011SMarcel Moolenaar  *	Execute the command in cmd, and return the output of that command
17752c3632d1SSimon J. Gerraty  *	in a string.  In the output, newlines are replaced with spaces.
17763955d011SMarcel Moolenaar  *
17773955d011SMarcel Moolenaar  * Results:
17782c3632d1SSimon J. Gerraty  *	A string containing the output of the command, or the empty string.
17792c3632d1SSimon J. Gerraty  *	*errfmt returns a format string describing the command failure,
17802c3632d1SSimon J. Gerraty  *	if any, using a single %s conversion specification.
17813955d011SMarcel Moolenaar  *
17823955d011SMarcel Moolenaar  * Side Effects:
17833955d011SMarcel Moolenaar  *	The string must be freed by the caller.
17843955d011SMarcel Moolenaar  */
17853955d011SMarcel Moolenaar char *
17862c3632d1SSimon J. Gerraty Cmd_Exec(const char *cmd, const char **errfmt)
17873955d011SMarcel Moolenaar {
17883955d011SMarcel Moolenaar 	const char *args[4];	/* Args for invoking the shell */
178906b9b3e0SSimon J. Gerraty 	int pipefds[2];
17903955d011SMarcel Moolenaar 	int cpid;		/* Child PID */
17913955d011SMarcel Moolenaar 	int pid;		/* PID from wait() */
1792e2eeea75SSimon J. Gerraty 	int status;		/* command exit status */
17933955d011SMarcel Moolenaar 	Buffer buf;		/* buffer to store the result */
17942c3632d1SSimon J. Gerraty 	ssize_t bytes_read;
17952c3632d1SSimon J. Gerraty 	char *res;		/* result */
17962c3632d1SSimon J. Gerraty 	size_t res_len;
17973955d011SMarcel Moolenaar 	char *cp;
1798db29cad8SSimon J. Gerraty 	int savederr;		/* saved errno */
17993955d011SMarcel Moolenaar 
18002c3632d1SSimon J. Gerraty 	*errfmt = NULL;
18013955d011SMarcel Moolenaar 
180206b9b3e0SSimon J. Gerraty 	if (shellName == NULL)
18033955d011SMarcel Moolenaar 		Shell_Init();
18043955d011SMarcel Moolenaar 	/*
18053955d011SMarcel Moolenaar 	 * Set up arguments for shell
18063955d011SMarcel Moolenaar 	 */
18073955d011SMarcel Moolenaar 	args[0] = shellName;
18083955d011SMarcel Moolenaar 	args[1] = "-c";
18093955d011SMarcel Moolenaar 	args[2] = cmd;
18103955d011SMarcel Moolenaar 	args[3] = NULL;
18113955d011SMarcel Moolenaar 
18123955d011SMarcel Moolenaar 	/*
18133955d011SMarcel Moolenaar 	 * Open a pipe for fetching its output
18143955d011SMarcel Moolenaar 	 */
181506b9b3e0SSimon J. Gerraty 	if (pipe(pipefds) == -1) {
18162c3632d1SSimon J. Gerraty 		*errfmt = "Couldn't create pipe for \"%s\"";
18173955d011SMarcel Moolenaar 		goto bad;
18183955d011SMarcel Moolenaar 	}
18193955d011SMarcel Moolenaar 
182006b9b3e0SSimon J. Gerraty 	Var_ReexportVars();
182106b9b3e0SSimon J. Gerraty 
18223955d011SMarcel Moolenaar 	/*
18233955d011SMarcel Moolenaar 	 * Fork
18243955d011SMarcel Moolenaar 	 */
1825*dba7b0efSSimon J. Gerraty 	switch (cpid = vfork()) {
18263955d011SMarcel Moolenaar 	case 0:
182706b9b3e0SSimon J. Gerraty 		(void)close(pipefds[0]); /* Close input side of pipe */
18283955d011SMarcel Moolenaar 
18293955d011SMarcel Moolenaar 		/*
18303955d011SMarcel Moolenaar 		 * Duplicate the output stream to the shell's output, then
18313955d011SMarcel Moolenaar 		 * shut the extra thing down. Note we don't fetch the error
18323955d011SMarcel Moolenaar 		 * stream...why not? Why?
18333955d011SMarcel Moolenaar 		 */
183406b9b3e0SSimon J. Gerraty 		(void)dup2(pipefds[1], 1);
183506b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]);
18363955d011SMarcel Moolenaar 
18373955d011SMarcel Moolenaar 		(void)execv(shellPath, UNCONST(args));
18383955d011SMarcel Moolenaar 		_exit(1);
18393955d011SMarcel Moolenaar 		/*NOTREACHED*/
18403955d011SMarcel Moolenaar 
18413955d011SMarcel Moolenaar 	case -1:
18422c3632d1SSimon J. Gerraty 		*errfmt = "Couldn't exec \"%s\"";
18433955d011SMarcel Moolenaar 		goto bad;
18443955d011SMarcel Moolenaar 
18453955d011SMarcel Moolenaar 	default:
184606b9b3e0SSimon J. Gerraty 		(void)close(pipefds[1]); /* No need for the writing half */
18473955d011SMarcel Moolenaar 
1848db29cad8SSimon J. Gerraty 		savederr = 0;
1849e2eeea75SSimon J. Gerraty 		Buf_Init(&buf);
18503955d011SMarcel Moolenaar 
18513955d011SMarcel Moolenaar 		do {
18523955d011SMarcel Moolenaar 			char result[BUFSIZ];
185306b9b3e0SSimon J. Gerraty 			bytes_read = read(pipefds[0], result, sizeof result);
18542c3632d1SSimon J. Gerraty 			if (bytes_read > 0)
18552c3632d1SSimon J. Gerraty 				Buf_AddBytes(&buf, result, (size_t)bytes_read);
1856e2eeea75SSimon J. Gerraty 		} while (bytes_read > 0 ||
1857e2eeea75SSimon J. Gerraty 			 (bytes_read == -1 && errno == EINTR));
18582c3632d1SSimon J. Gerraty 		if (bytes_read == -1)
1859db29cad8SSimon J. Gerraty 			savederr = errno;
18603955d011SMarcel Moolenaar 
186106b9b3e0SSimon J. Gerraty 		(void)close(pipefds[0]); /* Close the input side of the pipe. */
18623955d011SMarcel Moolenaar 
1863e2eeea75SSimon J. Gerraty 		/* Wait for the process to exit. */
1864e2eeea75SSimon J. Gerraty 		while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
18653955d011SMarcel Moolenaar 			JobReapChild(pid, status, FALSE);
1866e2eeea75SSimon J. Gerraty 
1867*dba7b0efSSimon J. Gerraty 		res_len = buf.len;
1868*dba7b0efSSimon J. Gerraty 		res = Buf_DoneData(&buf);
18693955d011SMarcel Moolenaar 
1870db29cad8SSimon J. Gerraty 		if (savederr != 0)
18712c3632d1SSimon J. Gerraty 			*errfmt = "Couldn't read shell's output for \"%s\"";
18723955d011SMarcel Moolenaar 
18733955d011SMarcel Moolenaar 		if (WIFSIGNALED(status))
18742c3632d1SSimon J. Gerraty 			*errfmt = "\"%s\" exited on a signal";
18753955d011SMarcel Moolenaar 		else if (WEXITSTATUS(status) != 0)
18762c3632d1SSimon J. Gerraty 			*errfmt = "\"%s\" returned non-zero status";
18773955d011SMarcel Moolenaar 
18782c3632d1SSimon J. Gerraty 		/* Convert newlines to spaces.  A final newline is just stripped */
18792c3632d1SSimon J. Gerraty 		if (res_len > 0 && res[res_len - 1] == '\n')
18802c3632d1SSimon J. Gerraty 			res[res_len - 1] = '\0';
18812c3632d1SSimon J. Gerraty 		for (cp = res; *cp != '\0'; cp++)
18822c3632d1SSimon J. Gerraty 			if (*cp == '\n')
18833955d011SMarcel Moolenaar 				*cp = ' ';
18843955d011SMarcel Moolenaar 		break;
18853955d011SMarcel Moolenaar 	}
18863955d011SMarcel Moolenaar 	return res;
18873955d011SMarcel Moolenaar bad:
18882c3632d1SSimon J. Gerraty 	return bmake_strdup("");
18893955d011SMarcel Moolenaar }
18903955d011SMarcel Moolenaar 
189106b9b3e0SSimon J. Gerraty /*
189206b9b3e0SSimon J. Gerraty  * Print a printf-style error message.
18933955d011SMarcel Moolenaar  *
1894e2eeea75SSimon J. Gerraty  * In default mode, this error message has no consequences, in particular it
189506b9b3e0SSimon J. Gerraty  * does not affect the exit status.  Only in lint mode (-dL) it does.
189606b9b3e0SSimon J. Gerraty  */
18973955d011SMarcel Moolenaar void
18983955d011SMarcel Moolenaar Error(const char *fmt, ...)
18993955d011SMarcel Moolenaar {
19003955d011SMarcel Moolenaar 	va_list ap;
19013955d011SMarcel Moolenaar 	FILE *err_file;
19023955d011SMarcel Moolenaar 
1903956e45f6SSimon J. Gerraty 	err_file = opts.debug_file;
19043955d011SMarcel Moolenaar 	if (err_file == stdout)
19053955d011SMarcel Moolenaar 		err_file = stderr;
19063955d011SMarcel Moolenaar 	(void)fflush(stdout);
19073955d011SMarcel Moolenaar 	for (;;) {
19083955d011SMarcel Moolenaar 		va_start(ap, fmt);
19093955d011SMarcel Moolenaar 		fprintf(err_file, "%s: ", progname);
19103955d011SMarcel Moolenaar 		(void)vfprintf(err_file, fmt, ap);
19113955d011SMarcel Moolenaar 		va_end(ap);
19123955d011SMarcel Moolenaar 		(void)fprintf(err_file, "\n");
19133955d011SMarcel Moolenaar 		(void)fflush(err_file);
19143955d011SMarcel Moolenaar 		if (err_file == stderr)
19153955d011SMarcel Moolenaar 			break;
19163955d011SMarcel Moolenaar 		err_file = stderr;
19173955d011SMarcel Moolenaar 	}
191806b9b3e0SSimon J. Gerraty 	main_errors++;
19193955d011SMarcel Moolenaar }
19203955d011SMarcel Moolenaar 
192106b9b3e0SSimon J. Gerraty /*
192206b9b3e0SSimon J. Gerraty  * Wait for any running jobs to finish, then produce an error message,
1923e2eeea75SSimon J. Gerraty  * finally exit immediately.
19243955d011SMarcel Moolenaar  *
1925e2eeea75SSimon J. Gerraty  * Exiting immediately differs from Parse_Error, which exits only after the
192606b9b3e0SSimon J. Gerraty  * current top-level makefile has been parsed completely.
192706b9b3e0SSimon J. Gerraty  */
19283955d011SMarcel Moolenaar void
19293955d011SMarcel Moolenaar Fatal(const char *fmt, ...)
19303955d011SMarcel Moolenaar {
19313955d011SMarcel Moolenaar 	va_list ap;
19323955d011SMarcel Moolenaar 
19333955d011SMarcel Moolenaar 	if (jobsRunning)
19343955d011SMarcel Moolenaar 		Job_Wait();
19353955d011SMarcel Moolenaar 
19363955d011SMarcel Moolenaar 	(void)fflush(stdout);
1937e2eeea75SSimon J. Gerraty 	va_start(ap, fmt);
19383955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19393955d011SMarcel Moolenaar 	va_end(ap);
19403955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19413955d011SMarcel Moolenaar 	(void)fflush(stderr);
19423955d011SMarcel Moolenaar 
19433955d011SMarcel Moolenaar 	PrintOnError(NULL, NULL);
19443955d011SMarcel Moolenaar 
19453955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
19463955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1947e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
19483955d011SMarcel Moolenaar 	exit(2);		/* Not 1 so -q can distinguish error */
19493955d011SMarcel Moolenaar }
19503955d011SMarcel Moolenaar 
195106b9b3e0SSimon J. Gerraty /*
195206b9b3e0SSimon J. Gerraty  * Major exception once jobs are being created.
195306b9b3e0SSimon J. Gerraty  * Kills all jobs, prints a message and exits.
195406b9b3e0SSimon J. Gerraty  */
19553955d011SMarcel Moolenaar void
19563955d011SMarcel Moolenaar Punt(const char *fmt, ...)
19573955d011SMarcel Moolenaar {
19583955d011SMarcel Moolenaar 	va_list ap;
19593955d011SMarcel Moolenaar 
19603955d011SMarcel Moolenaar 	va_start(ap, fmt);
19613955d011SMarcel Moolenaar 	(void)fflush(stdout);
19623955d011SMarcel Moolenaar 	(void)fprintf(stderr, "%s: ", progname);
19633955d011SMarcel Moolenaar 	(void)vfprintf(stderr, fmt, ap);
19643955d011SMarcel Moolenaar 	va_end(ap);
19653955d011SMarcel Moolenaar 	(void)fprintf(stderr, "\n");
19663955d011SMarcel Moolenaar 	(void)fflush(stderr);
19673955d011SMarcel Moolenaar 
19683955d011SMarcel Moolenaar 	PrintOnError(NULL, NULL);
19693955d011SMarcel Moolenaar 
19703955d011SMarcel Moolenaar 	DieHorribly();
19713955d011SMarcel Moolenaar }
19723955d011SMarcel Moolenaar 
1973956e45f6SSimon J. Gerraty /* Exit without giving a message. */
19743955d011SMarcel Moolenaar void
19753955d011SMarcel Moolenaar DieHorribly(void)
19763955d011SMarcel Moolenaar {
19773955d011SMarcel Moolenaar 	if (jobsRunning)
19783955d011SMarcel Moolenaar 		Job_AbortAll();
19793955d011SMarcel Moolenaar 	if (DEBUG(GRAPH2))
19803955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
1981e2eeea75SSimon J. Gerraty 	Trace_Log(MAKEERROR, NULL);
198206b9b3e0SSimon J. Gerraty 	exit(2);		/* Not 1 so -q can distinguish error */
19833955d011SMarcel Moolenaar }
19843955d011SMarcel Moolenaar 
198506b9b3e0SSimon J. Gerraty /*
198606b9b3e0SSimon J. Gerraty  * Called when aborting due to errors in child shell to signal abnormal exit.
1987956e45f6SSimon J. Gerraty  * The program exits.
198806b9b3e0SSimon J. Gerraty  * Errors is the number of errors encountered in Make_Make.
198906b9b3e0SSimon J. Gerraty  */
19903955d011SMarcel Moolenaar void
1991956e45f6SSimon J. Gerraty Finish(int errs)
19923955d011SMarcel Moolenaar {
1993e2eeea75SSimon J. Gerraty 	if (shouldDieQuietly(NULL, -1))
19943841c287SSimon J. Gerraty 		exit(2);
1995956e45f6SSimon J. Gerraty 	Fatal("%d error%s", errs, errs == 1 ? "" : "s");
19963955d011SMarcel Moolenaar }
19973955d011SMarcel Moolenaar 
19983955d011SMarcel Moolenaar /*
19991748de26SSimon J. Gerraty  * eunlink --
20003955d011SMarcel Moolenaar  *	Remove a file carefully, avoiding directories.
20013955d011SMarcel Moolenaar  */
20023955d011SMarcel Moolenaar int
20033955d011SMarcel Moolenaar eunlink(const char *file)
20043955d011SMarcel Moolenaar {
20053955d011SMarcel Moolenaar 	struct stat st;
20063955d011SMarcel Moolenaar 
20073955d011SMarcel Moolenaar 	if (lstat(file, &st) == -1)
20083955d011SMarcel Moolenaar 		return -1;
20093955d011SMarcel Moolenaar 
20103955d011SMarcel Moolenaar 	if (S_ISDIR(st.st_mode)) {
20113955d011SMarcel Moolenaar 		errno = EISDIR;
20123955d011SMarcel Moolenaar 		return -1;
20133955d011SMarcel Moolenaar 	}
20143955d011SMarcel Moolenaar 	return unlink(file);
20153955d011SMarcel Moolenaar }
20163955d011SMarcel Moolenaar 
2017956e45f6SSimon J. Gerraty static void
2018956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n)
2019956e45f6SSimon J. Gerraty {
2020956e45f6SSimon J. Gerraty 	const char *mem = data;
2021956e45f6SSimon J. Gerraty 
2022956e45f6SSimon J. Gerraty 	while (n > 0) {
2023956e45f6SSimon J. Gerraty 		ssize_t written = write(fd, mem, n);
2024956e45f6SSimon J. Gerraty 		if (written == -1 && errno == EAGAIN)
2025956e45f6SSimon J. Gerraty 			continue;
2026956e45f6SSimon J. Gerraty 		if (written == -1)
2027956e45f6SSimon J. Gerraty 			break;
2028956e45f6SSimon J. Gerraty 		mem += written;
2029956e45f6SSimon J. Gerraty 		n -= (size_t)written;
2030956e45f6SSimon J. Gerraty 	}
2031956e45f6SSimon J. Gerraty }
2032956e45f6SSimon J. Gerraty 
20333955d011SMarcel Moolenaar /*
2034956e45f6SSimon J. Gerraty  * execDie --
20353955d011SMarcel Moolenaar  *	Print why exec failed, avoiding stdio.
20363955d011SMarcel Moolenaar  */
2037956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD
2038956e45f6SSimon J. Gerraty execDie(const char *af, const char *av)
20393955d011SMarcel Moolenaar {
2040956e45f6SSimon J. Gerraty 	Buffer buf;
20413955d011SMarcel Moolenaar 
2042e2eeea75SSimon J. Gerraty 	Buf_Init(&buf);
2043956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, progname);
2044956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ": ");
2045956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, af);
2046956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, "(");
2047956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, av);
2048956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ") failed (");
2049956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, strerror(errno));
2050956e45f6SSimon J. Gerraty 	Buf_AddStr(&buf, ")\n");
20513955d011SMarcel Moolenaar 
2052*dba7b0efSSimon J. Gerraty 	write_all(STDERR_FILENO, buf.data, buf.len);
2053956e45f6SSimon J. Gerraty 
2054*dba7b0efSSimon J. Gerraty 	Buf_Done(&buf);
2055956e45f6SSimon J. Gerraty 	_exit(1);
20563955d011SMarcel Moolenaar }
20573955d011SMarcel Moolenaar 
2058b46b9039SSimon J. Gerraty /* purge any relative paths */
2059e1cee40dSSimon J. Gerraty static void
2060e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void)
2061e1cee40dSSimon J. Gerraty {
2062956e45f6SSimon J. Gerraty 	HashEntry *he, *nhe;
2063956e45f6SSimon J. Gerraty 	HashIter hi;
2064b778b302SSimon J. Gerraty 
2065e2eeea75SSimon J. Gerraty 	HashIter_Init(&hi, &cached_realpaths);
2066956e45f6SSimon J. Gerraty 	he = HashIter_Next(&hi);
2067956e45f6SSimon J. Gerraty 	while (he != NULL) {
2068956e45f6SSimon J. Gerraty 		nhe = HashIter_Next(&hi);
2069956e45f6SSimon J. Gerraty 		if (he->key[0] != '/') {
2070e2eeea75SSimon J. Gerraty 			DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
2071e2eeea75SSimon J. Gerraty 			HashTable_DeleteEntry(&cached_realpaths, he);
2072e2eeea75SSimon J. Gerraty 			/* XXX: What about the allocated he->value? Either
2073e2eeea75SSimon J. Gerraty 			 * free them or document why they cannot be freed. */
2074b46b9039SSimon J. Gerraty 		}
2075b46b9039SSimon J. Gerraty 		he = nhe;
2076b46b9039SSimon J. Gerraty 	}
2077b46b9039SSimon J. Gerraty }
2078e1cee40dSSimon J. Gerraty 
2079e1cee40dSSimon J. Gerraty char *
2080e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved)
2081e1cee40dSSimon J. Gerraty {
20822c3632d1SSimon J. Gerraty 	const char *rp;
2083e1cee40dSSimon J. Gerraty 
2084e2eeea75SSimon J. Gerraty 	if (pathname == NULL || pathname[0] == '\0')
2085e1cee40dSSimon J. Gerraty 		return NULL;
2086e1cee40dSSimon J. Gerraty 
2087e2eeea75SSimon J. Gerraty 	rp = HashTable_FindValue(&cached_realpaths, pathname);
2088e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2089b778b302SSimon J. Gerraty 		/* a hit */
2090e2eeea75SSimon J. Gerraty 		strncpy(resolved, rp, MAXPATHLEN);
2091e2eeea75SSimon J. Gerraty 		resolved[MAXPATHLEN - 1] = '\0';
2092e2eeea75SSimon J. Gerraty 		return resolved;
2093e2eeea75SSimon J. Gerraty 	}
20943841c287SSimon J. Gerraty 
2095e2eeea75SSimon J. Gerraty 	rp = realpath(pathname, resolved);
2096e2eeea75SSimon J. Gerraty 	if (rp != NULL) {
2097e2eeea75SSimon J. Gerraty 		HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
2098e2eeea75SSimon J. Gerraty 		DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
2099e2eeea75SSimon J. Gerraty 		return resolved;
2100e2eeea75SSimon J. Gerraty 	}
2101e2eeea75SSimon J. Gerraty 
2102e2eeea75SSimon J. Gerraty 	/* should we negative-cache? */
2103e2eeea75SSimon J. Gerraty 	return NULL;
2104b778b302SSimon J. Gerraty }
2105b778b302SSimon J. Gerraty 
21063841c287SSimon J. Gerraty /*
21073841c287SSimon J. Gerraty  * Return true if we should die without noise.
2108e2eeea75SSimon J. Gerraty  * For example our failing child was a sub-make or failure happened elsewhere.
21093841c287SSimon J. Gerraty  */
2110e2eeea75SSimon J. Gerraty Boolean
2111e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf)
21123841c287SSimon J. Gerraty {
21133841c287SSimon J. Gerraty 	static int quietly = -1;
21143841c287SSimon J. Gerraty 
21153841c287SSimon J. Gerraty 	if (quietly < 0) {
2116e2eeea75SSimon J. Gerraty 		if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE))
21173841c287SSimon J. Gerraty 			quietly = 0;
21183841c287SSimon J. Gerraty 		else if (bf >= 0)
21193841c287SSimon J. Gerraty 			quietly = bf;
21203841c287SSimon J. Gerraty 		else
212106b9b3e0SSimon J. Gerraty 			quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
21223841c287SSimon J. Gerraty 	}
2123*dba7b0efSSimon J. Gerraty 	return quietly != 0;
21243841c287SSimon J. Gerraty }
21253841c287SSimon J. Gerraty 
2126956e45f6SSimon J. Gerraty static void
2127956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn)
2128956e45f6SSimon J. Gerraty {
2129956e45f6SSimon J. Gerraty 	StringListNode *ln;
2130956e45f6SSimon J. Gerraty 
2131956e45f6SSimon J. Gerraty 	/*
2132956e45f6SSimon J. Gerraty 	 * We can print this even if there is no .ERROR target.
2133956e45f6SSimon J. Gerraty 	 */
2134*dba7b0efSSimon J. Gerraty 	Global_Set(".ERROR_TARGET", gn->name);
2135*dba7b0efSSimon J. Gerraty 	Global_Delete(".ERROR_CMD");
2136956e45f6SSimon J. Gerraty 
213706b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
2138956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
2139956e45f6SSimon J. Gerraty 
2140956e45f6SSimon J. Gerraty 		if (cmd == NULL)
2141956e45f6SSimon J. Gerraty 			break;
2142*dba7b0efSSimon J. Gerraty 		Global_Append(".ERROR_CMD", cmd);
2143956e45f6SSimon J. Gerraty 	}
2144956e45f6SSimon J. Gerraty }
2145956e45f6SSimon J. Gerraty 
214606b9b3e0SSimon J. Gerraty /*
214706b9b3e0SSimon J. Gerraty  * Print some helpful information in case of an error.
214806b9b3e0SSimon J. Gerraty  * The caller should exit soon after calling this function.
214906b9b3e0SSimon J. Gerraty  */
21503955d011SMarcel Moolenaar void
2151e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg)
21523955d011SMarcel Moolenaar {
2153e2eeea75SSimon J. Gerraty 	static GNode *errorNode = NULL;
21543955d011SMarcel Moolenaar 
21552c3632d1SSimon J. Gerraty 	if (DEBUG(HASH)) {
21562c3632d1SSimon J. Gerraty 		Targ_Stats();
21572c3632d1SSimon J. Gerraty 		Var_Stats();
21582c3632d1SSimon J. Gerraty 	}
21592c3632d1SSimon J. Gerraty 
216006b9b3e0SSimon J. Gerraty 	if (errorNode != NULL)
216106b9b3e0SSimon J. Gerraty 		return;		/* we've been here! */
21623841c287SSimon J. Gerraty 
2163e2eeea75SSimon J. Gerraty 	if (msg != NULL)
2164e2eeea75SSimon J. Gerraty 		printf("%s", msg);
21653955d011SMarcel Moolenaar 	printf("\n%s: stopped in %s\n", progname, curdir);
21663955d011SMarcel Moolenaar 
216706b9b3e0SSimon J. Gerraty 	/* we generally want to keep quiet if a sub-make died */
216806b9b3e0SSimon J. Gerraty 	if (shouldDieQuietly(gn, -1))
216906b9b3e0SSimon J. Gerraty 		return;
2170e2eeea75SSimon J. Gerraty 
2171e2eeea75SSimon J. Gerraty 	if (gn != NULL)
2172956e45f6SSimon J. Gerraty 		SetErrorVars(gn);
2173e2eeea75SSimon J. Gerraty 
2174e2eeea75SSimon J. Gerraty 	{
2175e2eeea75SSimon J. Gerraty 		char *errorVarsValues;
2176e2eeea75SSimon J. Gerraty 		(void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
2177*dba7b0efSSimon J. Gerraty 				SCOPE_GLOBAL, VARE_WANTRES, &errorVarsValues);
2178956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
2179e2eeea75SSimon J. Gerraty 		printf("%s", errorVarsValues);
2180e2eeea75SSimon J. Gerraty 		free(errorVarsValues);
2181e2eeea75SSimon J. Gerraty 	}
2182e2eeea75SSimon J. Gerraty 
2183ac3446e9SSimon J. Gerraty 	fflush(stdout);
2184ac3446e9SSimon J. Gerraty 
21853955d011SMarcel Moolenaar 	/*
21863955d011SMarcel Moolenaar 	 * Finally, see if there is a .ERROR target, and run it if so.
21873955d011SMarcel Moolenaar 	 */
2188e2eeea75SSimon J. Gerraty 	errorNode = Targ_FindNode(".ERROR");
2189e2eeea75SSimon J. Gerraty 	if (errorNode != NULL) {
2190e2eeea75SSimon J. Gerraty 		errorNode->type |= OP_SPECIAL;
2191e2eeea75SSimon J. Gerraty 		Compat_Make(errorNode, errorNode);
21923955d011SMarcel Moolenaar 	}
21933955d011SMarcel Moolenaar }
21943955d011SMarcel Moolenaar 
21953955d011SMarcel Moolenaar void
21963955d011SMarcel Moolenaar Main_ExportMAKEFLAGS(Boolean first)
21973955d011SMarcel Moolenaar {
21982c3632d1SSimon J. Gerraty 	static Boolean once = TRUE;
21992c3632d1SSimon J. Gerraty 	const char *expr;
22003955d011SMarcel Moolenaar 	char *s;
22013955d011SMarcel Moolenaar 
22023955d011SMarcel Moolenaar 	if (once != first)
22033955d011SMarcel Moolenaar 		return;
22042c3632d1SSimon J. Gerraty 	once = FALSE;
22053955d011SMarcel Moolenaar 
22062c3632d1SSimon J. Gerraty 	expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
2207*dba7b0efSSimon J. Gerraty 	(void)Var_Subst(expr, SCOPE_CMDLINE, VARE_WANTRES, &s);
2208956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
22092c3632d1SSimon J. Gerraty 	if (s[0] != '\0') {
22103955d011SMarcel Moolenaar #ifdef POSIX
22113955d011SMarcel Moolenaar 		setenv("MAKEFLAGS", s, 1);
22123955d011SMarcel Moolenaar #else
22133955d011SMarcel Moolenaar 		setenv("MAKE", s, 1);
22143955d011SMarcel Moolenaar #endif
22153955d011SMarcel Moolenaar 	}
22163955d011SMarcel Moolenaar }
22173955d011SMarcel Moolenaar 
22183955d011SMarcel Moolenaar char *
22193955d011SMarcel Moolenaar getTmpdir(void)
22203955d011SMarcel Moolenaar {
22213955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
22223955d011SMarcel Moolenaar 	struct stat st;
22233955d011SMarcel Moolenaar 
2224e2eeea75SSimon J. Gerraty 	if (tmpdir != NULL)
2225e2eeea75SSimon J. Gerraty 		return tmpdir;
2226e2eeea75SSimon J. Gerraty 
2227e2eeea75SSimon J. Gerraty 	/* Honor $TMPDIR but only if it is valid. Ensure it ends with '/'. */
2228e2eeea75SSimon J. Gerraty 	(void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/",
2229*dba7b0efSSimon J. Gerraty 	    SCOPE_GLOBAL, VARE_WANTRES, &tmpdir);
2230956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
2231e2eeea75SSimon J. Gerraty 
22323955d011SMarcel Moolenaar 	if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
22333955d011SMarcel Moolenaar 		free(tmpdir);
22343955d011SMarcel Moolenaar 		tmpdir = bmake_strdup(_PATH_TMP);
22353955d011SMarcel Moolenaar 	}
22363955d011SMarcel Moolenaar 	return tmpdir;
22373955d011SMarcel Moolenaar }
22383955d011SMarcel Moolenaar 
22393955d011SMarcel Moolenaar /*
22403955d011SMarcel Moolenaar  * Create and open a temp file using "pattern".
2241956e45f6SSimon J. Gerraty  * If out_fname is provided, set it to a copy of the filename created.
22423955d011SMarcel Moolenaar  * Otherwise unlink the file once open.
22433955d011SMarcel Moolenaar  */
22443955d011SMarcel Moolenaar int
2245*dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz)
22463955d011SMarcel Moolenaar {
22473955d011SMarcel Moolenaar 	static char *tmpdir = NULL;
2248*dba7b0efSSimon J. Gerraty 	char tbuf[MAXPATHLEN];
22493955d011SMarcel Moolenaar 	int fd;
22503955d011SMarcel Moolenaar 
2251e2eeea75SSimon J. Gerraty 	if (pattern == NULL)
22523955d011SMarcel Moolenaar 		pattern = TMPPAT;
2253956e45f6SSimon J. Gerraty 	if (tmpdir == NULL)
22543955d011SMarcel Moolenaar 		tmpdir = getTmpdir();
2255*dba7b0efSSimon J. Gerraty 	if (tfile == NULL) {
2256*dba7b0efSSimon J. Gerraty 	    tfile = tbuf;
2257*dba7b0efSSimon J. Gerraty 	    tfile_sz = sizeof tbuf;
2258*dba7b0efSSimon J. Gerraty 	}
22593955d011SMarcel Moolenaar 	if (pattern[0] == '/') {
2260*dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s", pattern);
22613955d011SMarcel Moolenaar 	} else {
2262*dba7b0efSSimon J. Gerraty 		snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern);
22633955d011SMarcel Moolenaar 	}
22643955d011SMarcel Moolenaar 	if ((fd = mkstemp(tfile)) < 0)
2265e2eeea75SSimon J. Gerraty 		Punt("Could not create temporary file %s: %s", tfile,
2266e2eeea75SSimon J. Gerraty 		    strerror(errno));
2267*dba7b0efSSimon J. Gerraty 	if (tfile == tbuf) {
226806b9b3e0SSimon J. Gerraty 		unlink(tfile);	/* we just want the descriptor */
22693955d011SMarcel Moolenaar 	}
22703955d011SMarcel Moolenaar 	return fd;
22713955d011SMarcel Moolenaar }
22723955d011SMarcel Moolenaar 
2273be19d90bSSimon J. Gerraty /*
2274e2eeea75SSimon J. Gerraty  * Convert a string representation of a boolean into a boolean value.
2275e2eeea75SSimon J. Gerraty  * Anything that looks like "No", "False", "Off", "0" etc. is FALSE,
2276e2eeea75SSimon J. Gerraty  * the empty string is the fallback, everything else is TRUE.
2277be19d90bSSimon J. Gerraty  */
2278be19d90bSSimon J. Gerraty Boolean
2279e2eeea75SSimon J. Gerraty ParseBoolean(const char *s, Boolean fallback)
2280be19d90bSSimon J. Gerraty {
2281e2eeea75SSimon J. Gerraty 	char ch = ch_tolower(s[0]);
2282e2eeea75SSimon J. Gerraty 	if (ch == '\0')
2283e2eeea75SSimon J. Gerraty 		return fallback;
2284e2eeea75SSimon J. Gerraty 	if (ch == '0' || ch == 'f' || ch == 'n')
2285956e45f6SSimon J. Gerraty 		return FALSE;
2286e2eeea75SSimon J. Gerraty 	if (ch == 'o')
2287e2eeea75SSimon J. Gerraty 		return ch_tolower(s[1]) != 'f';
2288956e45f6SSimon J. Gerraty 	return TRUE;
2289be19d90bSSimon J. Gerraty }
2290