diff options
Diffstat (limited to 'usr.bin/make/main.c')
-rw-r--r-- | usr.bin/make/main.c | 477 |
1 files changed, 389 insertions, 88 deletions
diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index 8607fbb..d8b1708 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -1,3 +1,5 @@ +/* $NetBSD: main.c,v 1.30 1996/08/13 16:42:08 christos Exp $ */ + /* * Copyright (c) 1988, 1989, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -43,7 +45,11 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/28/95"; +#if 0 +static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; +#else +static char rcsid[] = "$NetBSD: main.c,v 1.30 1996/08/13 16:42:08 christos Exp $"; +#endif #endif /* not lint */ /*- @@ -79,7 +85,10 @@ static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/28/95"; #include <sys/resource.h> #include <sys/signal.h> #include <sys/stat.h> +#ifndef MACHINE #include <sys/utsname.h> +#endif +#include <sys/wait.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -96,7 +105,7 @@ static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/28/95"; #ifndef DEFMAXLOCAL #define DEFMAXLOCAL DEFMAXJOBS -#endif DEFMAXLOCAL +#endif /* DEFMAXLOCAL */ #define MAKEFLAGS ".MAKEFLAGS" @@ -107,7 +116,9 @@ Boolean allPrecious; /* .PRECIOUS given on line by itself */ static Boolean noBuiltins; /* -r flag */ static Lst makefiles; /* ordered list of makefiles to read */ -int maxJobs; /* -J argument */ +static Boolean printVars; /* print value of one or more vars */ +static Lst variables; /* list of variables to print */ +int maxJobs; /* -j argument */ static int maxLocal; /* -L argument */ Boolean compatMake; /* -B argument */ Boolean debug; /* -d flag */ @@ -122,8 +133,10 @@ Boolean oldVars; /* variable substitution style */ Boolean checkEnvFirst; /* -e flag */ static Boolean jobsRunning; /* TRUE if the jobs might be running */ -static Boolean ReadMakefile(); -static void usage(); +static void MainParseArgs __P((int, char **)); +char * chdir_verify_path __P((char *, char *)); +static int ReadMakefile __P((ClientData, ClientData)); +static void usage __P((void)); static char *curdir; /* startup directory */ static char *objdir; /* where we chdir'ed to */ @@ -150,12 +163,13 @@ MainParseArgs(argc, argv) extern int optind; extern char *optarg; int c; + int forceJobs = 0; optind = 1; /* since we're called more than once */ -#ifdef notyet -# define OPTFLAGS "BD:I:L:PSd:ef:ij:knqrst" +#ifdef REMOTE +# define OPTFLAGS "BD:I:L:PSV:d:ef:ij:km:nqrst" #else -# define OPTFLAGS "D:I:d:ef:ij:knqrst" +# define OPTFLAGS "BD:I:PSV:d:ef:ij:km:nqrst" #endif rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { switch(c) { @@ -169,15 +183,22 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); break; -#ifdef notyet + case 'V': + printVars = TRUE; + (void)Lst_AtEnd(variables, (ClientData)optarg); + Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); + Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); + break; case 'B': compatMake = TRUE; break; +#ifdef REMOTE case 'L': maxLocal = atoi(optarg); Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); break; +#endif case 'P': usePipes = FALSE; Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); @@ -186,7 +207,6 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { keepgoing = FALSE; Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); break; -#endif case 'd': { char *modules = optarg; @@ -254,7 +274,11 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); break; case 'j': + forceJobs = TRUE; maxJobs = atoi(optarg); +#ifndef REMOTE + maxLocal = maxJobs; +#endif Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); break; @@ -262,6 +286,11 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { keepgoing = TRUE; Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); break; + case 'm': + Dir_AddDir(sysIncPath, optarg); + Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); + Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); + break; case 'n': noExecute = TRUE; Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); @@ -289,6 +318,13 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { } } + /* + * Be compatible if user did not specify -j and did not explicitly + * turned compatibility on + */ + if (!compatMake && !forceJobs) + compatMake = TRUE; + oldVars = TRUE; /* @@ -309,7 +345,7 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != EOF) { optind = 1; /* - */ goto rearg; } - (void)Lst_AtEnd(create, (ClientData)strdup(*argv)); + (void)Lst_AtEnd(create, (ClientData)estrdup(*argv)); } } @@ -346,6 +382,34 @@ Main_ParseArgLine(line) MainParseArgs(argc, argv); } +char * +chdir_verify_path(path, obpath) + char *path; + char *obpath; +{ + struct stat sb; + + if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { + if (chdir(path)) { + (void)fprintf(stderr, "make warning: %s: %s.\n", + path, strerror(errno)); + return 0; + } + else { + if (path[0] != '/') { + (void) snprintf(obpath, MAXPATHLEN, "%s/%s", + curdir, path); + return obpath; + } + else + return path; + } + } + + return 0; +} + + /*- * main -- * The main function, for obvious reasons. Initializes variables @@ -371,13 +435,29 @@ main(argc, argv) Lst targs; /* target nodes to create -- passed to Make_Init */ Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ struct stat sb, sa; - char *p, *p1, *path, *pwd, *getenv(), *getwd(); + char *p, *p1, *path, *pathp, *pwd; char mdpath[MAXPATHLEN + 1]; char obpath[MAXPATHLEN + 1]; char cdpath[MAXPATHLEN + 1]; - struct utsname utsname; char *machine = getenv("MACHINE"); + Lst sysMkPath; /* Path of sys.mk */ + char *cp = NULL, *start; + /* avoid faults on read-only strings */ + static char syspath[] = _PATH_DEFSYSPATH; +#ifdef RLIMIT_NOFILE + /* + * get rid of resource limit on file descriptors + */ + { + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && + rl.rlim_cur != rl.rlim_max) { + rl.rlim_cur = rl.rlim_max; + (void) setrlimit(RLIMIT_NOFILE, &rl); + } + } +#endif /* * Find where we are and take care of PWD for the automounter... * All this code is so that we know where we are when we start up @@ -397,7 +477,7 @@ main(argc, argv) if ((pwd = getenv("PWD")) != NULL) { if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && - sa.st_dev == sb.st_dev) + sa.st_dev == sb.st_dev) (void) strcpy(curdir, pwd); } @@ -410,62 +490,53 @@ main(argc, argv) * MACHINE_ARCH is always known at compile time. */ if (!machine) { - if (uname(&utsname)) { +#ifndef MACHINE + struct utsname utsname; + + if (uname(&utsname) == -1) { perror("make: uname"); exit(2); } machine = utsname.machine; +#else + machine = MACHINE; +#endif } /* - * if the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory - * exists, change into it and build there. Once things are - * initted, have to add the original directory to the search path, + * If the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory + * exists, change into it and build there. (If a .${MACHINE} suffix + * exists, use that directory instead). + * Otherwise check MAKEOBJDIRPREFIX`cwd` (or by default, + * _PATH_OBJDIRPREFIX`cwd`) and build there if it exists. + * If all fails, use the current directory to build. + * + * Once things are initted, + * have to add the original directory to the search path, * and modify the paths for the Makefiles apropriately. The * current directory is also placed as a variable for make scripts. */ - if (!(path = getenv("MAKEOBJDIR"))) { - path = _PATH_OBJDIR; - (void) sprintf(mdpath, "%s.%s", path, machine); - } - else - (void) strncpy(mdpath, path, MAXPATHLEN + 1); - - if (stat(mdpath, &sb) == 0 && S_ISDIR(sb.st_mode)) { - - if (chdir(mdpath)) { - (void)fprintf(stderr, "make warning: %s: %s.\n", - mdpath, strerror(errno)); - objdir = curdir; - } - else { - if (mdpath[0] != '/') { - (void) sprintf(obpath, "%s/%s", curdir, mdpath); - objdir = obpath; - } - else - objdir = mdpath; + if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) { + if (!(path = getenv("MAKEOBJDIR"))) { + path = _PATH_OBJDIR; + pathp = _PATH_OBJDIRPREFIX; + (void) snprintf(mdpath, MAXPATHLEN, "%s.%s", + path, machine); + if (!(objdir = chdir_verify_path(mdpath, obpath))) + if (!(objdir=chdir_verify_path(path, obpath))) { + (void) snprintf(mdpath, MAXPATHLEN, + "%s%s", pathp, curdir); + if (!(objdir=chdir_verify_path(mdpath, + obpath))) + objdir = curdir; + } } + else if (!(objdir = chdir_verify_path(path, obpath))) + objdir = curdir; } else { - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { - - if (chdir(path)) { - (void)fprintf(stderr, "make warning: %s: %s.\n", - path, strerror(errno)); - objdir = curdir; - } - else { - if (path[0] != '/') { - (void) sprintf(obpath, "%s/%s", curdir, - path); - objdir = obpath; - } - else - objdir = obpath; - } - } - else + (void) snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir); + if (!(objdir = chdir_verify_path(mdpath, obpath))) objdir = curdir; } @@ -473,6 +544,8 @@ main(argc, argv) create = Lst_Init(FALSE); makefiles = Lst_Init(FALSE); + printVars = FALSE; + variables = Lst_Init(FALSE); beSilent = FALSE; /* Print commands as executed */ ignoreErrors = FALSE; /* Pay attention to non-zero returns */ noExecute = FALSE; /* Execute all commands */ @@ -485,14 +558,14 @@ main(argc, argv) debug = 0; /* No debug verbosity, please. */ jobsRunning = FALSE; - maxJobs = DEFMAXJOBS; /* Set default max concurrency */ maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ -#ifdef notyet - compatMake = FALSE; /* No compat mode */ +#ifdef REMOTE + maxJobs = DEFMAXJOBS; /* Set default max concurrency */ #else - compatMake = TRUE; /* No compat mode */ + maxJobs = maxLocal; #endif - + compatMake = FALSE; /* No compat mode */ + /* * Initialize the parsing, directory and variable modules to prepare @@ -535,7 +608,7 @@ main(argc, argv) #else Main_ParseArgLine(getenv("MAKE")); #endif - + MainParseArgs(argc, argv); /* @@ -566,13 +639,41 @@ main(argc, argv) } else Var_Set(".TARGETS", "", VAR_GLOBAL); + + /* + * If no user-supplied system path was given (through the -m option) + * add the directories from the DEFSYSPATH (more than one may be given + * as dir1:...:dirn) to the system include path. + */ + if (Lst_IsEmpty(sysIncPath)) { + for (start = syspath; *start != '\0'; start = cp) { + for (cp = start; *cp != '\0' && *cp != ':'; cp++) + continue; + if (*cp == '\0') { + Dir_AddDir(sysIncPath, start); + } else { + *cp++ = '\0'; + Dir_AddDir(sysIncPath, start); + } + } + } + /* - * Read in the built-in rules first, followed by the specified makefile, - * if it was (makefile != (char *) NULL), or the default Makefile and - * makefile, in that order, if it wasn't. + * Read in the built-in rules first, followed by the specified + * makefile, if it was (makefile != (char *) NULL), or the default + * Makefile and makefile, in that order, if it wasn't. */ - if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK)) - Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); + if (!noBuiltins) { + LstNode ln; + + sysMkPath = Lst_Init (FALSE); + Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath); + if (Lst_IsEmpty(sysMkPath)) + Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); + ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); + if (ln != NILLNODE) + Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); + } if (!Lst_IsEmpty(makefiles)) { LstNode ln; @@ -580,10 +681,10 @@ main(argc, argv) ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); if (ln != NILLNODE) Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); - } else if (!ReadMakefile("makefile")) - (void)ReadMakefile("Makefile"); + } else if (!ReadMakefile("makefile", NULL)) + (void)ReadMakefile("Makefile", NULL); - (void)ReadMakefile(".depend"); + (void)ReadMakefile(".depend", NULL); Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); if (p1) @@ -641,6 +742,21 @@ main(argc, argv) if (DEBUG(GRAPH1)) Targ_PrintGraph(1); + /* print the values of any variables requested by the user */ + if (printVars) { + LstNode ln; + + for (ln = Lst_First(variables); ln != NILLNODE; + ln = Lst_Succ(ln)) { + char *value = Var_Value((char *)Lst_Datum(ln), + VAR_GLOBAL, &p1); + + printf("%s\n", value ? value : ""); + if (p1) + free(p1); + } + } + /* * Have now read the entire graph and need to make a list of targets * to create. If none was given on the command line, we consult the @@ -651,11 +767,7 @@ main(argc, argv) else targs = Targ_FindList(create, TARG_CREATE); -/* - * this was original amMake -- want to allow parallelism, so put this - * back in, eventually. - */ - if (!compatMake) { + if (!compatMake && !printVars) { /* * Initialize job module before traversing the graph, now that * any .BEGIN and .END targets have been read. This is done @@ -671,14 +783,16 @@ main(argc, argv) /* Traverse the graph, checking on all the targets */ outOfDate = Make_Run(targs); - } else + } else if (!printVars) { /* * Compat_Init will take care of creating all the targets as * well as initializing the module. */ Compat_Run(targs); - + } + Lst_Destroy(targs, NOFREE); + Lst_Destroy(variables, NOFREE); Lst_Destroy(makefiles, NOFREE); Lst_Destroy(create, (void (*) __P((ClientData))) free); @@ -711,10 +825,11 @@ main(argc, argv) * lots */ static Boolean -ReadMakefile(fname) - char *fname; /* makefile to read */ +ReadMakefile(p, q) + ClientData p, q; { - extern Lst parseIncPath, sysIncPath; + char *fname = p; /* makefile to read */ + extern Lst parseIncPath; FILE *stream; char *name, path[MAXPATHLEN + 1]; @@ -752,6 +867,142 @@ found: Var_Set("MAKEFILE", fname, VAR_GLOBAL); } /*- + * Cmd_Exec -- + * Execute the command in cmd, and return the output of that command + * in a string. + * + * Results: + * A string containing the output of the command, or the empty string + * If err is not NULL, it contains the reason for the command failure + * + * Side Effects: + * The string must be freed by the caller. + */ +char * +Cmd_Exec(cmd, err) + char *cmd; + char **err; +{ + char *args[4]; /* Args for invoking the shell */ + int fds[2]; /* Pipe streams */ + int cpid; /* Child PID */ + int pid; /* PID from wait() */ + char *res; /* result */ + int status; /* command exit status */ + Buffer buf; /* buffer to store the result */ + char *cp; + int cc; + + + *err = NULL; + + /* + * Set up arguments for shell + */ + args[0] = "sh"; + args[1] = "-c"; + args[2] = cmd; + args[3] = NULL; + + /* + * Open a pipe for fetching its output + */ + if (pipe(fds) == -1) { + *err = "Couldn't create pipe for \"%s\""; + goto bad; + } + + /* + * Fork + */ + switch (cpid = vfork()) { + case 0: + /* + * Close input side of pipe + */ + (void) close(fds[0]); + + /* + * Duplicate the output stream to the shell's output, then + * shut the extra thing down. Note we don't fetch the error + * stream...why not? Why? + */ + (void) dup2(fds[1], 1); + (void) close(fds[1]); + + (void) execv("/bin/sh", args); + _exit(1); + /*NOTREACHED*/ + + case -1: + *err = "Couldn't exec \"%s\""; + goto bad; + + default: + /* + * No need for the writing half + */ + (void) close(fds[1]); + + buf = Buf_Init (MAKE_BSIZE); + + do { + char result[BUFSIZ]; + cc = read(fds[0], result, sizeof(result)); + if (cc > 0) + Buf_AddBytes(buf, cc, (Byte *) result); + } + while (cc > 0 || (cc == -1 && errno == EINTR)); + + /* + * Close the input side of the pipe. + */ + (void) close(fds[0]); + + /* + * Wait for the process to exit. + */ + while(((pid = wait(&status)) != cpid) && (pid >= 0)) + continue; + + res = (char *)Buf_GetAll (buf, &cc); + Buf_Destroy (buf, FALSE); + + if (cc == 0) + *err = "Couldn't read shell's output for \"%s\""; + + if (status) + *err = "\"%s\" returned non-zero status"; + + /* + * Null-terminate the result, convert newlines to spaces and + * install it in the variable. + */ + res[cc] = '\0'; + cp = &res[cc] - 1; + + if (*cp == '\n') { + /* + * A final newline is just stripped + */ + *cp-- = '\0'; + } + while (cp >= res) { + if (*cp == '\n') { + *cp = ' '; + } + cp--; + } + break; + } + return res; +bad: + res = emalloc(1); + *res = '\0'; + return res; +} + +/*- * Error -- * Print an error message given its format. * @@ -833,7 +1084,7 @@ Fatal(va_alist) * a message and exits. * * Results: - * None + * None * * Side Effects: * All children are killed indiscriminately and the program Lib_Exits @@ -889,10 +1140,10 @@ DieHorribly() /* * Finish -- * Called when aborting due to errors in child shell to signal - * abnormal exit. + * abnormal exit. * * Results: - * None + * None * * Side Effects: * The program exits @@ -908,18 +1159,47 @@ Finish(errors) * emalloc -- * malloc, but die on error. */ -char * +void * emalloc(len) size_t len; { + void *p; + + if ((p = malloc(len)) == NULL) + enomem(); + return(p); +} + +/* + * estrdup -- + * strdup, but die on error. + */ +char * +estrdup(str) + const char *str; +{ char *p; - if ((p = (char *) malloc(len)) == NULL) + if ((p = strdup(str)) == NULL) enomem(); return(p); } /* + * erealloc -- + * realloc, but die on error. + */ +void * +erealloc(ptr, size) + void *ptr; + size_t size; +{ + if ((ptr = realloc(ptr, size)) == NULL) + enomem(); + return(ptr); +} + +/* * enomem -- * die when out of memory. */ @@ -931,6 +1211,26 @@ enomem() } /* + * enunlink -- + * Remove a file carefully, avoiding directories. + */ +int +eunlink(file) + const char *file; +{ + struct stat st; + + if (lstat(file, &st) == -1) + return -1; + + if (S_ISDIR(st.st_mode)) { + errno = EISDIR; + return -1; + } + return unlink(file); +} + +/* * usage -- * exit with usage message */ @@ -938,8 +1238,9 @@ static void usage() { (void)fprintf(stderr, -"usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile ]\n\ - [-I directory] [-j max_jobs] [variable=value]\n"); +"usage: make [-Beiknqrst] [-D variable] [-d flags] [-f makefile ]\n\ + [-I directory] [-j max_jobs] [-m directory] [-V variable]\n\ + [variable=value] [target ...]\n"); exit(2); } |