From: Arun Thomas Date: Fri, 25 Jun 2010 23:25:48 +0000 (+0000) Subject: Make: Updates from NetBSD X-Git-Tag: v3.1.8~352 X-Git-Url: http://zhaoyanbai.com/repos/doc/mandoc_char.7.html?a=commitdiff_plain;h=8e0253ac3daf63fa8d9a6129d477dc7168280c88;p=minix.git Make: Updates from NetBSD Needed for pkgsrc --- diff --git a/commands/make/Makefile b/commands/make/Makefile index f837ec73f..3c451ccae 100644 --- a/commands/make/Makefile +++ b/commands/make/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.49 2009/04/14 22:15:23 lukem Exp $ +# $NetBSD: Makefile,v 1.50 2010/04/22 19:15:23 sjg Exp $ # @(#)Makefile 5.2 (Berkeley) 12/28/90 PROG= make @@ -35,4 +35,4 @@ CPPFLAGS+= -DTARGET_MACHINE=\"${MACHINE}\" \ # A simple unit-test driver to help catch regressions accept test: - cd ${.CURDIR}/unit-tests && ${.MAKE:S,^./,${.CURDIR}/,} TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} + cd ${.CURDIR}/unit-tests && ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} diff --git a/commands/make/Makefile.netbsd b/commands/make/Makefile.netbsd index 51cbda371..acbe83aa7 100644 --- a/commands/make/Makefile.netbsd +++ b/commands/make/Makefile.netbsd @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.49 2009/04/14 22:15:23 lukem Exp $ +# $NetBSD: Makefile,v 1.50 2010/04/22 19:15:23 sjg Exp $ # @(#)Makefile 5.2 (Berkeley) 12/28/90 PROG= make @@ -37,4 +37,4 @@ DPADD+=${LIBUTIL} # A simple unit-test driver to help catch regressions accept test: - cd ${.CURDIR}/unit-tests && ${.MAKE:S,^./,${.CURDIR}/,} TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} + cd ${.CURDIR}/unit-tests && ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} diff --git a/commands/make/compat.c b/commands/make/compat.c index 42c5fe2f6..054cfd75e 100644 --- a/commands/make/compat.c +++ b/commands/make/compat.c @@ -1,4 +1,4 @@ -/* $NetBSD: compat.c,v 1.76 2009/02/22 07:33:00 dholland Exp $ */ +/* $NetBSD: compat.c,v 1.79 2010/06/03 15:40:15 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: compat.c,v 1.76 2009/02/22 07:33:00 dholland Exp $"; +static char rcsid[] = "$NetBSD: compat.c,v 1.79 2010/06/03 15:40:15 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: compat.c,v 1.76 2009/02/22 07:33:00 dholland Exp $"); +__RCSID("$NetBSD: compat.c,v 1.79 2010/06/03 15:40:15 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -355,11 +355,7 @@ again: /* * Fork and execute the single command. If the fork fails, we abort. */ -#if defined(__minix) - cpid = fork(); -#else - cpid = vfork(); -#endif + cpid = vFork(); if (cpid < 0) { Fatal("Could not fork"); } @@ -578,7 +574,7 @@ Compat_Make(void *gnp, void *pgnp) } else if (keepgoing) { pgn->flags &= ~REMAKE; } else { - PrintOnError("\n\nStop."); + PrintOnError(gn, "\n\nStop."); exit(1); } } else if (gn->made == ERROR) { @@ -645,17 +641,17 @@ Compat_Run(Lst targs) Compat_Init(); - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - signal(SIGINT, CompatInterrupt); + if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { + bmake_signal(SIGINT, CompatInterrupt); } - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - signal(SIGTERM, CompatInterrupt); + if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { + bmake_signal(SIGTERM, CompatInterrupt); } - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - signal(SIGHUP, CompatInterrupt); + if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { + bmake_signal(SIGHUP, CompatInterrupt); } - if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - signal(SIGQUIT, CompatInterrupt); + if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { + bmake_signal(SIGQUIT, CompatInterrupt); } ENDNode = Targ_FindNode(".END", TARG_CREATE); @@ -669,7 +665,7 @@ Compat_Run(Lst targs) if (gn != NULL) { Compat_Make(gn, gn); if (gn->made == ERROR) { - PrintOnError("\n\nStop."); + PrintOnError(gn, "\n\nStop."); exit(1); } } @@ -710,7 +706,7 @@ Compat_Run(Lst targs) if (errors == 0) { Compat_Make(ENDNode, ENDNode); if (gn->made == ERROR) { - PrintOnError("\n\nStop."); + PrintOnError(gn, "\n\nStop."); exit(1); } } diff --git a/commands/make/for.c b/commands/make/for.c index 62f483d72..4a320a38a 100644 --- a/commands/make/for.c +++ b/commands/make/for.c @@ -1,4 +1,4 @@ -/* $NetBSD: for.c,v 1.46 2009/01/17 13:29:37 dsl Exp $ */ +/* $NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $ */ /* * Copyright (c) 1992, The Regents of the University of California. @@ -30,14 +30,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: for.c,v 1.46 2009/01/17 13:29:37 dsl Exp $"; +static char rcsid[] = "$NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: for.c,v 1.46 2009/01/17 13:29:37 dsl Exp $"); +__RCSID("$NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $"); #endif #endif /* not lint */ #endif @@ -237,7 +237,8 @@ For_Eval(char *line) if (strlist_num(&new_for->items) % strlist_num(&new_for->vars)) { Parse_Error(PARSE_FATAL, - "Wrong number of words in .for substitution list %d %d", + "Wrong number of words (%d) in .for substitution list" + " with %d vars", strlist_num(&new_for->items), strlist_num(&new_for->vars)); /* * Return 'success' so that the body of the .for loop is accumulated. diff --git a/commands/make/job.c b/commands/make/job.c index a8a94433d..aeda9da93 100644 --- a/commands/make/job.c +++ b/commands/make/job.c @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.146 2009/06/26 01:26:32 sjg Exp $ */ +/* $NetBSD: job.c,v 1.151 2010/06/17 03:36:05 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: job.c,v 1.146 2009/06/26 01:26:32 sjg Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.151 2010/06/17 03:36:05 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: job.c,v 1.146 2009/06/26 01:26:32 sjg Exp $"); +__RCSID("$NetBSD: job.c,v 1.151 2010/06/17 03:36:05 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -342,8 +342,6 @@ static sigset_t caught_signals; /* Set of signals we handle */ #define KILLPG(pid, sig) killpg((pid), (sig)) #endif -static char *tmpdir; /* directory name, always ending with "/" */ - static void JobChildSig(int); static void JobContinueSig(int); static Job *JobFindPid(int, int); @@ -1022,8 +1020,11 @@ JobFinish(Job *job, int status) job->node->name, WEXITSTATUS(status), (job->flags & JOB_IGNERR) ? "(ignored)" : ""); - if (job->flags & JOB_IGNERR) + if (job->flags & JOB_IGNERR) { status = 0; + } else { + PrintOnError(job->node, NULL); + } } else if (DEBUG(JOB)) { if (job->node != lastNode) { MESSAGE(stdout, job->node); @@ -1225,8 +1226,8 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) static const char msg[] = ": don't know how to make"; if (gn->flags & FROM_DEPEND) { - fprintf(stdout, "%s: ignoring stale .depend for %s\n", - progname, gn->name); + fprintf(stdout, "%s: ignoring stale %s for %s\n", + progname, makeDependfile, gn->name); return TRUE; } @@ -1301,11 +1302,7 @@ JobExec(Job *job, char **argv) /* Pre-emptively mark job running, pid still zero though */ job->job_state = JOB_ST_RUNNING; -#if defined(__minix) - cpid = fork(); -#else - cpid = vfork(); -#endif + cpid = vFork(); if (cpid == -1) Punt("Cannot vfork: %s", strerror(errno)); @@ -1559,11 +1556,7 @@ JobStart(GNode *gn, int flags) } JobSigLock(&mask); - tfile = bmake_malloc(strlen(tmpdir) + sizeof(TMPPAT)); - strcpy(tfile, tmpdir); - strcat(tfile, TMPPAT); - if ((tfd = mkstemp(tfile)) == -1) - Punt("Could not create temporary file %s", strerror(errno)); + tfd = mkTempFile(TMPPAT, &tfile); if (!DEBUG(SCRIPT)) (void)eunlink(tfile); JobSigUnlock(&mask); @@ -1901,7 +1894,7 @@ JobRun(GNode *targ) #else Compat_Make(targ, targ); if (targ->made == ERROR) { - PrintOnError("\n\nStop."); + PrintOnError(targ, "\n\nStop."); exit(1); } #endif @@ -2126,8 +2119,6 @@ void Job_Init(void) { GNode *begin; /* node for commands to do at the very start */ - const char *p; - size_t len; /* Allocate space for all the job info */ job_table = bmake_malloc(maxJobs * sizeof *job_table); @@ -2140,18 +2131,6 @@ Job_Init(void) lastNode = NULL; - /* set tmpdir, and ensure that it ends with "/" */ - p = getenv("TMPDIR"); - if (p == NULL || *p == '\0') { - p = _PATH_TMP; - } - len = strlen(p); - tmpdir = bmake_malloc(len + 2); - strcpy(tmpdir, p); - if (tmpdir[len - 1] != '/') { - strcat(tmpdir, "/"); - } - if (maxJobs == 1) { /* * If only one job can run at a time, there's no need for a banner, @@ -2195,13 +2174,13 @@ Job_Init(void) /* * Install a SIGCHLD handler. */ - (void)signal(SIGCHLD, JobChildSig); + (void)bmake_signal(SIGCHLD, JobChildSig); sigaddset(&caught_signals, SIGCHLD); #define ADDSIG(s,h) \ - if (signal(s, SIG_IGN) != SIG_IGN) { \ + if (bmake_signal(s, SIG_IGN) != SIG_IGN) { \ sigaddset(&caught_signals, s); \ - (void)signal(s, h); \ + (void)bmake_signal(s, h); \ } /* @@ -2231,7 +2210,7 @@ Job_Init(void) if (begin != NULL) { JobRun(begin); if (begin->made == ERROR) { - PrintOnError("\n\nStop."); + PrintOnError(begin, "\n\nStop."); exit(1); } } @@ -2242,7 +2221,7 @@ static void JobSigReset(void) { #define DELSIG(s) \ if (sigismember(&caught_signals, s)) { \ - (void)signal(s, SIG_DFL); \ + (void)bmake_signal(s, SIG_DFL); \ } DELSIG(SIGINT) @@ -2255,7 +2234,7 @@ static void JobSigReset(void) DELSIG(SIGWINCH) DELSIG(SIGCONT) #undef DELSIG - (void)signal(SIGCHLD, SIG_DFL); + (void)bmake_signal(SIGCHLD, SIG_DFL); } /*- diff --git a/commands/make/main.c b/commands/make/main.c index 54f4e6744..169778c10 100644 --- a/commands/make/main.c +++ b/commands/make/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.174 2009/09/09 17:09:49 sjg Exp $ */ +/* $NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,7 +69,7 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: main.c,v 1.174 2009/09/09 17:09:49 sjg Exp $"; +static char rcsid[] = "$NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $"; #else #include #ifndef lint @@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ #if 0 static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: main.c,v 1.174 2009/09/09 17:09:49 sjg Exp $"); +__RCSID("$NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -184,6 +184,8 @@ static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ static char curdir[MAXPATHLEN + 1]; /* startup directory */ static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ char *progname; /* the program name */ +char *makeDependfile; +pid_t myPid; Boolean forceJobs = FALSE; @@ -384,6 +386,7 @@ rearg: case 'B': compatMake = TRUE; Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); + Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); break; case 'C': if (chdir(argvalue) == -1) { @@ -393,6 +396,10 @@ rearg: strerror(errno)); exit(1); } + if (getcwd(curdir, MAXPATHLEN) == NULL) { + (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); + exit(2); + } ignorePWD = TRUE; break; case 'D': @@ -495,6 +502,7 @@ rearg: } Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); maxJobTokens = maxJobs; break; case 'k': @@ -509,7 +517,6 @@ rearg: found_path, sizeof(found_path))) break; /* nothing doing */ (void)Dir_AddDir(sysIncPath, found_path); - } else { (void)Dir_AddDir(sysIncPath, argvalue); } @@ -677,6 +684,22 @@ ReadAllMakefiles(const void *p, const void *q) return (ReadMakefile(p, q) == 0); } +static int +str2Lst_Append(Lst lp, char *str, const char *sep) +{ + char *cp; + int n; + + if (!sep) + sep = " \t"; + + for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { + (void)Lst_AtEnd(lp, cp); + n++; + } + return (n); +} + #ifdef SIGINFO /*ARGSUSED*/ static void @@ -693,6 +716,27 @@ siginfo(int signo) } #endif +/* + * Allow makefiles some control over the mode we run in. + */ +void +MakeMode(const char *mode) +{ + char *mp = NULL; + + if (!mode) + mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", VAR_GLOBAL, 0); + + if (mode && *mode) { + if (strstr(mode, "compat")) { + compatMake = TRUE; + forceJobs = FALSE; + } + } + if (mp) + free(mp); +} + /*- * main -- * The main function, for obvious reasons. Initializes variables @@ -735,7 +779,7 @@ main(int argc, char **argv) debug_file = stderr; #ifdef SIGINFO - (void)signal(SIGINFO, siginfo); + (void)bmake_signal(SIGINFO, siginfo); #endif /* * Set the seed to produce a different random sequence @@ -799,6 +843,8 @@ main(int argc, char **argv) #endif } + myPid = getpid(); /* remember this for vFork() */ + /* * Just in case MAKEOBJDIR wants us to do something tricky. */ @@ -810,6 +856,15 @@ main(int argc, char **argv) Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); #endif Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ + /* + * This is the traditional preference for makefiles. + */ +#ifndef MAKEFILE_PREFERENCE_LIST +# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" +#endif + Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, + VAR_GLOBAL, 0); + Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); create = Lst_Init(FALSE); makefiles = Lst_Init(FALSE); @@ -845,8 +900,24 @@ main(int argc, char **argv) * MFLAGS also gets initialized empty, for compatibility. */ Parse_Init(); - Var_Set("MAKE", argv[0], VAR_GLOBAL, 0); - Var_Set(".MAKE", argv[0], VAR_GLOBAL, 0); + if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { + /* + * Leave alone if it is an absolute path, or if it does + * not contain a '/' in which case we need to find it in + * the path, like execvp(3) and the shells do. + */ + p1 = argv[0]; + } else { + /* + * A relative path, canonicalize it. + */ + p1 = realpath(argv[0], mdpath); + if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { + p1 = argv[0]; /* realpath failed */ + } + } + Var_Set("MAKE", p1, VAR_GLOBAL, 0); + Var_Set(".MAKE", p1, VAR_GLOBAL, 0); Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); Var_Set("MFLAGS", "", VAR_GLOBAL, 0); @@ -863,7 +934,7 @@ main(int argc, char **argv) ep = "0"; } Var_Set(MAKE_LEVEL, ep, VAR_GLOBAL, 0); - snprintf(tmp, sizeof(tmp), "%u", getpid()); + snprintf(tmp, sizeof(tmp), "%u", myPid); Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); snprintf(tmp, sizeof(tmp), "%u", getppid()); Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); @@ -881,18 +952,20 @@ main(int argc, char **argv) Main_ParseArgLine(getenv("MAKE")); #endif - MainParseArgs(argc, argv); - /* - * Find where we are (now) and take care of PWD for the automounter... - * All this code is so that we know where we are when we start up - * on a different machine with pmake. + * Find where we are (now). + * We take care of PWD for the automounter below... */ if (getcwd(curdir, MAXPATHLEN) == NULL) { (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); exit(2); } + MainParseArgs(argc, argv); + + /* + * Verify that cwd is sane. + */ if (stat(curdir, &sa) == -1) { (void)fprintf(stderr, "%s: %s: %s.\n", progname, curdir, strerror(errno)); @@ -900,6 +973,8 @@ main(int argc, char **argv) } /* + * All this code is so that we know where we are when we start up + * on a different machine with pmake. * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX * since the value of curdir can vary depending on how we got * here. Ie sitting at a shell prompt (shell that provides $PWD) @@ -1044,16 +1119,27 @@ main(int argc, char **argv) if (ln != NULL) Fatal("%s: cannot open %s.", progname, (char *)Lst_Datum(ln)); - } else if (ReadMakefile("makefile", NULL) != 0) - (void)ReadMakefile("Makefile", NULL); + } else { + p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", + VAR_CMD, 0); + if (p1) { + (void)str2Lst_Append(makefiles, p1, NULL); + (void)Lst_Find(makefiles, NULL, ReadMakefile); + free(p1); + } + } /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ if (!noBuiltins || !printVars) { - doing_depend = TRUE; - (void)ReadMakefile(".depend", NULL); - doing_depend = FALSE; + makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", + VAR_CMD, 0); + doing_depend = TRUE; + (void)ReadMakefile(makeDependfile, NULL); + doing_depend = FALSE; } + MakeMode(NULL); + Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); if (p1) free(p1); @@ -1212,14 +1298,11 @@ ReadMakefile(const void *p, const void *q __unused) int fd; size_t len = MAXPATHLEN; char *name, *path = bmake_malloc(len); - int setMAKEFILE; if (!strcmp(fname, "-")) { Parse_File("(stdin)", dup(fileno(stdin))); Var_Set("MAKEFILE", "", VAR_GLOBAL, 0); } else { - setMAKEFILE = strcmp(fname, ".depend"); - /* if we've chdir'd, rebuild the path name */ if (strcmp(curdir, objdir) && *fname != '/') { size_t plen = strlen(curdir) + strlen(fname) + 2; @@ -1266,7 +1349,7 @@ ReadMakefile(const void *p, const void *q __unused) * makefile specified, as it is set by SysV make. */ found: - if (setMAKEFILE) + if (!doing_depend) Var_Set("MAKEFILE", fname, VAR_GLOBAL, 0); Parse_File(fname, fd); } @@ -1509,11 +1592,7 @@ Cmd_Exec(const char *cmd, const char **errnum) /* * Fork */ -#if defined(__minix) - switch (cpid = fork()) { -#else - switch (cpid = vfork()) { -#endif + switch (cpid = vFork()) { case 0: /* * Close input side of pipe @@ -1624,6 +1703,7 @@ Error(const char *fmt, ...) err_file = debug_file; if (err_file == stdout) err_file = stderr; + (void)fflush(stdout); for (;;) { va_start(ap, fmt); fprintf(err_file, "%s: ", progname); @@ -1658,12 +1738,13 @@ Fatal(const char *fmt, ...) if (jobsRunning) Job_Wait(); + (void)fflush(stdout); (void)vfprintf(stderr, fmt, ap); va_end(ap); (void)fprintf(stderr, "\n"); (void)fflush(stderr); - PrintOnError(NULL); + PrintOnError(NULL, NULL); if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) Targ_PrintGraph(2); @@ -1689,13 +1770,14 @@ Punt(const char *fmt, ...) va_list ap; va_start(ap, fmt); + (void)fflush(stdout); (void)fprintf(stderr, "%s: ", progname); (void)vfprintf(stderr, fmt, ap); va_end(ap); (void)fprintf(stderr, "\n"); (void)fflush(stderr); - PrintOnError(NULL); + PrintOnError(NULL, NULL); DieHorribly(); } @@ -1816,22 +1898,40 @@ PrintAddr(void *a, void *b) void -PrintOnError(const char *s) +PrintOnError(GNode *gn, const char *s) { + static GNode *en = NULL; char tmp[64]; char *cp; if (s) - printf("%s", s); + printf("%s", s); printf("\n%s: stopped in %s\n", progname, curdir); + + if (en) + return; /* we've been here! */ + if (gn) { + /* + * We can print this even if there is no .ERROR target. + */ + Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); + } strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", sizeof(tmp) - 1); cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); if (cp) { - if (*cp) - printf("%s", cp); - free(cp); + if (*cp) + printf("%s", cp); + free(cp); + } + /* + * Finally, see if there is a .ERROR target, and run it if so. + */ + en = Targ_FindNode(".ERROR", TARG_NOCREATE); + if (en) { + en->type |= OP_SPECIAL; + Compat_Make(en, en); } } @@ -1857,3 +1957,46 @@ Main_ExportMAKEFLAGS(Boolean first) #endif } } + +/* + * Create and open a temp file using "pattern". + * If "fnamep" is provided set it to a copy of the filename created. + * Otherwise unlink the file once open. + */ +int +mkTempFile(const char *pattern, char **fnamep) +{ + static char *tmpdir = NULL; + char tfile[MAXPATHLEN]; + int fd; + + if (!pattern) + pattern = TMPPAT; + + if (!tmpdir) { + struct stat st; + + /* + * Honor $TMPDIR but only if it is valid. + * Ensure it ends with /. + */ + tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 0); + if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { + free(tmpdir); + tmpdir = bmake_strdup(_PATH_TMP); + } + } + if (pattern[0] == '/') { + snprintf(tfile, sizeof(tfile), "%s", pattern); + } else { + snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); + } + if ((fd = mkstemp(tfile)) < 0) + Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); + if (fnamep) { + *fnamep = bmake_strdup(tfile); + } else { + unlink(tfile); /* we just want the descriptor */ + } + return fd; +} diff --git a/commands/make/make.1 b/commands/make/make.1 index ccc90e229..a5aed6740 100644 --- a/commands/make/make.1 +++ b/commands/make/make.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.166 2009/11/19 06:48:37 wiz Exp $ +.\" $NetBSD: make.1,v 1.176 2010/06/10 18:35:22 wiz Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd November 15, 2009 +.Dd June 9, 2010 .Dt MAKE 1 .Os .Sh NAME @@ -536,11 +536,48 @@ If the result of expanding a variable contains a dollar sign .Pq Ql \&$ the string is expanded again. .Pp -Variable substitution occurs at two distinct times, depending on where +Variable substitution occurs at three distinct times, depending on where the variable is being used. +.Bl -enum +.It Variables in dependency lines are expanded as the line is read. +.It Variables in shell commands are expanded when the shell command is executed. +.It +.Dq .for +loop index variables are expanded on each loop iteration. +Note that other variables are not expanded inside loops so +the following example code: +.Bd -literal -offset indent + +.Dv .for i in 1 2 3 +a+= ${i} +j= ${i} +b+= ${j} +.Dv .endfor + +all: + @echo ${a} + @echo ${b} + +.Ed +will print: +.Bd -literal -offset indent +1 2 3 +3 3 3 + +.Ed +Because while ${a} contains +.Dq 1 2 3 +after the loop is executed, ${b} +contains +.Dq ${j} ${j} ${j} +which expands to +.Dq 3 3 3 +since after the loop completes ${j} contains +.Dq 3 . +.El .Ss Variable classes The four different classes of variables (in order of increasing precedence) are: @@ -652,31 +689,17 @@ The preferred variable to use is the environment variable because it is more compatible with other versions of .Nm and cannot be confused with the special target with the same name. +.It Va .MAKE.DEPENDFILE +Names the makefile (default +.Ql Pa .depend ) +from which generated dependencies are read. .It Va .MAKE.EXPORTED The list of variables exported by .Nm . -.It Va .MAKE.MAKEFILES -The list of makefiles read by -.Nm , -which is useful for tracking dependencies. -Each makefile is recorded only once, regardless of the number of times read. -.It Va .MAKE.LEVEL -The recursion depth of -.Nm . -The initial instance of -.Nm -will be 0, and an incremented value is put into the environment -to be seen by the next generation. -This allows tests like: -.Li .if ${.MAKE.LEVEL} == 0 -to protect things which should only be evaluated in the initial instance of -.Nm . -.It Va .MAKE.PID -The process-id of -.Nm . -.It Va .MAKE.PPID -The parent process-id of -.Nm . +.It Va .MAKE.JOBS +The argument to the +.Fl j +option. .It Va .MAKE.JOB.PREFIX If .Nm @@ -707,6 +730,38 @@ variable which is then entered into the environment for all programs which .Nm executes. +.It Va .MAKE.LEVEL +The recursion depth of +.Nm . +The initial instance of +.Nm +will be 0, and an incremented value is put into the environment +to be seen by the next generation. +This allows tests like: +.Li .if ${.MAKE.LEVEL} == 0 +to protect things which should only be evaluated in the initial instance of +.Nm . +.It Va .MAKE.MAKEFILE_PREFERENCE +The ordered list of makefile names +(default +.Ql Pa makefile , +.Ql Pa Makefile ) +that +.Nm +will look for. +.It Va .MAKE.MAKEFILES +The list of makefiles read by +.Nm , +which is useful for tracking dependencies. +Each makefile is recorded only once, regardless of the number of times read. +.It Va .MAKE.MODE +Processed after reading all makefiles. +Can affect the mode that +.Nm +runs in. +Currently just +.Ql Pa compat +mode. .It Va .MAKEOVERRIDES This variable is used to record the names of variables assigned to on the command line, so that they may be exported as part of @@ -721,6 +776,12 @@ by appending their names to is re-exported whenever .Ql Va .MAKEOVERRIDES is modified. +.It Va .MAKE.PID +The process-id of +.Nm . +.It Va .MAKE.PPID +The parent process-id of +.Nm . .It Va MAKE_PRINT_VAR_ON_ERROR When .Nm @@ -767,8 +828,10 @@ is set in the environment or on the command line.) .Pp Variable expansion is performed on the value before it's used, so expressions such as -.Dl ${.CURDIR:C,^/usr/src,/var/obj,} +.Dl ${.CURDIR:S,^/usr/src,/var/obj,} may be used. +This is especially useful with +.Ql Ev MAKEOBJDIR . .Pp .Ql Va .OBJDIR may be modified in the makefile as a global variable. @@ -878,7 +941,7 @@ The standard shell wildcard characters .Pf ( Ql * , .Ql \&? , and -.Ql Op ) +.Ql Oo Oc ) may be used. The wildcard characters may be escaped with a backslash @@ -925,6 +988,10 @@ safely through recursive invocations of .Nm . .It Cm \&:R Replaces each word in the variable with everything but its suffix. +.It Cm \&:tA +Attempt to convert variable to an absolute path using +.Xr realpath 3 , +if that fails, the value is unchanged. .It Cm \&:tl Converts variable to lower-case letters. .It Cm \&:ts Ns Ar c @@ -934,6 +1001,7 @@ This modifier sets the separator to the character If .Ar c is omitted, then no separator is used. +The common escapes (including octal numeric codes), work as expected. .It Cm \&:tu Converts variable to upper-case letters. .It Cm \&:tW @@ -1274,6 +1342,11 @@ Conditional expressions are also preceded by a single dot as the first character of a line. The possible conditionals are as follows: .Bl -tag -width Ds +.It Ic .error Ar message +The message is printed along with the name of the makefile and line number, +then +.Nm +will exit. .It Ic .export Ar variable ... Export the specified global variable. If no variable list is provided, all globals are exported @@ -1286,6 +1359,20 @@ flag, so should be used with caution. Appending a variable name to .Va .MAKE.EXPORTED is equivalent to exporting a variable. +.It Ic .export-env Ar variable ... +The same as +.Ql .export , +except that the variable is not appended to +.Va .MAKE.EXPORTED . +This allows exporting a value to the environment which is different from that +used by +.Nm +internally. +.It Ic .info Ar message +The message is printed along with the name of the makefile and line number. +.It Ic .undef Ar variable +Un-define the specified global variable. +Only global variables may be un-defined. .It Ic .unexport Ar variable ... The opposite of .Ql .export . @@ -1322,9 +1409,10 @@ which is the minimal useful environment. Actually .Ql Ev .MAKE.LEVEL will also be pushed into the new environment. -.It Ic .undef Ar variable -Un-define the specified global variable. -Only global variables may be un-defined. +.It Ic .warning Ar message +The message prefixed by +.Ql Pa warning: +is printed along with the name of the makefile and line number. .It Ic \&.if Oo \&! Oc Ns Ar expression Op Ar operator expression ... Test the value of an expression. .It Ic .ifdef Oo \&! Oc Ns Ar variable Op Ar operator variable ... @@ -1627,6 +1715,13 @@ to the target's own name. .It Ic .END Any command lines attached to this target are executed after everything else is done. +.It Ic .ERROR +Any command lines attached to this target are executed when another target fails. +The +.Ic .ERROR_TARGET +variable is set to the target that failed. +See also +.Ic MAKE_PRINT_VAR_ON_ERROR . .It Ic .IGNORE Mark each of the sources with the .Ic .IGNORE @@ -1750,10 +1845,10 @@ character when used outside of any quoting characters. .El Example: .Bd -literal -\&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \\ - check="set -e" ignore="set +e" \\ - echo="set -v" quiet="set +v" filter="set +v" \\ - echoFlag=v errFlag=e newline="'\\n'" +\&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \e + check="set -e" ignore="set +e" \e + echo="set -v" quiet="set +v" filter="set +v" \e + echoFlag=v errFlag=e newline="'\en'" .Ed .It Ic .SILENT Apply the diff --git a/commands/make/make.c b/commands/make/make.c index aa8f8bcd7..11e2ca8cb 100644 --- a/commands/make/make.c +++ b/commands/make/make.c @@ -1,4 +1,4 @@ -/* $NetBSD: make.c,v 1.78 2009/01/23 21:26:30 dsl Exp $ */ +/* $NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: make.c,v 1.78 2009/01/23 21:26:30 dsl Exp $"; +static char rcsid[] = "$NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: make.c,v 1.78 2009/01/23 21:26:30 dsl Exp $"); +__RCSID("$NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -958,6 +958,9 @@ MakeAddAllSrc(void *cgnp, void *pgnp) void Make_DoAllVar(GNode *gn) { + if (gn->flags & DONE_ALLSRC) + return; + Lst_ForEach(gn->children, MakeUnmark, gn); Lst_ForEach(gn->children, MakeAddAllSrc, gn); @@ -974,6 +977,7 @@ Make_DoAllVar(GNode *gn) if (p1) free(p1); } + gn->flags |= DONE_ALLSRC; } /*- diff --git a/commands/make/make.h b/commands/make/make.h index 582dae4c3..d770586d6 100644 --- a/commands/make/make.h +++ b/commands/make/make.h @@ -1,4 +1,4 @@ -/* $NetBSD: make.h,v 1.79 2009/09/08 17:29:20 sjg Exp $ */ +/* $NetBSD: make.h,v 1.82 2010/04/23 00:18:50 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -164,6 +164,7 @@ typedef struct GNode { #define DONE_WAIT 0x8 /* Set by Make_ProcessWait() */ #define DONE_ORDER 0x10 /* Build requested by .ORDER processing */ #define FROM_DEPEND 0x20 /* Node created from .depend */ +#define DONE_ALLSRC 0x40 /* We do it once only */ #define CYCLE 0x1000 /* Used by MakePrintStatus */ #define DONECYCLE 0x2000 /* Used by MakePrintStatus */ enum enum_made { @@ -392,6 +393,18 @@ extern Lst sysIncPath; /* The system include path. */ extern Lst defIncPath; /* The default include path. */ extern char *progname; /* The program name */ +extern char *makeDependfile; /* .depend */ + +/* + * We cannot vfork() in a child of vfork(). + * Most systems do not enforce this but some do. + */ +#if defined(__minix) +#define vFork() fork() +#else +#define vFork() ((getpid() == myPid) ? vfork() : fork()) +#endif +extern pid_t myPid; #define MAKEFLAGS ".MAKEFLAGS" #define MAKEOVERRIDES ".MAKEOVERRIDES" @@ -399,6 +412,9 @@ extern char *progname; /* The program name */ #define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */ #define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all the makefiles we read */ #define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */ +#define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE" +#define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */ +#define MAKE_MODE ".MAKE.MODE" /* * debug control: @@ -442,9 +458,10 @@ void Make_DoAllVar(GNode *); Boolean Make_Run(Lst); char * Check_Cwd_Cmd(const char *); void Check_Cwd(const char **); -void PrintOnError(const char *); +void PrintOnError(GNode *, const char *); void Main_ExportMAKEFLAGS(Boolean); Boolean Main_SetObjdir(const char *); +int mkTempFile(const char *, char **); #ifdef __GNUC__ #define UNCONST(ptr) ({ \ diff --git a/commands/make/nonints.h b/commands/make/nonints.h index c22307cb5..f49759a70 100644 --- a/commands/make/nonints.h +++ b/commands/make/nonints.h @@ -1,4 +1,4 @@ -/* $NetBSD: nonints.h,v 1.57 2009/11/19 00:30:24 sjg Exp $ */ +/* $NetBSD: nonints.h,v 1.59 2010/06/03 15:40:16 sjg Exp $ */ /*- * Copyright (c) 1988, 1989, 1990, 1993 @@ -108,6 +108,7 @@ void For_Run(int); /* main.c */ void Main_ParseArgLine(const char *); +void MakeMode(const char *); int main(int, char **); char *Cmd_Exec(const char *, const char **); void Error(const char *, ...) __attribute__((__format__(__printf__, 1, 2))); @@ -194,3 +195,6 @@ void Var_Dump(GNode *); void Var_ExportVars(void); void Var_Export(char *, int); void Var_UnExport(char *); + +/* util.c */ +void (*bmake_signal(int, void (*)(int)))(int); diff --git a/commands/make/parse.c b/commands/make/parse.c index 49bc79cd9..7c6538e09 100644 --- a/commands/make/parse.c +++ b/commands/make/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.160 2009/11/19 00:30:25 sjg Exp $ */ +/* $NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: parse.c,v 1.160 2009/11/19 00:30:25 sjg Exp $"; +static char rcsid[] = "$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: parse.c,v 1.160 2009/11/19 00:30:25 sjg Exp $"); +__RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -191,6 +191,7 @@ typedef enum { Begin, /* .BEGIN */ Default, /* .DEFAULT */ End, /* .END */ + dotError, /* .ERROR */ Ignore, /* .IGNORE */ Includes, /* .INCLUDES */ Interrupt, /* .INTERRUPT */ @@ -245,6 +246,7 @@ static struct { { ".BEGIN", Begin, 0 }, { ".DEFAULT", Default, 0 }, { ".END", End, 0 }, +{ ".ERROR", dotError, 0 }, { ".EXEC", Attribute, OP_EXEC }, { ".IGNORE", Ignore, OP_IGNORE }, { ".INCLUDES", Includes, 0 }, @@ -449,6 +451,7 @@ ParseErrorInternal(const char *cfname, size_t clineno, int type, va_list ap; va_start(ap, fmt); + (void)fflush(stdout); ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap); va_end(ap); @@ -487,6 +490,7 @@ Parse_Error(int type, const char *fmt, ...) } va_start(ap, fmt); + (void)fflush(stdout); ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap); va_end(ap); @@ -497,6 +501,53 @@ Parse_Error(int type, const char *fmt, ...) } } + +/* + * ParseMessage + * Parse a .info .warning or .error directive + * + * The input is the line minus the ".". We substitute + * variables, print the message and exit(1) (for .error) or just print + * a warning if the directive is malformed. + */ +static Boolean +ParseMessage(char *line) +{ + int mtype; + + switch(*line) { + case 'i': + mtype = 0; + break; + case 'w': + mtype = PARSE_WARNING; + break; + case 'e': + mtype = PARSE_FATAL; + break; + default: + Parse_Error(PARSE_WARNING, "invalid syntax: \".%s\"", line); + return FALSE; + } + + while (isalpha((u_char)*line)) + line++; + if (!isspace((u_char)*line)) + return FALSE; /* not for us */ + while (isspace((u_char)*line)) + line++; + + line = Var_Subst(NULL, line, VAR_CMD, 0); + Parse_Error(mtype, "%s", line); + free(line); + + if (mtype == PARSE_FATAL) { + /* Terminate immediately. */ + exit(1); + } + return TRUE; +} + /*- *--------------------------------------------------------------------- * ParseLinkSrc -- @@ -973,6 +1024,7 @@ ParseDoDependency(char *line) * .NOPATH Don't search for file in the path * .BEGIN * .END + * .ERROR * .INTERRUPT Are not to be considered the * main target. * .NOTPARALLEL Make only one target at a time. @@ -993,6 +1045,7 @@ ParseDoDependency(char *line) break; case Begin: case End: + case dotError: case Interrupt: gn = Targ_FindNode(line, TARG_CREATE); gn->type |= OP_NOTMAIN|OP_SPECIAL; @@ -1122,6 +1175,7 @@ ParseDoDependency(char *line) case Default: case Begin: case End: + case dotError: case Interrupt: /* * These four create nodes on which to hang commands, so @@ -2513,7 +2567,12 @@ Parse_File(const char *name, int fd) } else if (strncmp(cp, "unexport", 8) == 0) { Var_UnExport(cp); continue; - } + } else if (strncmp(cp, "info", 4) == 0 || + strncmp(cp, "error", 5) == 0 || + strncmp(cp, "warning", 7) == 0) { + if (ParseMessage(cp)) + continue; + } } if (*line == '\t') { @@ -2658,10 +2717,11 @@ Parse_File(const char *name, int fd) } while (ParseEOF() == CONTINUE); if (fatals) { + (void)fflush(stdout); (void)fprintf(stderr, "%s: Fatal errors encountered -- cannot continue\n", progname); - PrintOnError(NULL); + PrintOnError(NULL, NULL); exit(1); } } diff --git a/commands/make/util.c b/commands/make/util.c index 5b51e2c2b..3c27089d3 100644 --- a/commands/make/util.c +++ b/commands/make/util.c @@ -1,15 +1,15 @@ -/* $NetBSD: util.c,v 1.48 2009/01/29 09:03:04 dholland Exp $ */ +/* $NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $ */ /* * Missing stuff from OS's */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: util.c,v 1.48 2009/01/29 09:03:04 dholland Exp $"; +static char rcsid[] = "$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $"; #else #include #ifndef lint -__RCSID("$NetBSD: util.c,v 1.48 2009/01/29 09:03:04 dholland Exp $"); +__RCSID("$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $"); #endif #endif @@ -18,6 +18,7 @@ __RCSID("$NetBSD: util.c,v 1.48 2009/01/29 09:03:04 dholland Exp $"); #include #include #include +#include #include "make.h" @@ -231,24 +232,6 @@ random(void) } #endif -/* turn into bsd signals */ -void (* -signal(int s, void (*a)(int)))(int) -{ - struct sigvec osv, sv; - - (void)sigvector(s, NULL, &osv); - sv = osv; - sv.sv_handler = a; -#ifdef SV_BSDSIG - sv.sv_flags = SV_BSDSIG; -#endif - - if (sigvector(s, &sv, NULL) == -1) - return (BADSIG); - return (osv.sv_handler); -} - #if !defined(__hpux__) && !defined(__hpux) int utimes(char *file, struct timeval tvp[2]) @@ -370,12 +353,9 @@ getwd(char *pathname) } /* end getwd */ #endif /* __hpux */ -#if defined(sun) && defined(__svr4__) -#include - -/* turn into bsd signals */ +/* force posix signals */ void (* -signal(int s, void (*a)(int)))(int) +bmake_signal(int s, void (*a)(int)))(int) { struct sigaction sa, osa; @@ -388,7 +368,6 @@ signal(int s, void (*a)(int)))(int) else return osa.sa_handler; } -#endif #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF) #include diff --git a/commands/make/var.c b/commands/make/var.c index ec5a57622..d644674c7 100644 --- a/commands/make/var.c +++ b/commands/make/var.c @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.155 2009/11/19 00:30:25 sjg Exp $ */ +/* $NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: var.c,v 1.155 2009/11/19 00:30:25 sjg Exp $"; +static char rcsid[] = "$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: var.c,v 1.155 2009/11/19 00:30:25 sjg Exp $"); +__RCSID("$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $"); #endif #endif /* not lint */ #endif @@ -123,6 +123,7 @@ __RCSID("$NetBSD: var.c,v 1.155 2009/11/19 00:30:25 sjg Exp $"); * XXX: There's a lot of duplication in these functions. */ +#include #ifndef NO_REGEX #include #include @@ -590,6 +591,13 @@ Var_Export1(const char *name, int parent) v->flags |= (VAR_EXPORTED|VAR_REEXPORT); return 1; } + if (v->flags & VAR_IN_USE) { + /* + * We recursed while exporting in a child. + * This isn't going to end well, just skip it. + */ + return 0; + } n = snprintf(tmp, sizeof(tmp), "${%s}", name); if (n < (int)sizeof(tmp)) { val = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); @@ -674,6 +682,7 @@ Var_Export(char *str, int isExport) char *val; char **av; char *as; + int track; int ac; int i; @@ -682,6 +691,12 @@ Var_Export(char *str, int isExport) return; } + if (strncmp(str, "-env", 4) == 0) { + track = 0; + str += 4; + } else { + track = VAR_EXPORT_PARENT; + } val = Var_Subst(NULL, str, VAR_GLOBAL, 0); av = brk_string(val, &ac, FALSE, &as); for (i = 0; i < ac; i++) { @@ -701,10 +716,10 @@ Var_Export(char *str, int isExport) continue; } } - if (Var_Export1(name, VAR_EXPORT_PARENT)) { + if (Var_Export1(name, track)) { if (VAR_EXPORTED_ALL != var_exportedVars) var_exportedVars = VAR_EXPORTED_YES; - if (isExport) { + if (isExport && track) { Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); } } @@ -1859,6 +1874,33 @@ VarSelectWords(GNode *ctx __unused, Var_Parse_State *vpstate, return Buf_Destroy(&buf, FALSE); } + +/*- + * VarRealpath -- + * Replace each word with the result of realpath() + * if successful. + */ +static Boolean +VarRealpath(GNode *ctx __unused, Var_Parse_State *vpstate, + char *word, Boolean addSpace, Buffer *buf, + void *patternp __unused) +{ + struct stat st; + char rbuf[MAXPATHLEN]; + char *rp; + + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + rp = realpath(word, rbuf); + if (rp && *rp == '/' && stat(rp, &st) == 0) + word = rp; + + Buf_AddBytes(buf, strlen(word), word); + return(addSpace); +} + /*- *----------------------------------------------------------------------- * VarModify -- @@ -2849,7 +2891,12 @@ ApplyModifiers(char *nstr, const char *tstr, * Check for two-character options: * ":tu", ":tl" */ - if (tstr[1] == 'u' || tstr[1] == 'l') { + if (tstr[1] == 'A') { /* absolute path */ + newStr = VarModify(ctxt, &parsestate, nstr, + VarRealpath, NULL); + cp = tstr + 2; + termc = *cp; + } else if (tstr[1] == 'u' || tstr[1] == 'l') { newStr = VarChangeCase(nstr, (tstr[1] == 'u')); cp = tstr + 2; termc = *cp;