-# $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
# 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}
-# $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
# 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}
-/* $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.
*/
#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 <sys/cdefs.h>
#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
/*
* 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");
}
} else if (keepgoing) {
pgn->flags &= ~REMAKE;
} else {
- PrintOnError("\n\nStop.");
+ PrintOnError(gn, "\n\nStop.");
exit(1);
}
} else if (gn->made == ERROR) {
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);
if (gn != NULL) {
Compat_Make(gn, gn);
if (gn->made == ERROR) {
- PrintOnError("\n\nStop.");
+ PrintOnError(gn, "\n\nStop.");
exit(1);
}
}
if (errors == 0) {
Compat_Make(ENDNode, ENDNode);
if (gn->made == ERROR) {
- PrintOnError("\n\nStop.");
+ PrintOnError(gn, "\n\nStop.");
exit(1);
}
}
-/* $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.
*/
#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 <sys/cdefs.h>
#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
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.
-/* $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.
*/
#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 <sys/cdefs.h>
#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
#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);
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);
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;
}
/* 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));
}
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);
#else
Compat_Make(targ, targ);
if (targ->made == ERROR) {
- PrintOnError("\n\nStop.");
+ PrintOnError(targ, "\n\nStop.");
exit(1);
}
#endif
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);
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,
/*
* 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); \
}
/*
if (begin != NULL) {
JobRun(begin);
if (begin->made == ERROR) {
- PrintOnError("\n\nStop.");
+ PrintOnError(begin, "\n\nStop.");
exit(1);
}
}
{
#define DELSIG(s) \
if (sigismember(&caught_signals, s)) { \
- (void)signal(s, SIG_DFL); \
+ (void)bmake_signal(s, SIG_DFL); \
}
DELSIG(SIGINT)
DELSIG(SIGWINCH)
DELSIG(SIGCONT)
#undef DELSIG
- (void)signal(SIGCHLD, SIG_DFL);
+ (void)bmake_signal(SIGCHLD, SIG_DFL);
}
/*-
-/* $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
*/
#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 <sys/cdefs.h>
#ifndef lint
#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
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;
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) {
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':
}
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':
found_path, sizeof(found_path)))
break; /* nothing doing */
(void)Dir_AddDir(sysIncPath, found_path);
-
} else {
(void)Dir_AddDir(sysIncPath, argvalue);
}
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
}
#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
debug_file = stderr;
#ifdef SIGINFO
- (void)signal(SIGINFO, siginfo);
+ (void)bmake_signal(SIGINFO, siginfo);
#endif
/*
* Set the seed to produce a different random sequence
#endif
}
+ myPid = getpid(); /* remember this for vFork() */
+
/*
* Just in case MAKEOBJDIR wants us to do something tricky.
*/
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);
* 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);
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);
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));
}
/*
+ * 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)
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);
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;
* 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);
}
/*
* Fork
*/
-#if defined(__minix)
- switch (cpid = fork()) {
-#else
- switch (cpid = vfork()) {
-#endif
+ switch (cpid = vFork()) {
case 0:
/*
* Close input side of pipe
err_file = debug_file;
if (err_file == stdout)
err_file = stderr;
+ (void)fflush(stdout);
for (;;) {
va_start(ap, fmt);
fprintf(err_file, "%s: ", progname);
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);
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();
}
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);
}
}
#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;
+}
-.\" $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.
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd November 15, 2009
+.Dd June 9, 2010
.Dt MAKE 1
.Os
.Sh NAME
.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:
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
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
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
.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.
.Pf ( Ql * ,
.Ql \&? ,
and
-.Ql Op )
+.Ql Oo Oc )
may
be used.
The wildcard characters may be escaped with a backslash
.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
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
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
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 .
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 ...
.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
.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
-/* $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
*/
#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 <sys/cdefs.h>
#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
void
Make_DoAllVar(GNode *gn)
{
+ if (gn->flags & DONE_ALLSRC)
+ return;
+
Lst_ForEach(gn->children, MakeUnmark, gn);
Lst_ForEach(gn->children, MakeAddAllSrc, gn);
if (p1)
free(p1);
}
+ gn->flags |= DONE_ALLSRC;
}
\f
/*-
-/* $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
#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 {
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"
#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:
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) ({ \
-/* $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
/* 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)));
void Var_ExportVars(void);
void Var_Export(char *, int);
void Var_UnExport(char *);
+
+/* util.c */
+void (*bmake_signal(int, void (*)(int)))(int);
-/* $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
*/
#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 <sys/cdefs.h>
#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
Begin, /* .BEGIN */
Default, /* .DEFAULT */
End, /* .END */
+ dotError, /* .ERROR */
Ignore, /* .IGNORE */
Includes, /* .INCLUDES */
Interrupt, /* .INTERRUPT */
{ ".BEGIN", Begin, 0 },
{ ".DEFAULT", Default, 0 },
{ ".END", End, 0 },
+{ ".ERROR", dotError, 0 },
{ ".EXEC", Attribute, OP_EXEC },
{ ".IGNORE", Ignore, OP_IGNORE },
{ ".INCLUDES", Includes, 0 },
va_list ap;
va_start(ap, fmt);
+ (void)fflush(stdout);
ParseVErrorInternal(stderr, cfname, clineno, type, fmt, ap);
va_end(ap);
}
va_start(ap, fmt);
+ (void)fflush(stdout);
ParseVErrorInternal(stderr, fname, lineno, type, fmt, ap);
va_end(ap);
}
}
+
+/*
+ * 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 --
* .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.
break;
case Begin:
case End:
+ case dotError:
case Interrupt:
gn = Targ_FindNode(line, TARG_CREATE);
gn->type |= OP_NOTMAIN|OP_SPECIAL;
case Default:
case Begin:
case End:
+ case dotError:
case Interrupt:
/*
* These four create nodes on which to hang commands, so
} 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') {
} 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);
}
}
-/* $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 <sys/cdefs.h>
#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
#include <errno.h>
#include <stdio.h>
#include <time.h>
+#include <signal.h>
#include "make.h"
}
#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])
} /* end getwd */
#endif /* __hpux */
-#if defined(sun) && defined(__svr4__)
-#include <signal.h>
-
-/* 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;
else
return osa.sa_handler;
}
-#endif
#if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
#include <stdarg.h>
-/* $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
*/
#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 <sys/cdefs.h>
#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
* XXX: There's a lot of duplication in these functions.
*/
+#include <sys/stat.h>
#ifndef NO_REGEX
#include <sys/types.h>
#include <regex.h>
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);
char *val;
char **av;
char *as;
+ int track;
int ac;
int i;
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++) {
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);
}
}
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 --
* 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;