main.c revision 17193
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
371590Srgrimes */
381590Srgrimes
391590Srgrimes#ifndef lint
401590Srgrimesstatic char copyright[] =
411590Srgrimes"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\
421590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
431590Srgrimes#endif /* not lint */
441590Srgrimes
451590Srgrimes#ifndef lint
461590Srgrimesstatic char sccsid[] = "@(#)main.c	8.3 (Berkeley) 3/19/94";
471590Srgrimes#endif /* not lint */
481590Srgrimes
491590Srgrimes/*-
501590Srgrimes * main.c --
511590Srgrimes *	The main file for this entire program. Exit routines etc
521590Srgrimes *	reside here.
531590Srgrimes *
541590Srgrimes * Utility functions defined in this file:
551590Srgrimes *	Main_ParseArgLine	Takes a line of arguments, breaks them and
561590Srgrimes *				treats them as if they were given when first
571590Srgrimes *				invoked. Used by the parse module to implement
581590Srgrimes *				the .MFLAGS target.
591590Srgrimes *
601590Srgrimes *	Error			Print a tagged error message. The global
611590Srgrimes *				MAKE variable must have been defined. This
621590Srgrimes *				takes a format string and two optional
631590Srgrimes *				arguments for it.
641590Srgrimes *
651590Srgrimes *	Fatal			Print an error message and exit. Also takes
661590Srgrimes *				a format string and two arguments.
671590Srgrimes *
681590Srgrimes *	Punt			Aborts all jobs and exits with a message. Also
691590Srgrimes *				takes a format string and two arguments.
701590Srgrimes *
711590Srgrimes *	Finish			Finish things up by printing the number of
721590Srgrimes *				errors which occured, as passed to it, and
731590Srgrimes *				exiting.
741590Srgrimes */
751590Srgrimes
761590Srgrimes#include <sys/types.h>
771590Srgrimes#include <sys/time.h>
781590Srgrimes#include <sys/param.h>
791590Srgrimes#include <sys/resource.h>
801590Srgrimes#include <sys/signal.h>
811590Srgrimes#include <sys/stat.h>
825814Sjkh#include <sys/utsname.h>
831590Srgrimes#include <errno.h>
841590Srgrimes#include <fcntl.h>
851590Srgrimes#include <stdio.h>
861590Srgrimes#if __STDC__
871590Srgrimes#include <stdarg.h>
881590Srgrimes#else
891590Srgrimes#include <varargs.h>
901590Srgrimes#endif
911590Srgrimes#include "make.h"
921590Srgrimes#include "hash.h"
931590Srgrimes#include "dir.h"
941590Srgrimes#include "job.h"
951590Srgrimes#include "pathnames.h"
961590Srgrimes
971590Srgrimes#ifndef	DEFMAXLOCAL
981590Srgrimes#define	DEFMAXLOCAL DEFMAXJOBS
991590Srgrimes#endif	DEFMAXLOCAL
1001590Srgrimes
1011590Srgrimes#define	MAKEFLAGS	".MAKEFLAGS"
1021590Srgrimes
1031590SrgrimesLst			create;		/* Targets to be made */
1041590Srgrimestime_t			now;		/* Time at start of make */
1051590SrgrimesGNode			*DEFAULT;	/* .DEFAULT node */
1061590SrgrimesBoolean			allPrecious;	/* .PRECIOUS given on line by itself */
1071590Srgrimes
1081590Srgrimesstatic Boolean		noBuiltins;	/* -r flag */
1091590Srgrimesstatic Lst		makefiles;	/* ordered list of makefiles to read */
11017193Sbdestatic Boolean		printVars;	/* print value of one or more vars */
11117193Sbdestatic Lst		variables;	/* list of variables to print */
1121590Srgrimesint			maxJobs;	/* -J argument */
1131590Srgrimesstatic int		maxLocal;	/* -L argument */
1141590SrgrimesBoolean			compatMake;	/* -B argument */
1151590SrgrimesBoolean			debug;		/* -d flag */
1161590SrgrimesBoolean			noExecute;	/* -n flag */
1171590SrgrimesBoolean			keepgoing;	/* -k flag */
1181590SrgrimesBoolean			queryFlag;	/* -q flag */
1191590SrgrimesBoolean			touchFlag;	/* -t flag */
1201590SrgrimesBoolean			usePipes;	/* !-P flag */
1211590SrgrimesBoolean			ignoreErrors;	/* -i flag */
1221590SrgrimesBoolean			beSilent;	/* -s flag */
1231590SrgrimesBoolean			oldVars;	/* variable substitution style */
1241590SrgrimesBoolean			checkEnvFirst;	/* -e flag */
1251590Srgrimesstatic Boolean		jobsRunning;	/* TRUE if the jobs might be running */
1261590Srgrimes
1271590Srgrimesstatic Boolean		ReadMakefile();
1281590Srgrimesstatic void		usage();
1291590Srgrimes
1301590Srgrimesstatic char *curdir;			/* startup directory */
1311590Srgrimesstatic char *objdir;			/* where we chdir'ed to */
1321590Srgrimes
1331590Srgrimes/*-
1341590Srgrimes * MainParseArgs --
1351590Srgrimes *	Parse a given argument vector. Called from main() and from
1361590Srgrimes *	Main_ParseArgLine() when the .MAKEFLAGS target is used.
1371590Srgrimes *
1381590Srgrimes *	XXX: Deal with command line overriding .MAKEFLAGS in makefile
1391590Srgrimes *
1401590Srgrimes * Results:
1411590Srgrimes *	None
1421590Srgrimes *
1431590Srgrimes * Side Effects:
1441590Srgrimes *	Various global and local flags will be set depending on the flags
1451590Srgrimes *	given
1461590Srgrimes */
1471590Srgrimesstatic void
1481590SrgrimesMainParseArgs(argc, argv)
1491590Srgrimes	int argc;
1501590Srgrimes	char **argv;
1511590Srgrimes{
1521590Srgrimes	extern int optind;
1531590Srgrimes	extern char *optarg;
1545814Sjkh	int c;
1551590Srgrimes
1561590Srgrimes	optind = 1;	/* since we're called more than once */
1571590Srgrimes#ifdef notyet
15817193Sbde# define OPTFLAGS "BD:I:L:PSVd:ef:ij:knqrst"
1591590Srgrimes#else
16017193Sbde# define OPTFLAGS "D:I:V:d:ef:ij:knqrst"
1611590Srgrimes#endif
1625814Sjkhrearg:	while((c = getopt(argc, argv, OPTFLAGS)) != EOF) {
1631590Srgrimes		switch(c) {
1641590Srgrimes		case 'D':
1651590Srgrimes			Var_Set(optarg, "1", VAR_GLOBAL);
1661590Srgrimes			Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
1671590Srgrimes			Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
1681590Srgrimes			break;
1691590Srgrimes		case 'I':
1701590Srgrimes			Parse_AddIncludeDir(optarg);
1711590Srgrimes			Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
1721590Srgrimes			Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
1731590Srgrimes			break;
17417193Sbde		case 'V':
17517193Sbde			printVars = TRUE;
17617193Sbde			(void)Lst_AtEnd(variables, (ClientData)optarg);
17717193Sbde			Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
17817193Sbde			Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
17917193Sbde			break;
1801590Srgrimes#ifdef notyet
1811590Srgrimes		case 'B':
1821590Srgrimes			compatMake = TRUE;
1831590Srgrimes			break;
1841590Srgrimes		case 'L':
1851590Srgrimes			maxLocal = atoi(optarg);
1861590Srgrimes			Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL);
1871590Srgrimes			Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
1881590Srgrimes			break;
1891590Srgrimes		case 'P':
1901590Srgrimes			usePipes = FALSE;
1911590Srgrimes			Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL);
1921590Srgrimes			break;
1931590Srgrimes		case 'S':
1941590Srgrimes			keepgoing = FALSE;
1951590Srgrimes			Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
1961590Srgrimes			break;
1971590Srgrimes#endif
1981590Srgrimes		case 'd': {
1991590Srgrimes			char *modules = optarg;
2001590Srgrimes
2011590Srgrimes			for (; *modules; ++modules)
2021590Srgrimes				switch (*modules) {
2031590Srgrimes				case 'A':
2041590Srgrimes					debug = ~0;
2051590Srgrimes					break;
2061590Srgrimes				case 'a':
2071590Srgrimes					debug |= DEBUG_ARCH;
2081590Srgrimes					break;
2091590Srgrimes				case 'c':
2101590Srgrimes					debug |= DEBUG_COND;
2111590Srgrimes					break;
2121590Srgrimes				case 'd':
2131590Srgrimes					debug |= DEBUG_DIR;
2141590Srgrimes					break;
2151590Srgrimes				case 'f':
2161590Srgrimes					debug |= DEBUG_FOR;
2171590Srgrimes					break;
2181590Srgrimes				case 'g':
2191590Srgrimes					if (modules[1] == '1') {
2201590Srgrimes						debug |= DEBUG_GRAPH1;
2211590Srgrimes						++modules;
2221590Srgrimes					}
2231590Srgrimes					else if (modules[1] == '2') {
2241590Srgrimes						debug |= DEBUG_GRAPH2;
2251590Srgrimes						++modules;
2261590Srgrimes					}
2271590Srgrimes					break;
2281590Srgrimes				case 'j':
2291590Srgrimes					debug |= DEBUG_JOB;
2301590Srgrimes					break;
2311590Srgrimes				case 'm':
2321590Srgrimes					debug |= DEBUG_MAKE;
2331590Srgrimes					break;
2341590Srgrimes				case 's':
2351590Srgrimes					debug |= DEBUG_SUFF;
2361590Srgrimes					break;
2371590Srgrimes				case 't':
2381590Srgrimes					debug |= DEBUG_TARG;
2391590Srgrimes					break;
2401590Srgrimes				case 'v':
2411590Srgrimes					debug |= DEBUG_VAR;
2421590Srgrimes					break;
2431590Srgrimes				default:
2441590Srgrimes					(void)fprintf(stderr,
2451590Srgrimes				"make: illegal argument to d option -- %c\n",
2461590Srgrimes					    *modules);
2471590Srgrimes					usage();
2481590Srgrimes				}
2491590Srgrimes			Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
2501590Srgrimes			Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
2511590Srgrimes			break;
2521590Srgrimes		}
2531590Srgrimes		case 'e':
2541590Srgrimes			checkEnvFirst = TRUE;
2551590Srgrimes			Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
2561590Srgrimes			break;
2571590Srgrimes		case 'f':
2581590Srgrimes			(void)Lst_AtEnd(makefiles, (ClientData)optarg);
2591590Srgrimes			break;
2601590Srgrimes		case 'i':
2611590Srgrimes			ignoreErrors = TRUE;
2621590Srgrimes			Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
2631590Srgrimes			break;
2641590Srgrimes		case 'j':
2651590Srgrimes			maxJobs = atoi(optarg);
2661590Srgrimes			Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
2671590Srgrimes			Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
2681590Srgrimes			break;
2691590Srgrimes		case 'k':
2701590Srgrimes			keepgoing = TRUE;
2711590Srgrimes			Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
2721590Srgrimes			break;
2731590Srgrimes		case 'n':
2741590Srgrimes			noExecute = TRUE;
2751590Srgrimes			Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
2761590Srgrimes			break;
2771590Srgrimes		case 'q':
2781590Srgrimes			queryFlag = TRUE;
2791590Srgrimes			/* Kind of nonsensical, wot? */
2801590Srgrimes			Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
2811590Srgrimes			break;
2821590Srgrimes		case 'r':
2831590Srgrimes			noBuiltins = TRUE;
2841590Srgrimes			Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
2851590Srgrimes			break;
2861590Srgrimes		case 's':
2871590Srgrimes			beSilent = TRUE;
2881590Srgrimes			Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
2891590Srgrimes			break;
2901590Srgrimes		case 't':
2911590Srgrimes			touchFlag = TRUE;
2921590Srgrimes			Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
2931590Srgrimes			break;
2941590Srgrimes		default:
2951590Srgrimes		case '?':
2961590Srgrimes			usage();
2971590Srgrimes		}
2981590Srgrimes	}
2991590Srgrimes
3001590Srgrimes	oldVars = TRUE;
3011590Srgrimes
3021590Srgrimes	/*
3031590Srgrimes	 * See if the rest of the arguments are variable assignments and
3041590Srgrimes	 * perform them if so. Else take them to be targets and stuff them
3051590Srgrimes	 * on the end of the "create" list.
3061590Srgrimes	 */
3071590Srgrimes	for (argv += optind, argc -= optind; *argv; ++argv, --argc)
3081590Srgrimes		if (Parse_IsVar(*argv))
3091590Srgrimes			Parse_DoVar(*argv, VAR_CMD);
3101590Srgrimes		else {
3111590Srgrimes			if (!**argv)
3121590Srgrimes				Punt("illegal (null) argument.");
3131590Srgrimes			if (**argv == '-') {
3141590Srgrimes				if ((*argv)[1])
3151590Srgrimes					optind = 0;     /* -flag... */
3161590Srgrimes				else
3171590Srgrimes					optind = 1;     /* - */
3181590Srgrimes				goto rearg;
3191590Srgrimes			}
3205814Sjkh			(void)Lst_AtEnd(create, (ClientData)strdup(*argv));
3211590Srgrimes		}
3221590Srgrimes}
3231590Srgrimes
3241590Srgrimes/*-
3251590Srgrimes * Main_ParseArgLine --
3261590Srgrimes *  	Used by the parse module when a .MFLAGS or .MAKEFLAGS target
3271590Srgrimes *	is encountered and by main() when reading the .MAKEFLAGS envariable.
3281590Srgrimes *	Takes a line of arguments and breaks it into its
3291590Srgrimes * 	component words and passes those words and the number of them to the
3301590Srgrimes *	MainParseArgs function.
3311590Srgrimes *	The line should have all its leading whitespace removed.
3321590Srgrimes *
3331590Srgrimes * Results:
3341590Srgrimes *	None
3351590Srgrimes *
3361590Srgrimes * Side Effects:
3371590Srgrimes *	Only those that come from the various arguments.
3381590Srgrimes */
3391590Srgrimesvoid
3401590SrgrimesMain_ParseArgLine(line)
3411590Srgrimes	char *line;			/* Line to fracture */
3421590Srgrimes{
3431590Srgrimes	char **argv;			/* Manufactured argument vector */
3441590Srgrimes	int argc;			/* Number of arguments in argv */
3451590Srgrimes
3461590Srgrimes	if (line == NULL)
3471590Srgrimes		return;
3481590Srgrimes	for (; *line == ' '; ++line)
3491590Srgrimes		continue;
3501590Srgrimes	if (!*line)
3511590Srgrimes		return;
3521590Srgrimes
3535814Sjkh	argv = brk_string(line, &argc, TRUE);
3541590Srgrimes	MainParseArgs(argc, argv);
3551590Srgrimes}
3561590Srgrimes
3571590Srgrimes/*-
3581590Srgrimes * main --
3591590Srgrimes *	The main function, for obvious reasons. Initializes variables
3601590Srgrimes *	and a few modules, then parses the arguments give it in the
3611590Srgrimes *	environment and on the command line. Reads the system makefile
3621590Srgrimes *	followed by either Makefile, makefile or the file given by the
3631590Srgrimes *	-f argument. Sets the .MAKEFLAGS PMake variable based on all the
3641590Srgrimes *	flags it has received by then uses either the Make or the Compat
3651590Srgrimes *	module to create the initial list of targets.
3661590Srgrimes *
3671590Srgrimes * Results:
3681590Srgrimes *	If -q was given, exits -1 if anything was out-of-date. Else it exits
3691590Srgrimes *	0.
3701590Srgrimes *
3711590Srgrimes * Side Effects:
3721590Srgrimes *	The program exits when done. Targets are created. etc. etc. etc.
3731590Srgrimes */
3741590Srgrimesint
3751590Srgrimesmain(argc, argv)
3761590Srgrimes	int argc;
3771590Srgrimes	char **argv;
3781590Srgrimes{
3791590Srgrimes	Lst targs;	/* target nodes to create -- passed to Make_Init */
3801590Srgrimes	Boolean outOfDate = TRUE; 	/* FALSE if all targets up to date */
3811590Srgrimes	struct stat sb, sa;
3825814Sjkh	char *p, *p1, *path, *pwd, *getenv(), *getwd();
3831590Srgrimes	char mdpath[MAXPATHLEN + 1];
3841590Srgrimes	char obpath[MAXPATHLEN + 1];
3851590Srgrimes	char cdpath[MAXPATHLEN + 1];
38616663Sjkh	char *realobjdir;	/* Where we'd like to go */
3875814Sjkh	struct utsname utsname;
3885814Sjkh    	char *machine = getenv("MACHINE");
3891590Srgrimes
3901590Srgrimes	/*
3911590Srgrimes	 * Find where we are and take care of PWD for the automounter...
3921590Srgrimes	 * All this code is so that we know where we are when we start up
3931590Srgrimes	 * on a different machine with pmake.
3941590Srgrimes	 */
3951590Srgrimes	curdir = cdpath;
3965814Sjkh	if (getcwd(curdir, MAXPATHLEN) == NULL) {
3975814Sjkh		(void)fprintf(stderr, "make: %s.\n", strerror(errno));
3981590Srgrimes		exit(2);
3991590Srgrimes	}
4001590Srgrimes
4011590Srgrimes	if (stat(curdir, &sa) == -1) {
4021590Srgrimes	    (void)fprintf(stderr, "make: %s: %s.\n",
4031590Srgrimes			  curdir, strerror(errno));
4041590Srgrimes	    exit(2);
4051590Srgrimes	}
4061590Srgrimes
40716885Sjkh	if ((pwd = getenv("PWD")) != NULL) {
40816885Sjkh	    if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino &&
40916885Sjkh		sa.st_dev == sb.st_dev)
41016885Sjkh		(void) strcpy(curdir, pwd);
41116885Sjkh	}
41216885Sjkh
4135814Sjkh	/*
4145814Sjkh	 * Get the name of this type of MACHINE from utsname
4155814Sjkh	 * so we can share an executable for similar machines.
4165814Sjkh	 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
4175814Sjkh	 *
4185814Sjkh	 * Note that while MACHINE is decided at run-time,
4195814Sjkh	 * MACHINE_ARCH is always known at compile time.
4205814Sjkh	 */
4215814Sjkh    	if (!machine) {
4225814Sjkh	    if (uname(&utsname)) {
4235814Sjkh		    perror("make: uname");
4245814Sjkh		    exit(2);
4255814Sjkh	    }
4265814Sjkh	    machine = utsname.machine;
4275814Sjkh	}
4281590Srgrimes
4291590Srgrimes	/*
4301590Srgrimes	 * if the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory
4311590Srgrimes	 * exists, change into it and build there.  Once things are
4321590Srgrimes	 * initted, have to add the original directory to the search path,
4331590Srgrimes	 * and modify the paths for the Makefiles apropriately.  The
4341590Srgrimes	 * current directory is also placed as a variable for make scripts.
4351590Srgrimes	 */
43616663Sjkh	if (!(path = getenv("MAKEOBJDIR")))
4371590Srgrimes		path = _PATH_OBJDIR;
43816663Sjkh	(void) snprintf(mdpath, MAXPATHLEN, "%s%s", path, curdir);
43916663Sjkh	realobjdir = mdpath;	/* This is where we'd _like_ to be, anyway */
4408874Srgrimes
4411590Srgrimes	if (stat(mdpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
4421590Srgrimes
4431590Srgrimes		if (chdir(mdpath)) {
4441590Srgrimes			(void)fprintf(stderr, "make warning: %s: %s.\n",
4451590Srgrimes				      mdpath, strerror(errno));
4461590Srgrimes			objdir = curdir;
4471590Srgrimes		}
4481590Srgrimes		else {
4491590Srgrimes			if (mdpath[0] != '/') {
4501590Srgrimes				(void) sprintf(obpath, "%s/%s", curdir, mdpath);
4511590Srgrimes				objdir = obpath;
4521590Srgrimes			}
4531590Srgrimes			else
4541590Srgrimes				objdir = mdpath;
4551590Srgrimes		}
4561590Srgrimes	}
45716663Sjkh	else
45816663Sjkh		objdir = curdir;
4591590Srgrimes
4601590Srgrimes	setenv("PWD", objdir, 1);
4611590Srgrimes
4621590Srgrimes	create = Lst_Init(FALSE);
4631590Srgrimes	makefiles = Lst_Init(FALSE);
46417193Sbde	printVars = FALSE;
46517193Sbde	variables = Lst_Init(FALSE);
4661590Srgrimes	beSilent = FALSE;		/* Print commands as executed */
4671590Srgrimes	ignoreErrors = FALSE;		/* Pay attention to non-zero returns */
4681590Srgrimes	noExecute = FALSE;		/* Execute all commands */
4691590Srgrimes	keepgoing = FALSE;		/* Stop on error */
4701590Srgrimes	allPrecious = FALSE;		/* Remove targets when interrupted */
4711590Srgrimes	queryFlag = FALSE;		/* This is not just a check-run */
4721590Srgrimes	noBuiltins = FALSE;		/* Read the built-in rules */
4731590Srgrimes	touchFlag = FALSE;		/* Actually update targets */
4741590Srgrimes	usePipes = TRUE;		/* Catch child output in pipes */
4751590Srgrimes	debug = 0;			/* No debug verbosity, please. */
4761590Srgrimes	jobsRunning = FALSE;
4771590Srgrimes
4781590Srgrimes	maxJobs = DEFMAXJOBS;		/* Set default max concurrency */
4791590Srgrimes	maxLocal = DEFMAXLOCAL;		/* Set default local max concurrency */
4801590Srgrimes#ifdef notyet
4811590Srgrimes	compatMake = FALSE;		/* No compat mode */
4821590Srgrimes#else
4831590Srgrimes	compatMake = TRUE;		/* No compat mode */
4841590Srgrimes#endif
4851590Srgrimes
4868874Srgrimes
4871590Srgrimes	/*
4881590Srgrimes	 * Initialize the parsing, directory and variable modules to prepare
4891590Srgrimes	 * for the reading of inclusion paths and variable settings on the
4901590Srgrimes	 * command line
4911590Srgrimes	 */
4921590Srgrimes	Dir_Init();		/* Initialize directory structures so -I flags
4931590Srgrimes				 * can be processed correctly */
4941590Srgrimes	Parse_Init();		/* Need to initialize the paths of #include
4951590Srgrimes				 * directories */
4961590Srgrimes	Var_Init();		/* As well as the lists of variables for
4971590Srgrimes				 * parsing arguments */
4985814Sjkh        str_init();
4991590Srgrimes	if (objdir != curdir)
5001590Srgrimes		Dir_AddDir(dirSearchPath, curdir);
5011590Srgrimes	Var_Set(".CURDIR", curdir, VAR_GLOBAL);
50216663Sjkh	Var_Set(".TARGETOBJDIR", realobjdir, VAR_GLOBAL);
5031590Srgrimes	Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
5041590Srgrimes
5051590Srgrimes	/*
5061590Srgrimes	 * Initialize various variables.
5071590Srgrimes	 *	MAKE also gets this name, for compatibility
5081590Srgrimes	 *	.MAKEFLAGS gets set to the empty string just in case.
5091590Srgrimes	 *	MFLAGS also gets initialized empty, for compatibility.
5101590Srgrimes	 */
5111590Srgrimes	Var_Set("MAKE", argv[0], VAR_GLOBAL);
5121590Srgrimes	Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
5131590Srgrimes	Var_Set("MFLAGS", "", VAR_GLOBAL);
5145814Sjkh	Var_Set("MACHINE", machine, VAR_GLOBAL);
5151590Srgrimes#ifdef MACHINE_ARCH
5161590Srgrimes	Var_Set("MACHINE_ARCH", MACHINE_ARCH, VAR_GLOBAL);
5171590Srgrimes#endif
5181590Srgrimes
5191590Srgrimes	/*
5201590Srgrimes	 * First snag any flags out of the MAKE environment variable.
5211590Srgrimes	 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
5221590Srgrimes	 * in a different format).
5231590Srgrimes	 */
5241590Srgrimes#ifdef POSIX
5251590Srgrimes	Main_ParseArgLine(getenv("MAKEFLAGS"));
5261590Srgrimes#else
5271590Srgrimes	Main_ParseArgLine(getenv("MAKE"));
5281590Srgrimes#endif
5298874Srgrimes
5301590Srgrimes	MainParseArgs(argc, argv);
5311590Srgrimes
5321590Srgrimes	/*
5331590Srgrimes	 * Initialize archive, target and suffix modules in preparation for
5341590Srgrimes	 * parsing the makefile(s)
5351590Srgrimes	 */
5361590Srgrimes	Arch_Init();
5371590Srgrimes	Targ_Init();
5381590Srgrimes	Suff_Init();
5391590Srgrimes
5401590Srgrimes	DEFAULT = NILGNODE;
5411590Srgrimes	(void)time(&now);
5421590Srgrimes
5431590Srgrimes	/*
5441590Srgrimes	 * Set up the .TARGETS variable to contain the list of targets to be
5451590Srgrimes	 * created. If none specified, make the variable empty -- the parser
5461590Srgrimes	 * will fill the thing in with the default or .MAIN target.
5471590Srgrimes	 */
5481590Srgrimes	if (!Lst_IsEmpty(create)) {
5491590Srgrimes		LstNode ln;
5501590Srgrimes
5511590Srgrimes		for (ln = Lst_First(create); ln != NILLNODE;
5521590Srgrimes		    ln = Lst_Succ(ln)) {
5531590Srgrimes			char *name = (char *)Lst_Datum(ln);
5541590Srgrimes
5551590Srgrimes			Var_Append(".TARGETS", name, VAR_GLOBAL);
5561590Srgrimes		}
5571590Srgrimes	} else
5581590Srgrimes		Var_Set(".TARGETS", "", VAR_GLOBAL);
5591590Srgrimes
5601590Srgrimes	/*
5611590Srgrimes	 * Read in the built-in rules first, followed by the specified makefile,
5621590Srgrimes	 * if it was (makefile != (char *) NULL), or the default Makefile and
5631590Srgrimes	 * makefile, in that order, if it wasn't.
5641590Srgrimes	 */
5651590Srgrimes	 if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK))
5661590Srgrimes		Fatal("make: no system rules (%s).", _PATH_DEFSYSMK);
5671590Srgrimes
5681590Srgrimes	if (!Lst_IsEmpty(makefiles)) {
5691590Srgrimes		LstNode ln;
5701590Srgrimes
5711590Srgrimes		ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile);
5721590Srgrimes		if (ln != NILLNODE)
5731590Srgrimes			Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
5741590Srgrimes	} else if (!ReadMakefile("makefile"))
5751590Srgrimes		(void)ReadMakefile("Makefile");
5761590Srgrimes
5771590Srgrimes	(void)ReadMakefile(".depend");
5781590Srgrimes
5795814Sjkh	Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);
5805814Sjkh	if (p1)
5815814Sjkh	    free(p1);
5821590Srgrimes
5831590Srgrimes	/* Install all the flags into the MAKE envariable. */
5845814Sjkh	if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p)
5851590Srgrimes#ifdef POSIX
5861590Srgrimes		setenv("MAKEFLAGS", p, 1);
5871590Srgrimes#else
5881590Srgrimes		setenv("MAKE", p, 1);
5891590Srgrimes#endif
5905814Sjkh	if (p1)
5915814Sjkh	    free(p1);
5921590Srgrimes
5931590Srgrimes	/*
5941590Srgrimes	 * For compatibility, look at the directories in the VPATH variable
5951590Srgrimes	 * and add them to the search path, if the variable is defined. The
5961590Srgrimes	 * variable's value is in the same format as the PATH envariable, i.e.
5971590Srgrimes	 * <directory>:<directory>:<directory>...
5981590Srgrimes	 */
5991590Srgrimes	if (Var_Exists("VPATH", VAR_CMD)) {
6001590Srgrimes		char *vpath, *path, *cp, savec;
6011590Srgrimes		/*
6021590Srgrimes		 * GCC stores string constants in read-only memory, but
6031590Srgrimes		 * Var_Subst will want to write this thing, so store it
6041590Srgrimes		 * in an array
6051590Srgrimes		 */
6061590Srgrimes		static char VPATH[] = "${VPATH}";
6071590Srgrimes
6081590Srgrimes		vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE);
6091590Srgrimes		path = vpath;
6101590Srgrimes		do {
6111590Srgrimes			/* skip to end of directory */
6121590Srgrimes			for (cp = path; *cp != ':' && *cp != '\0'; cp++)
6131590Srgrimes				continue;
6141590Srgrimes			/* Save terminator character so know when to stop */
6151590Srgrimes			savec = *cp;
6161590Srgrimes			*cp = '\0';
6171590Srgrimes			/* Add directory to search path */
6181590Srgrimes			Dir_AddDir(dirSearchPath, path);
6191590Srgrimes			*cp = savec;
6201590Srgrimes			path = cp + 1;
6211590Srgrimes		} while (savec == ':');
6221590Srgrimes		(void)free((Address)vpath);
6231590Srgrimes	}
6241590Srgrimes
6251590Srgrimes	/*
6261590Srgrimes	 * Now that all search paths have been read for suffixes et al, it's
6271590Srgrimes	 * time to add the default search path to their lists...
6281590Srgrimes	 */
6291590Srgrimes	Suff_DoPaths();
6301590Srgrimes
6311590Srgrimes	/* print the initial graph, if the user requested it */
6321590Srgrimes	if (DEBUG(GRAPH1))
6331590Srgrimes		Targ_PrintGraph(1);
6341590Srgrimes
63517193Sbde	/* print the values of any variables requested by the user */
63617193Sbde	if (printVars) {
63717193Sbde		LstNode ln;
63817193Sbde
63917193Sbde		for (ln = Lst_First(variables); ln != NILLNODE;
64017193Sbde		    ln = Lst_Succ(ln)) {
64117193Sbde			char *value = Var_Value((char *)Lst_Datum(ln),
64217193Sbde					  VAR_GLOBAL, &p1);
64317193Sbde
64417193Sbde			printf("%s\n", value ? value : "");
64517193Sbde			if (p1)
64617193Sbde				free(p1);
64717193Sbde		}
64817193Sbde	}
64917193Sbde
6501590Srgrimes	/*
6511590Srgrimes	 * Have now read the entire graph and need to make a list of targets
6521590Srgrimes	 * to create. If none was given on the command line, we consult the
6531590Srgrimes	 * parsing module to find the main target(s) to create.
6541590Srgrimes	 */
6551590Srgrimes	if (Lst_IsEmpty(create))
6561590Srgrimes		targs = Parse_MainName();
6571590Srgrimes	else
6581590Srgrimes		targs = Targ_FindList(create, TARG_CREATE);
6591590Srgrimes
6601590Srgrimes/*
6611590Srgrimes * this was original amMake -- want to allow parallelism, so put this
6621590Srgrimes * back in, eventually.
6631590Srgrimes */
66417193Sbde	if (!compatMake && !printVars) {
6651590Srgrimes		/*
6661590Srgrimes		 * Initialize job module before traversing the graph, now that
6671590Srgrimes		 * any .BEGIN and .END targets have been read.  This is done
6681590Srgrimes		 * only if the -q flag wasn't given (to prevent the .BEGIN from
6691590Srgrimes		 * being executed should it exist).
6701590Srgrimes		 */
6711590Srgrimes		if (!queryFlag) {
6721590Srgrimes			if (maxLocal == -1)
6731590Srgrimes				maxLocal = maxJobs;
6741590Srgrimes			Job_Init(maxJobs, maxLocal);
6751590Srgrimes			jobsRunning = TRUE;
6761590Srgrimes		}
6771590Srgrimes
6781590Srgrimes		/* Traverse the graph, checking on all the targets */
6791590Srgrimes		outOfDate = Make_Run(targs);
68017193Sbde	} else if (!printVars) {
6811590Srgrimes		/*
6821590Srgrimes		 * Compat_Init will take care of creating all the targets as
6831590Srgrimes		 * well as initializing the module.
6841590Srgrimes		 */
6851590Srgrimes		Compat_Run(targs);
68617193Sbde	}
6878874Srgrimes
6885814Sjkh	Lst_Destroy(targs, NOFREE);
68917193Sbde	Lst_Destroy(variables, NOFREE);
6905814Sjkh	Lst_Destroy(makefiles, NOFREE);
6915814Sjkh	Lst_Destroy(create, (void (*) __P((ClientData))) free);
6925814Sjkh
6931590Srgrimes	/* print the graph now it's been processed if the user requested it */
6941590Srgrimes	if (DEBUG(GRAPH2))
6951590Srgrimes		Targ_PrintGraph(2);
6961590Srgrimes
6975814Sjkh	Suff_End();
6985814Sjkh        Targ_End();
6995814Sjkh	Arch_End();
7005814Sjkh	str_end();
7015814Sjkh	Var_End();
7025814Sjkh	Parse_End();
7035814Sjkh	Dir_End();
7045814Sjkh
7051590Srgrimes	if (queryFlag && outOfDate)
7061590Srgrimes		return(1);
7071590Srgrimes	else
7081590Srgrimes		return(0);
7091590Srgrimes}
7101590Srgrimes
7111590Srgrimes/*-
7121590Srgrimes * ReadMakefile  --
7131590Srgrimes *	Open and parse the given makefile.
7141590Srgrimes *
7151590Srgrimes * Results:
7161590Srgrimes *	TRUE if ok. FALSE if couldn't open file.
7171590Srgrimes *
7181590Srgrimes * Side Effects:
7191590Srgrimes *	lots
7201590Srgrimes */
7211590Srgrimesstatic Boolean
7221590SrgrimesReadMakefile(fname)
7231590Srgrimes	char *fname;		/* makefile to read */
7241590Srgrimes{
7251590Srgrimes	extern Lst parseIncPath, sysIncPath;
7261590Srgrimes	FILE *stream;
7271590Srgrimes	char *name, path[MAXPATHLEN + 1];
7281590Srgrimes
7291590Srgrimes	if (!strcmp(fname, "-")) {
7301590Srgrimes		Parse_File("(stdin)", stdin);
7311590Srgrimes		Var_Set("MAKEFILE", "", VAR_GLOBAL);
7321590Srgrimes	} else {
7331590Srgrimes		if ((stream = fopen(fname, "r")) != NULL)
7341590Srgrimes			goto found;
7351590Srgrimes		/* if we've chdir'd, rebuild the path name */
7361590Srgrimes		if (curdir != objdir && *fname != '/') {
7371590Srgrimes			(void)sprintf(path, "%s/%s", curdir, fname);
7381590Srgrimes			if ((stream = fopen(path, "r")) != NULL) {
7391590Srgrimes				fname = path;
7401590Srgrimes				goto found;
7411590Srgrimes			}
7421590Srgrimes		}
7431590Srgrimes		/* look in -I and system include directories. */
7441590Srgrimes		name = Dir_FindFile(fname, parseIncPath);
7451590Srgrimes		if (!name)
7461590Srgrimes			name = Dir_FindFile(fname, sysIncPath);
7471590Srgrimes		if (!name || !(stream = fopen(name, "r")))
7481590Srgrimes			return(FALSE);
7491590Srgrimes		fname = name;
7501590Srgrimes		/*
7511590Srgrimes		 * set the MAKEFILE variable desired by System V fans -- the
7521590Srgrimes		 * placement of the setting here means it gets set to the last
7531590Srgrimes		 * makefile specified, as it is set by SysV make.
7541590Srgrimes		 */
7551590Srgrimesfound:		Var_Set("MAKEFILE", fname, VAR_GLOBAL);
7561590Srgrimes		Parse_File(fname, stream);
7571590Srgrimes		(void)fclose(stream);
7581590Srgrimes	}
7591590Srgrimes	return(TRUE);
7601590Srgrimes}
7611590Srgrimes
7621590Srgrimes/*-
7631590Srgrimes * Error --
7641590Srgrimes *	Print an error message given its format.
7651590Srgrimes *
7661590Srgrimes * Results:
7671590Srgrimes *	None.
7681590Srgrimes *
7691590Srgrimes * Side Effects:
7701590Srgrimes *	The message is printed.
7711590Srgrimes */
7721590Srgrimes/* VARARGS */
7731590Srgrimesvoid
7741590Srgrimes#if __STDC__
7755814SjkhError(char *fmt, ...)
7761590Srgrimes#else
7771590SrgrimesError(va_alist)
7781590Srgrimes	va_dcl
7791590Srgrimes#endif
7801590Srgrimes{
7811590Srgrimes	va_list ap;
7821590Srgrimes#if __STDC__
7831590Srgrimes	va_start(ap, fmt);
7841590Srgrimes#else
7851590Srgrimes	char *fmt;
7861590Srgrimes
7871590Srgrimes	va_start(ap);
7881590Srgrimes	fmt = va_arg(ap, char *);
7891590Srgrimes#endif
7901590Srgrimes	(void)vfprintf(stderr, fmt, ap);
7911590Srgrimes	va_end(ap);
7921590Srgrimes	(void)fprintf(stderr, "\n");
7931590Srgrimes	(void)fflush(stderr);
7941590Srgrimes}
7951590Srgrimes
7961590Srgrimes/*-
7971590Srgrimes * Fatal --
7981590Srgrimes *	Produce a Fatal error message. If jobs are running, waits for them
7991590Srgrimes *	to finish.
8001590Srgrimes *
8011590Srgrimes * Results:
8021590Srgrimes *	None
8031590Srgrimes *
8041590Srgrimes * Side Effects:
8051590Srgrimes *	The program exits
8061590Srgrimes */
8071590Srgrimes/* VARARGS */
8081590Srgrimesvoid
8091590Srgrimes#if __STDC__
8105814SjkhFatal(char *fmt, ...)
8111590Srgrimes#else
8121590SrgrimesFatal(va_alist)
8131590Srgrimes	va_dcl
8141590Srgrimes#endif
8151590Srgrimes{
8161590Srgrimes	va_list ap;
8171590Srgrimes#if __STDC__
8181590Srgrimes	va_start(ap, fmt);
8191590Srgrimes#else
8201590Srgrimes	char *fmt;
8211590Srgrimes
8221590Srgrimes	va_start(ap);
8231590Srgrimes	fmt = va_arg(ap, char *);
8241590Srgrimes#endif
8251590Srgrimes	if (jobsRunning)
8261590Srgrimes		Job_Wait();
8271590Srgrimes
8281590Srgrimes	(void)vfprintf(stderr, fmt, ap);
8291590Srgrimes	va_end(ap);
8301590Srgrimes	(void)fprintf(stderr, "\n");
8311590Srgrimes	(void)fflush(stderr);
8321590Srgrimes
8331590Srgrimes	if (DEBUG(GRAPH2))
8341590Srgrimes		Targ_PrintGraph(2);
8351590Srgrimes	exit(2);		/* Not 1 so -q can distinguish error */
8361590Srgrimes}
8371590Srgrimes
8381590Srgrimes/*
8391590Srgrimes * Punt --
8401590Srgrimes *	Major exception once jobs are being created. Kills all jobs, prints
8411590Srgrimes *	a message and exits.
8421590Srgrimes *
8431590Srgrimes * Results:
8448874Srgrimes *	None
8451590Srgrimes *
8461590Srgrimes * Side Effects:
8471590Srgrimes *	All children are killed indiscriminately and the program Lib_Exits
8481590Srgrimes */
8491590Srgrimes/* VARARGS */
8501590Srgrimesvoid
8511590Srgrimes#if __STDC__
8525814SjkhPunt(char *fmt, ...)
8531590Srgrimes#else
8541590SrgrimesPunt(va_alist)
8551590Srgrimes	va_dcl
8561590Srgrimes#endif
8571590Srgrimes{
8581590Srgrimes	va_list ap;
8591590Srgrimes#if __STDC__
8601590Srgrimes	va_start(ap, fmt);
8611590Srgrimes#else
8621590Srgrimes	char *fmt;
8631590Srgrimes
8641590Srgrimes	va_start(ap);
8651590Srgrimes	fmt = va_arg(ap, char *);
8661590Srgrimes#endif
8671590Srgrimes
8681590Srgrimes	(void)fprintf(stderr, "make: ");
8691590Srgrimes	(void)vfprintf(stderr, fmt, ap);
8701590Srgrimes	va_end(ap);
8711590Srgrimes	(void)fprintf(stderr, "\n");
8721590Srgrimes	(void)fflush(stderr);
8731590Srgrimes
8741590Srgrimes	DieHorribly();
8751590Srgrimes}
8761590Srgrimes
8771590Srgrimes/*-
8781590Srgrimes * DieHorribly --
8791590Srgrimes *	Exit without giving a message.
8801590Srgrimes *
8811590Srgrimes * Results:
8821590Srgrimes *	None
8831590Srgrimes *
8841590Srgrimes * Side Effects:
8851590Srgrimes *	A big one...
8861590Srgrimes */
8871590Srgrimesvoid
8881590SrgrimesDieHorribly()
8891590Srgrimes{
8901590Srgrimes	if (jobsRunning)
8911590Srgrimes		Job_AbortAll();
8921590Srgrimes	if (DEBUG(GRAPH2))
8931590Srgrimes		Targ_PrintGraph(2);
8941590Srgrimes	exit(2);		/* Not 1, so -q can distinguish error */
8951590Srgrimes}
8961590Srgrimes
8971590Srgrimes/*
8981590Srgrimes * Finish --
8991590Srgrimes *	Called when aborting due to errors in child shell to signal
9008874Srgrimes *	abnormal exit.
9011590Srgrimes *
9021590Srgrimes * Results:
9038874Srgrimes *	None
9041590Srgrimes *
9051590Srgrimes * Side Effects:
9061590Srgrimes *	The program exits
9071590Srgrimes */
9081590Srgrimesvoid
9091590SrgrimesFinish(errors)
9101590Srgrimes	int errors;	/* number of errors encountered in Make_Make */
9111590Srgrimes{
9121590Srgrimes	Fatal("%d error%s", errors, errors == 1 ? "" : "s");
9131590Srgrimes}
9141590Srgrimes
9151590Srgrimes/*
9161590Srgrimes * emalloc --
9171590Srgrimes *	malloc, but die on error.
9181590Srgrimes */
9191590Srgrimeschar *
9201590Srgrimesemalloc(len)
9215814Sjkh	size_t len;
9221590Srgrimes{
9231590Srgrimes	char *p;
9241590Srgrimes
9255814Sjkh	if ((p = (char *) malloc(len)) == NULL)
9261590Srgrimes		enomem();
9271590Srgrimes	return(p);
9281590Srgrimes}
9291590Srgrimes
9301590Srgrimes/*
9311590Srgrimes * enomem --
9321590Srgrimes *	die when out of memory.
9331590Srgrimes */
9341590Srgrimesvoid
9351590Srgrimesenomem()
9361590Srgrimes{
9371590Srgrimes	(void)fprintf(stderr, "make: %s.\n", strerror(errno));
9381590Srgrimes	exit(2);
9391590Srgrimes}
9401590Srgrimes
9411590Srgrimes/*
9421590Srgrimes * usage --
9431590Srgrimes *	exit with usage message
9441590Srgrimes */
9451590Srgrimesstatic void
9461590Srgrimesusage()
9471590Srgrimes{
9481590Srgrimes	(void)fprintf(stderr,
94917193Sbde"usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile] [-I directory]\n\
95017193Sbde            [-j max_jobs] [-V variable] [variable=value] [target ...]\n");
9511590Srgrimes	exit(2);
9521590Srgrimes}
9535814Sjkh
9545814Sjkh
9555814Sjkhint
9565814SjkhPrintAddr(a, b)
9575814Sjkh    ClientData a;
9585814Sjkh    ClientData b;
9595814Sjkh{
9605814Sjkh    printf("%lx ", (unsigned long) a);
9615814Sjkh    return b ? 0 : 0;
9625814Sjkh}
963