2021-02-02 00:32:54 +03:00
|
|
|
/* $NetBSD: meta.c,v 1.170 2021/02/01 21:32:54 rillig Exp $ */
|
2011-03-31 02:03:49 +04:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* Implement 'meta' mode.
|
|
|
|
* Adapted from John Birrell's patches to FreeBSD make.
|
|
|
|
* --sjg
|
|
|
|
*/
|
|
|
|
/*
|
2016-02-27 03:13:21 +03:00
|
|
|
* Copyright (c) 2009-2016, Juniper Networks, Inc.
|
2010-09-13 19:36:57 +04:00
|
|
|
* Portions Copyright (c) 2009, John Birrell.
|
2020-07-03 11:13:23 +03:00
|
|
|
*
|
2010-09-13 19:36:57 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
2020-07-03 11:13:23 +03:00
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
2010-09-13 19:36:57 +04:00
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
2020-07-03 11:13:23 +03:00
|
|
|
* notice, this list of conditions and the following disclaimer.
|
2010-09-13 19:36:57 +04:00
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
2020-07-03 11:13:23 +03:00
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
2010-09-13 19:36:57 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
2020-07-03 11:13:23 +03:00
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2010-09-13 19:36:57 +04:00
|
|
|
*/
|
2010-09-14 01:31:59 +04:00
|
|
|
#if defined(USE_META)
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <errno.h>
|
2010-09-14 00:34:21 +04:00
|
|
|
#if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
|
2010-09-13 19:36:57 +04:00
|
|
|
#include <err.h>
|
2010-09-14 00:34:21 +04:00
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
#include "make.h"
|
2020-09-02 07:08:54 +03:00
|
|
|
#include "dir.h"
|
2010-09-13 19:36:57 +04:00
|
|
|
#include "job.h"
|
|
|
|
|
2020-01-19 22:42:32 +03:00
|
|
|
#ifdef USE_FILEMON
|
2020-01-19 22:49:36 +03:00
|
|
|
#include "filemon/filemon.h"
|
2019-12-19 10:14:07 +03:00
|
|
|
#endif
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
static BuildMon Mybm; /* for compat */
|
2020-11-30 00:28:06 +03:00
|
|
|
static StringList metaBailiwick = LST_INIT; /* our scope of control */
|
2016-03-08 00:45:43 +03:00
|
|
|
static char *metaBailiwickStr; /* string storage for the list */
|
2020-11-30 00:28:06 +03:00
|
|
|
static StringList metaIgnorePaths = LST_INIT; /* paths we deliberately ignore */
|
2016-03-08 00:45:43 +03:00
|
|
|
static char *metaIgnorePathsStr; /* string storage for the list */
|
2013-06-25 04:20:54 +04:00
|
|
|
|
|
|
|
#ifndef MAKE_META_IGNORE_PATHS
|
|
|
|
#define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS"
|
|
|
|
#endif
|
2016-05-11 02:45:45 +03:00
|
|
|
#ifndef MAKE_META_IGNORE_PATTERNS
|
|
|
|
#define MAKE_META_IGNORE_PATTERNS ".MAKE.META.IGNORE_PATTERNS"
|
|
|
|
#endif
|
2016-08-15 22:20:17 +03:00
|
|
|
#ifndef MAKE_META_IGNORE_FILTER
|
|
|
|
#define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER"
|
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
Boolean useMeta = FALSE;
|
|
|
|
static Boolean useFilemon = FALSE;
|
|
|
|
static Boolean writeMeta = FALSE;
|
2016-06-03 04:16:27 +03:00
|
|
|
static Boolean metaMissing = FALSE; /* oodate if missing */
|
|
|
|
static Boolean filemonMissing = FALSE; /* oodate if missing */
|
2010-09-13 19:36:57 +04:00
|
|
|
static Boolean metaEnv = FALSE; /* don't save env unless asked */
|
|
|
|
static Boolean metaVerbose = FALSE;
|
|
|
|
static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
|
2016-05-11 02:45:45 +03:00
|
|
|
static Boolean metaIgnorePatterns = FALSE; /* do we need to do pattern matches */
|
2020-11-23 23:41:20 +03:00
|
|
|
static Boolean metaIgnoreFilter = FALSE; /* do we have more complex filtering? */
|
2011-03-27 23:39:21 +04:00
|
|
|
static Boolean metaCurdirOk = FALSE; /* write .meta in .CURDIR Ok? */
|
2011-08-28 07:54:07 +04:00
|
|
|
static Boolean metaSilent = FALSE; /* if we have a .meta be SILENT */
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
extern Boolean forceJobs;
|
2012-06-27 21:22:58 +04:00
|
|
|
extern char **environ;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-29 12:27:40 +03:00
|
|
|
#define MAKE_META_PREFIX ".MAKE.META.PREFIX"
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
#ifndef N2U
|
|
|
|
# define N2U(n, u) (((n) + ((u) - 1)) / (u))
|
|
|
|
#endif
|
|
|
|
#ifndef ROUNDUP
|
|
|
|
# define ROUNDUP(n, u) (N2U((n), (u)) * (u))
|
|
|
|
#endif
|
|
|
|
|
2010-09-14 00:34:21 +04:00
|
|
|
#if !defined(HAVE_STRSEP)
|
2020-11-07 13:16:18 +03:00
|
|
|
# define strsep(s, d) stresep((s), (d), '\0')
|
2010-09-14 00:34:21 +04:00
|
|
|
#endif
|
|
|
|
|
2019-12-19 10:14:07 +03:00
|
|
|
/*
|
|
|
|
* Filemon is a kernel module which snoops certain syscalls.
|
|
|
|
*
|
|
|
|
* C chdir
|
|
|
|
* E exec
|
|
|
|
* F [v]fork
|
|
|
|
* L [sym]link
|
|
|
|
* M rename
|
|
|
|
* R read
|
|
|
|
* W write
|
|
|
|
* S stat
|
|
|
|
*
|
|
|
|
* See meta_oodate below - we mainly care about 'E' and 'R'.
|
|
|
|
*
|
2020-07-03 11:13:23 +03:00
|
|
|
* We can still use meta mode without filemon, but
|
2019-12-19 10:14:07 +03:00
|
|
|
* the benefits are more limited.
|
|
|
|
*/
|
|
|
|
#ifdef USE_FILEMON
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open the filemon device.
|
|
|
|
*/
|
|
|
|
static void
|
2020-01-19 22:42:32 +03:00
|
|
|
meta_open_filemon(BuildMon *pbm)
|
2019-12-19 10:14:07 +03:00
|
|
|
{
|
2020-01-19 22:42:32 +03:00
|
|
|
int dupfd;
|
|
|
|
|
|
|
|
pbm->mon_fd = -1;
|
|
|
|
pbm->filemon = NULL;
|
2021-01-11 00:20:46 +03:00
|
|
|
if (!useFilemon || pbm->mfp == NULL)
|
2019-12-19 10:14:07 +03:00
|
|
|
return;
|
|
|
|
|
2020-01-19 22:42:32 +03:00
|
|
|
pbm->filemon = filemon_open();
|
|
|
|
if (pbm->filemon == NULL) {
|
2019-12-19 10:14:07 +03:00
|
|
|
useFilemon = FALSE;
|
2020-01-19 22:49:36 +03:00
|
|
|
warn("Could not open filemon %s", filemon_path());
|
2019-12-19 10:14:07 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We use a file outside of '.'
|
|
|
|
* to avoid a FreeBSD kernel bug where unlink invalidates
|
|
|
|
* cwd causing getcwd to do a lot more work.
|
|
|
|
* We only care about the descriptor.
|
|
|
|
*/
|
|
|
|
pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
|
2020-01-19 22:42:32 +03:00
|
|
|
if ((dupfd = dup(pbm->mon_fd)) == -1) {
|
|
|
|
err(1, "Could not dup filemon output!");
|
|
|
|
}
|
|
|
|
(void)fcntl(dupfd, F_SETFD, FD_CLOEXEC);
|
|
|
|
if (filemon_setfd(pbm->filemon, dupfd) == -1) {
|
2019-12-19 10:14:07 +03:00
|
|
|
err(1, "Could not set filemon file descriptor!");
|
|
|
|
}
|
|
|
|
/* we don't need these once we exec */
|
|
|
|
(void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the build monitor output file and write records to the target's
|
|
|
|
* metadata file.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
filemon_read(FILE *mfp, int fd)
|
|
|
|
{
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
int error;
|
|
|
|
|
|
|
|
/* Check if we're not writing to a meta data file.*/
|
|
|
|
if (mfp == NULL) {
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd); /* not interested */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* rewind */
|
2020-06-25 18:45:37 +03:00
|
|
|
if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
|
|
|
|
error = errno;
|
|
|
|
warn("Could not rewind filemon");
|
|
|
|
fprintf(mfp, "\n");
|
|
|
|
} else {
|
2020-10-30 18:39:17 +03:00
|
|
|
ssize_t n;
|
2020-10-18 14:54:43 +03:00
|
|
|
|
2020-06-25 18:45:37 +03:00
|
|
|
error = 0;
|
|
|
|
fprintf(mfp, "\n-- filemon acquired metadata --\n");
|
|
|
|
|
2020-11-05 20:27:16 +03:00
|
|
|
while ((n = read(fd, buf, sizeof buf)) > 0) {
|
2020-10-18 14:54:43 +03:00
|
|
|
if ((ssize_t)fwrite(buf, 1, (size_t)n, mfp) < n)
|
2020-06-25 18:45:37 +03:00
|
|
|
error = EIO;
|
|
|
|
}
|
2019-12-19 10:14:07 +03:00
|
|
|
}
|
|
|
|
fflush(mfp);
|
|
|
|
if (close(fd) < 0)
|
|
|
|
error = errno;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-02-14 00:22:41 +03:00
|
|
|
/*
|
|
|
|
* when realpath() fails,
|
|
|
|
* we use this, to clean up ./ and ../
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
eat_dots(char *buf, size_t bufsz, int dots)
|
|
|
|
{
|
|
|
|
char *cp;
|
|
|
|
char *cp2;
|
|
|
|
const char *eat;
|
|
|
|
size_t eatlen;
|
|
|
|
|
|
|
|
switch (dots) {
|
|
|
|
case 1:
|
|
|
|
eat = "/./";
|
|
|
|
eatlen = 2;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
eat = "/../";
|
|
|
|
eatlen = 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2011-02-14 00:22:41 +03:00
|
|
|
do {
|
|
|
|
cp = strstr(buf, eat);
|
2020-11-24 02:41:11 +03:00
|
|
|
if (cp != NULL) {
|
2011-02-14 00:22:41 +03:00
|
|
|
cp2 = cp + eatlen;
|
|
|
|
if (dots == 2 && cp > buf) {
|
|
|
|
do {
|
|
|
|
cp--;
|
|
|
|
} while (cp > buf && *cp != '/');
|
|
|
|
}
|
|
|
|
if (*cp == '/') {
|
2020-10-18 14:54:43 +03:00
|
|
|
strlcpy(cp, cp2, bufsz - (size_t)(cp - buf));
|
2011-02-14 00:22:41 +03:00
|
|
|
} else {
|
|
|
|
return; /* can't happen? */
|
|
|
|
}
|
|
|
|
}
|
2020-11-24 02:41:11 +03:00
|
|
|
} while (cp != NULL);
|
2011-02-14 00:22:41 +03:00
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
static char *
|
2020-10-24 07:31:53 +03:00
|
|
|
meta_name(char *mname, size_t mnamelen,
|
2010-09-13 19:36:57 +04:00
|
|
|
const char *dname,
|
2016-06-03 04:16:27 +03:00
|
|
|
const char *tname,
|
|
|
|
const char *cwd)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
|
|
|
char buf[MAXPATHLEN];
|
|
|
|
char *rp;
|
|
|
|
char *cp;
|
|
|
|
char *tp;
|
2017-08-11 00:07:48 +03:00
|
|
|
char *dtp;
|
|
|
|
size_t ldname;
|
2011-02-14 00:22:41 +03:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* Weed out relative paths from the target file name.
|
|
|
|
* We have to be careful though since if target is a
|
|
|
|
* symlink, the result will be unstable.
|
|
|
|
* So we use realpath() just to get the dirname, and leave the
|
|
|
|
* basename as given to us.
|
|
|
|
*/
|
2020-12-31 20:39:36 +03:00
|
|
|
if ((cp = strrchr(tname, '/')) != NULL) {
|
|
|
|
if (cached_realpath(tname, buf) != NULL) {
|
|
|
|
if ((rp = strrchr(buf, '/')) != NULL) {
|
2010-09-13 19:36:57 +04:00
|
|
|
rp++;
|
|
|
|
cp++;
|
|
|
|
if (strcmp(cp, rp) != 0)
|
2020-10-18 14:54:43 +03:00
|
|
|
strlcpy(rp, cp, sizeof buf - (size_t)(rp - buf));
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
tname = buf;
|
2011-02-14 00:22:41 +03:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We likely have a directory which is about to be made.
|
|
|
|
* We pretend realpath() succeeded, to have a chance
|
|
|
|
* of generating the same meta file name that we will
|
|
|
|
* next time through.
|
|
|
|
*/
|
|
|
|
if (tname[0] == '/') {
|
2020-11-05 20:27:16 +03:00
|
|
|
strlcpy(buf, tname, sizeof buf);
|
2011-02-14 00:22:41 +03:00
|
|
|
} else {
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(buf, sizeof buf, "%s/%s", cwd, tname);
|
2011-02-14 00:22:41 +03:00
|
|
|
}
|
2020-11-05 20:27:16 +03:00
|
|
|
eat_dots(buf, sizeof buf, 1); /* ./ */
|
|
|
|
eat_dots(buf, sizeof buf, 2); /* ../ */
|
2011-02-14 00:22:41 +03:00
|
|
|
tname = buf;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* on some systems dirname may modify its arg */
|
|
|
|
tp = bmake_strdup(tname);
|
2017-08-11 00:07:48 +03:00
|
|
|
dtp = dirname(tp);
|
|
|
|
if (strcmp(dname, dtp) == 0)
|
2010-09-13 19:36:57 +04:00
|
|
|
snprintf(mname, mnamelen, "%s.meta", tname);
|
|
|
|
else {
|
2017-08-11 00:07:48 +03:00
|
|
|
ldname = strlen(dname);
|
|
|
|
if (strncmp(dname, dtp, ldname) == 0 && dtp[ldname] == '/')
|
|
|
|
snprintf(mname, mnamelen, "%s/%s.meta", dname, &tname[ldname+1]);
|
|
|
|
else
|
|
|
|
snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Replace path separators in the file name after the
|
|
|
|
* current object directory path.
|
|
|
|
*/
|
|
|
|
cp = mname + strlen(dname) + 1;
|
|
|
|
|
|
|
|
while (*cp != '\0') {
|
|
|
|
if (*cp == '/')
|
|
|
|
*cp = '_';
|
|
|
|
cp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(tp);
|
2020-07-03 11:02:55 +03:00
|
|
|
return mname;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return true if running ${.MAKE}
|
|
|
|
* Bypassed if target is flagged .MAKE
|
|
|
|
*/
|
2020-11-27 11:07:26 +03:00
|
|
|
static Boolean
|
|
|
|
is_submake(const char *cmd, GNode *gn)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
2020-08-01 12:25:36 +03:00
|
|
|
static const char *p_make = NULL;
|
2020-10-18 14:54:43 +03:00
|
|
|
static size_t p_len;
|
2010-09-13 19:36:57 +04:00
|
|
|
char *mp = NULL;
|
|
|
|
char *cp;
|
|
|
|
char *cp2;
|
2020-11-27 11:07:26 +03:00
|
|
|
Boolean rc = FALSE;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-08 18:07:37 +03:00
|
|
|
if (p_make == NULL) {
|
2020-12-20 17:32:13 +03:00
|
|
|
p_make = Var_Value(".MAKE", gn).str;
|
2010-09-13 19:36:57 +04:00
|
|
|
p_len = strlen(p_make);
|
|
|
|
}
|
|
|
|
cp = strchr(cmd, '$');
|
2020-12-31 20:39:36 +03:00
|
|
|
if (cp != NULL) {
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst(cmd, gn, VARE_WANTRES, &mp);
|
|
|
|
/* TODO: handle errors */
|
2010-09-13 19:36:57 +04:00
|
|
|
cmd = mp;
|
|
|
|
}
|
|
|
|
cp2 = strstr(cmd, p_make);
|
2020-11-07 13:16:18 +03:00
|
|
|
if (cp2 != NULL) {
|
2010-09-13 19:36:57 +04:00
|
|
|
switch (cp2[p_len]) {
|
|
|
|
case '\0':
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\n':
|
2020-11-27 11:07:26 +03:00
|
|
|
rc = TRUE;
|
2010-09-13 19:36:57 +04:00
|
|
|
break;
|
|
|
|
}
|
2020-11-27 11:07:26 +03:00
|
|
|
if (cp2 > cmd && rc) {
|
2010-09-13 19:36:57 +04:00
|
|
|
switch (cp2[-1]) {
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\n':
|
|
|
|
break;
|
|
|
|
default:
|
2020-11-27 11:07:26 +03:00
|
|
|
rc = FALSE; /* no match */
|
2010-09-13 19:36:57 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-17 20:45:21 +03:00
|
|
|
free(mp);
|
2020-07-03 11:02:55 +03:00
|
|
|
return rc;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2020-11-27 11:07:26 +03:00
|
|
|
static Boolean
|
|
|
|
any_is_submake(GNode *gn)
|
|
|
|
{
|
|
|
|
StringListNode *ln;
|
|
|
|
|
2020-11-28 21:55:52 +03:00
|
|
|
for (ln = gn->commands.first; ln != NULL; ln = ln->next)
|
2020-11-27 11:07:26 +03:00
|
|
|
if (is_submake(ln->datum, gn))
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-09-24 10:53:32 +03:00
|
|
|
static void
|
2020-11-27 11:18:14 +03:00
|
|
|
printCMD(const char *cmd, FILE *fp, GNode *gn)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
2020-08-29 16:16:54 +03:00
|
|
|
char *cmd_freeIt = NULL;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strchr(cmd, '$') != NULL) {
|
2020-11-27 11:18:14 +03:00
|
|
|
(void)Var_Subst(cmd, gn, VARE_WANTRES, &cmd_freeIt);
|
2020-09-22 23:19:46 +03:00
|
|
|
/* TODO: handle errors */
|
|
|
|
cmd = cmd_freeIt;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2020-11-27 11:18:14 +03:00
|
|
|
fprintf(fp, "CMD %s\n", cmd);
|
2020-08-29 16:16:54 +03:00
|
|
|
free(cmd_freeIt);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2020-10-19 23:41:53 +03:00
|
|
|
static void
|
2020-11-27 11:18:14 +03:00
|
|
|
printCMDs(GNode *gn, FILE *fp)
|
2020-10-19 23:41:53 +03:00
|
|
|
{
|
2020-12-21 01:02:54 +03:00
|
|
|
StringListNode *ln;
|
2020-10-19 23:41:53 +03:00
|
|
|
|
2020-11-28 21:55:52 +03:00
|
|
|
for (ln = gn->commands.first; ln != NULL; ln = ln->next)
|
2020-11-27 11:18:14 +03:00
|
|
|
printCMD(ln->datum, fp, gn);
|
2020-10-19 23:41:53 +03:00
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* Certain node types never get a .meta file
|
|
|
|
*/
|
|
|
|
#define SKIP_META_TYPE(_type) do { \
|
2020-09-29 01:23:35 +03:00
|
|
|
if ((gn->type & __CONCAT(OP_, _type))) { \
|
2016-06-03 04:16:27 +03:00
|
|
|
if (verbose) { \
|
2020-09-29 01:23:35 +03:00
|
|
|
debug_printf("Skipping meta for %s: .%s\n", \
|
|
|
|
gn->name, __STRING(_type)); \
|
2010-09-13 19:36:57 +04:00
|
|
|
} \
|
2016-06-03 04:16:27 +03:00
|
|
|
return FALSE; \
|
2010-09-13 19:36:57 +04:00
|
|
|
} \
|
2021-01-16 23:49:31 +03:00
|
|
|
} while (/*CONSTCOND*/FALSE)
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2016-06-03 04:16:27 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we need/want a .meta file ?
|
|
|
|
*/
|
|
|
|
static Boolean
|
2020-12-05 20:46:41 +03:00
|
|
|
meta_needed(GNode *gn, const char *dname,
|
2020-11-28 13:28:53 +03:00
|
|
|
char *objdir_realpath, Boolean verbose)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
struct cached_stat cst;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2016-06-03 04:16:27 +03:00
|
|
|
if (verbose)
|
2020-12-23 01:31:50 +03:00
|
|
|
verbose = DEBUG(META);
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/* This may be a phony node which we don't want meta data for... */
|
|
|
|
/* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
|
|
|
|
/* Or it may be explicitly flagged as .NOMETA */
|
|
|
|
SKIP_META_TYPE(NOMETA);
|
|
|
|
/* Unless it is explicitly flagged as .META */
|
|
|
|
if (!(gn->type & OP_META)) {
|
|
|
|
SKIP_META_TYPE(PHONY);
|
|
|
|
SKIP_META_TYPE(SPECIAL);
|
|
|
|
SKIP_META_TYPE(MAKE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if there are no commands to execute. */
|
2020-11-28 21:55:52 +03:00
|
|
|
if (Lst_IsEmpty(&gn->commands)) {
|
2016-06-03 04:16:27 +03:00
|
|
|
if (verbose)
|
2020-09-29 01:23:35 +03:00
|
|
|
debug_printf("Skipping meta for %s: no commands\n", gn->name);
|
2016-06-03 04:16:27 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) {
|
|
|
|
/* OP_SUBMAKE is a bit too aggressive */
|
2020-11-27 11:07:26 +03:00
|
|
|
if (any_is_submake(gn)) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "Skipping meta for %s: .SUBMAKE\n", gn->name);
|
2016-06-03 04:16:27 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The object directory may not exist. Check it.. */
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
if (cached_stat(dname, &cst) != 0) {
|
2016-06-03 04:16:27 +03:00
|
|
|
if (verbose)
|
2020-09-29 01:23:35 +03:00
|
|
|
debug_printf("Skipping meta for %s: no .OBJDIR\n", gn->name);
|
2016-06-03 04:16:27 +03:00
|
|
|
return FALSE;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure these are canonical */
|
2020-12-31 20:39:36 +03:00
|
|
|
if (cached_realpath(dname, objdir_realpath) != NULL)
|
2020-11-28 13:28:53 +03:00
|
|
|
dname = objdir_realpath;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
/* If we aren't in the object directory, don't create a meta file. */
|
2011-03-27 23:39:21 +04:00
|
|
|
if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
|
2016-06-03 04:16:27 +03:00
|
|
|
if (verbose)
|
2020-09-29 01:23:35 +03:00
|
|
|
debug_printf("Skipping meta for %s: .OBJDIR == .CURDIR\n",
|
|
|
|
gn->name);
|
2016-06-03 04:16:27 +03:00
|
|
|
return FALSE;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2016-06-03 04:16:27 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2016-06-03 04:16:27 +03:00
|
|
|
static FILE *
|
|
|
|
meta_create(BuildMon *pbm, GNode *gn)
|
|
|
|
{
|
2020-11-27 11:18:14 +03:00
|
|
|
FILE *fp;
|
2016-06-03 04:16:27 +03:00
|
|
|
char buf[MAXPATHLEN];
|
2020-11-28 13:28:53 +03:00
|
|
|
char objdir_realpath[MAXPATHLEN];
|
2016-06-03 04:16:27 +03:00
|
|
|
char **ptr;
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr dname;
|
2016-06-03 04:16:27 +03:00
|
|
|
const char *tname;
|
|
|
|
char *fname;
|
|
|
|
const char *cp;
|
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
fp = NULL;
|
2016-06-03 04:16:27 +03:00
|
|
|
|
2020-12-20 17:32:13 +03:00
|
|
|
dname = Var_Value(".OBJDIR", gn);
|
2020-10-31 14:54:33 +03:00
|
|
|
tname = GNode_VarTarget(gn);
|
2016-06-03 04:16:27 +03:00
|
|
|
|
2020-11-28 13:28:53 +03:00
|
|
|
/* if this succeeds objdir_realpath is realpath of dname */
|
2020-12-20 17:32:13 +03:00
|
|
|
if (!meta_needed(gn, dname.str, objdir_realpath, TRUE))
|
2016-06-03 04:16:27 +03:00
|
|
|
goto out;
|
2020-12-20 17:32:13 +03:00
|
|
|
dname.str = objdir_realpath;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
if (metaVerbose) {
|
|
|
|
char *mp;
|
|
|
|
|
|
|
|
/* Describe the target we are building */
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES, &mp);
|
|
|
|
/* TODO: handle errors */
|
2020-11-23 23:52:59 +03:00
|
|
|
if (mp[0] != '\0')
|
2010-09-13 19:36:57 +04:00
|
|
|
fprintf(stdout, "%s\n", mp);
|
|
|
|
free(mp);
|
|
|
|
}
|
|
|
|
/* Get the basename of the target */
|
2020-12-13 23:14:48 +03:00
|
|
|
cp = str_basename(tname);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
|
|
|
if (!writeMeta)
|
|
|
|
/* Don't create meta data. */
|
|
|
|
goto out;
|
|
|
|
|
2020-11-05 20:27:16 +03:00
|
|
|
fname = meta_name(pbm->meta_fname, sizeof pbm->meta_fname,
|
2020-12-20 17:32:13 +03:00
|
|
|
dname.str, tname, objdir_realpath);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2011-02-14 00:22:41 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "meta_create: %s\n", fname);
|
2011-02-14 00:22:41 +03:00
|
|
|
#endif
|
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
if ((fp = fopen(fname, "w")) == NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
err(1, "Could not open meta file '%s'", fname);
|
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
fprintf(fp, "# Meta data file %s\n", fname);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
printCMDs(gn, fp);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
fprintf(fp, "CWD %s\n", getcwd(buf, sizeof buf));
|
|
|
|
fprintf(fp, "TARGET %s\n", tname);
|
2020-10-31 14:54:33 +03:00
|
|
|
cp = GNode_VarOodate(gn);
|
2021-01-11 00:20:46 +03:00
|
|
|
if (cp != NULL && *cp != '\0') {
|
2020-11-27 11:18:14 +03:00
|
|
|
fprintf(fp, "OODATE %s\n", cp);
|
2020-01-22 03:26:45 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
if (metaEnv) {
|
|
|
|
for (ptr = environ; *ptr != NULL; ptr++)
|
2020-11-27 11:18:14 +03:00
|
|
|
fprintf(fp, "ENV %s\n", *ptr);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
fprintf(fp, "-- command output --\n");
|
|
|
|
fflush(fp);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
|
|
|
|
Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
|
2011-08-28 07:54:07 +04:00
|
|
|
|
|
|
|
gn->type |= OP_META; /* in case anyone wants to know */
|
|
|
|
if (metaSilent) {
|
|
|
|
gn->type |= OP_SILENT;
|
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
out:
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr_Done(&dname);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-27 11:18:14 +03:00
|
|
|
return fp;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2011-03-27 23:39:21 +04:00
|
|
|
static Boolean
|
|
|
|
boolValue(char *s)
|
|
|
|
{
|
|
|
|
switch(*s) {
|
|
|
|
case '0':
|
|
|
|
case 'N':
|
|
|
|
case 'n':
|
|
|
|
case 'F':
|
|
|
|
case 'f':
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2013-03-23 09:31:29 +04:00
|
|
|
/*
|
|
|
|
* Initialization we need before reading makefiles.
|
|
|
|
*/
|
|
|
|
void
|
2013-05-17 01:56:56 +04:00
|
|
|
meta_init(void)
|
2013-03-23 09:31:29 +04:00
|
|
|
{
|
2019-12-19 10:14:07 +03:00
|
|
|
#ifdef USE_FILEMON
|
|
|
|
/* this allows makefiles to test if we have filemon support */
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(".MAKE.PATH_FILEMON", filemon_path(), VAR_GLOBAL);
|
2019-12-19 10:14:07 +03:00
|
|
|
#endif
|
2013-03-23 09:31:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-03 04:16:27 +03:00
|
|
|
#define get_mode_bf(bf, token) \
|
2020-12-31 20:39:36 +03:00
|
|
|
if ((cp = strstr(make_mode, token)) != NULL) \
|
2020-11-05 20:27:16 +03:00
|
|
|
bf = boolValue(cp + sizeof (token) - 1)
|
2016-06-03 04:16:27 +03:00
|
|
|
|
2013-03-23 09:31:29 +04:00
|
|
|
/*
|
|
|
|
* Initialization we need after reading makefiles.
|
|
|
|
*/
|
2010-09-13 19:36:57 +04:00
|
|
|
void
|
2013-03-23 09:31:29 +04:00
|
|
|
meta_mode_init(const char *make_mode)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
2020-11-24 02:41:11 +03:00
|
|
|
static Boolean once = FALSE;
|
2011-03-27 23:39:21 +04:00
|
|
|
char *cp;
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr value;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
useMeta = TRUE;
|
|
|
|
useFilemon = TRUE;
|
|
|
|
writeMeta = TRUE;
|
|
|
|
|
2020-11-24 02:41:11 +03:00
|
|
|
if (make_mode != NULL) {
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr(make_mode, "env") != NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
metaEnv = TRUE;
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr(make_mode, "verb") != NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
metaVerbose = TRUE;
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr(make_mode, "read") != NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
writeMeta = FALSE;
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr(make_mode, "nofilemon") != NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
useFilemon = FALSE;
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr(make_mode, "ignore-cmd") != NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
metaIgnoreCMDs = TRUE;
|
2016-06-03 04:16:27 +03:00
|
|
|
if (useFilemon)
|
|
|
|
get_mode_bf(filemonMissing, "missing-filemon=");
|
|
|
|
get_mode_bf(metaCurdirOk, "curdirok=");
|
|
|
|
get_mode_bf(metaMissing, "missing-meta=");
|
|
|
|
get_mode_bf(metaSilent, "silent=");
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
|
|
|
|
/*
|
|
|
|
* The default value for MAKE_META_PREFIX
|
|
|
|
* prints the absolute path of the target.
|
|
|
|
* This works be cause :H will generate '.' if there is no /
|
|
|
|
* and :tA will resolve that to cwd.
|
|
|
|
*/
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
if (once)
|
|
|
|
return;
|
2020-11-24 02:41:11 +03:00
|
|
|
once = TRUE;
|
2020-11-05 20:27:16 +03:00
|
|
|
memset(&Mybm, 0, sizeof Mybm);
|
2011-05-05 00:38:31 +04:00
|
|
|
/*
|
|
|
|
* We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
|
|
|
|
*/
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}",
|
|
|
|
VAR_GLOBAL, VARE_WANTRES, &metaBailiwickStr);
|
|
|
|
/* TODO: handle errors */
|
2020-11-30 00:28:06 +03:00
|
|
|
str2Lst_Append(&metaBailiwick, metaBailiwickStr);
|
2013-06-25 04:20:54 +04:00
|
|
|
/*
|
|
|
|
* We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS}
|
|
|
|
*/
|
|
|
|
Var_Append(MAKE_META_IGNORE_PATHS,
|
|
|
|
"/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL);
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}",
|
|
|
|
VAR_GLOBAL, VARE_WANTRES, &metaIgnorePathsStr);
|
|
|
|
/* TODO: handle errors */
|
2020-11-30 00:28:06 +03:00
|
|
|
str2Lst_Append(&metaIgnorePaths, metaIgnorePathsStr);
|
2016-05-11 02:45:45 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS}
|
|
|
|
*/
|
2020-12-20 17:32:13 +03:00
|
|
|
value = Var_Value(MAKE_META_IGNORE_PATTERNS, VAR_GLOBAL);
|
|
|
|
if (value.str != NULL) {
|
2016-05-11 02:45:45 +03:00
|
|
|
metaIgnorePatterns = TRUE;
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr_Done(&value);
|
2016-05-11 02:45:45 +03:00
|
|
|
}
|
2020-12-20 17:32:13 +03:00
|
|
|
value = Var_Value(MAKE_META_IGNORE_FILTER, VAR_GLOBAL);
|
|
|
|
if (value.str != NULL) {
|
2016-08-15 22:20:17 +03:00
|
|
|
metaIgnoreFilter = TRUE;
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr_Done(&value);
|
2016-08-15 22:20:17 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In each case below we allow for job==NULL
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_job_start(Job *job, GNode *gn)
|
|
|
|
{
|
|
|
|
BuildMon *pbm;
|
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
|
|
|
pbm->mfp = meta_create(pbm, gn);
|
2019-12-19 10:14:07 +03:00
|
|
|
#ifdef USE_FILEMON_ONCE
|
|
|
|
/* compat mode we open the filemon dev once per command */
|
|
|
|
if (job == NULL)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_FILEMON
|
|
|
|
if (pbm->mfp != NULL && useFilemon) {
|
2020-01-19 22:42:32 +03:00
|
|
|
meta_open_filemon(pbm);
|
2019-12-19 10:14:07 +03:00
|
|
|
} else {
|
2020-01-19 22:42:32 +03:00
|
|
|
pbm->mon_fd = -1;
|
|
|
|
pbm->filemon = NULL;
|
2019-12-19 10:14:07 +03:00
|
|
|
}
|
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The child calls this before doing anything.
|
|
|
|
* It does not disturb our state.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_job_child(Job *job)
|
|
|
|
{
|
2019-12-19 10:14:07 +03:00
|
|
|
#ifdef USE_FILEMON
|
|
|
|
BuildMon *pbm;
|
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
|
|
|
if (pbm->mfp != NULL) {
|
|
|
|
close(fileno(pbm->mfp));
|
2021-01-11 00:20:46 +03:00
|
|
|
if (useFilemon && pbm->filemon != NULL) {
|
2019-12-19 10:14:07 +03:00
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
pid = getpid();
|
2020-01-19 22:42:32 +03:00
|
|
|
if (filemon_setpid_child(pbm->filemon, pid) == -1) {
|
2019-12-19 10:14:07 +03:00
|
|
|
err(1, "Could not set filemon pid!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2020-01-19 22:42:32 +03:00
|
|
|
void
|
|
|
|
meta_job_parent(Job *job, pid_t pid)
|
|
|
|
{
|
2020-02-06 04:13:19 +03:00
|
|
|
#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
|
2020-01-19 22:42:32 +03:00
|
|
|
BuildMon *pbm;
|
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
2021-01-11 00:20:46 +03:00
|
|
|
if (useFilemon && pbm->filemon != NULL) {
|
2020-01-19 22:42:32 +03:00
|
|
|
filemon_setpid_parent(pbm->filemon, pid);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_job_fd(Job *job)
|
|
|
|
{
|
2020-02-06 04:13:19 +03:00
|
|
|
#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
|
2020-01-19 22:42:32 +03:00
|
|
|
BuildMon *pbm;
|
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
2021-01-11 00:20:46 +03:00
|
|
|
if (useFilemon && pbm->filemon != NULL) {
|
2020-01-19 22:42:32 +03:00
|
|
|
return filemon_readfd(pbm->filemon);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_job_event(Job *job)
|
|
|
|
{
|
2020-02-06 04:13:19 +03:00
|
|
|
#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
|
2020-01-19 22:42:32 +03:00
|
|
|
BuildMon *pbm;
|
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
2021-01-11 00:20:46 +03:00
|
|
|
if (useFilemon && pbm->filemon != NULL) {
|
2020-01-19 22:42:32 +03:00
|
|
|
return filemon_process(pbm->filemon);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
void
|
2020-12-10 23:49:11 +03:00
|
|
|
meta_job_error(Job *job, GNode *gn, Boolean ignerr, int status)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
|
|
|
char cwd[MAXPATHLEN];
|
|
|
|
BuildMon *pbm;
|
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
2020-11-08 18:07:37 +03:00
|
|
|
if (gn == NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
gn = job->node;
|
2016-02-27 19:20:06 +03:00
|
|
|
} else {
|
2010-09-13 19:36:57 +04:00
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
|
|
|
if (pbm->mfp != NULL) {
|
2017-07-09 07:54:00 +03:00
|
|
|
fprintf(pbm->mfp, "\n*** Error code %d%s\n",
|
2020-12-10 23:49:11 +03:00
|
|
|
status, ignerr ? "(ignored)" : "");
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2020-11-24 02:41:11 +03:00
|
|
|
if (gn != NULL) {
|
2020-10-26 00:51:48 +03:00
|
|
|
Var_Set(".ERROR_TARGET", GNode_Path(gn), VAR_GLOBAL);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2020-11-05 20:27:16 +03:00
|
|
|
getcwd(cwd, sizeof cwd);
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL);
|
2020-11-07 13:16:18 +03:00
|
|
|
if (pbm->meta_fname[0] != '\0') {
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2011-03-31 10:50:43 +04:00
|
|
|
meta_job_finish(job);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_job_output(Job *job, char *cp, const char *nl)
|
|
|
|
{
|
|
|
|
BuildMon *pbm;
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
|
|
|
if (pbm->mfp != NULL) {
|
|
|
|
if (metaVerbose) {
|
|
|
|
static char *meta_prefix = NULL;
|
2020-10-18 14:54:43 +03:00
|
|
|
static size_t meta_prefix_len;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-08 18:07:37 +03:00
|
|
|
if (meta_prefix == NULL) {
|
2010-09-13 19:36:57 +04:00
|
|
|
char *cp2;
|
|
|
|
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst("${" MAKE_META_PREFIX "}",
|
|
|
|
VAR_GLOBAL, VARE_WANTRES, &meta_prefix);
|
|
|
|
/* TODO: handle errors */
|
2020-12-31 20:39:36 +03:00
|
|
|
if ((cp2 = strchr(meta_prefix, '$')) != NULL)
|
2020-10-18 14:54:43 +03:00
|
|
|
meta_prefix_len = (size_t)(cp2 - meta_prefix);
|
2010-09-13 19:36:57 +04:00
|
|
|
else
|
|
|
|
meta_prefix_len = strlen(meta_prefix);
|
|
|
|
}
|
|
|
|
if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
|
2020-12-21 01:36:40 +03:00
|
|
|
cp = strchr(cp + 1, '\n');
|
|
|
|
if (cp == NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
return;
|
2020-12-21 01:36:40 +03:00
|
|
|
cp++;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fprintf(pbm->mfp, "%s%s", cp, nl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-12 23:28:34 +03:00
|
|
|
int
|
2010-09-13 19:36:57 +04:00
|
|
|
meta_cmd_finish(void *pbmp)
|
|
|
|
{
|
2016-05-12 23:28:34 +03:00
|
|
|
int error = 0;
|
2010-09-13 19:36:57 +04:00
|
|
|
BuildMon *pbm = pbmp;
|
2019-12-19 10:14:07 +03:00
|
|
|
#ifdef USE_FILEMON
|
|
|
|
int x;
|
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-07 13:16:18 +03:00
|
|
|
if (pbm == NULL)
|
2010-09-13 19:36:57 +04:00
|
|
|
pbm = &Mybm;
|
|
|
|
|
2019-12-19 10:14:07 +03:00
|
|
|
#ifdef USE_FILEMON
|
2020-12-31 20:39:36 +03:00
|
|
|
if (pbm->filemon != NULL) {
|
2020-01-19 22:42:32 +03:00
|
|
|
while (filemon_process(pbm->filemon) > 0)
|
|
|
|
continue;
|
|
|
|
if (filemon_close(pbm->filemon) == -1)
|
2019-12-19 10:14:07 +03:00
|
|
|
error = errno;
|
|
|
|
x = filemon_read(pbm->mfp, pbm->mon_fd);
|
|
|
|
if (error == 0 && x != 0)
|
|
|
|
error = x;
|
2020-01-19 22:42:32 +03:00
|
|
|
pbm->mon_fd = -1;
|
|
|
|
pbm->filemon = NULL;
|
2020-11-08 00:26:43 +03:00
|
|
|
return error;
|
|
|
|
}
|
2019-12-19 10:14:07 +03:00
|
|
|
#endif
|
2020-11-08 00:26:43 +03:00
|
|
|
|
|
|
|
fprintf(pbm->mfp, "\n"); /* ensure end with newline */
|
2016-05-12 23:28:34 +03:00
|
|
|
return error;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2016-05-12 23:28:34 +03:00
|
|
|
int
|
2010-09-13 19:36:57 +04:00
|
|
|
meta_job_finish(Job *job)
|
|
|
|
{
|
|
|
|
BuildMon *pbm;
|
2016-05-12 23:28:34 +03:00
|
|
|
int error = 0;
|
|
|
|
int x;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
if (job != NULL) {
|
|
|
|
pbm = &job->bm;
|
|
|
|
} else {
|
|
|
|
pbm = &Mybm;
|
|
|
|
}
|
|
|
|
if (pbm->mfp != NULL) {
|
2016-05-12 23:28:34 +03:00
|
|
|
error = meta_cmd_finish(pbm);
|
|
|
|
x = fclose(pbm->mfp);
|
|
|
|
if (error == 0 && x != 0)
|
|
|
|
error = errno;
|
2010-09-13 19:36:57 +04:00
|
|
|
pbm->mfp = NULL;
|
2010-12-16 02:03:35 +03:00
|
|
|
pbm->meta_fname[0] = '\0';
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2016-05-12 23:28:34 +03:00
|
|
|
return error;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
2016-03-08 00:45:43 +03:00
|
|
|
void
|
|
|
|
meta_finish(void)
|
|
|
|
{
|
2020-11-30 00:28:06 +03:00
|
|
|
Lst_Done(&metaBailiwick);
|
2016-03-08 00:45:43 +03:00
|
|
|
free(metaBailiwickStr);
|
2020-11-30 00:28:06 +03:00
|
|
|
Lst_Done(&metaIgnorePaths);
|
2016-03-08 00:45:43 +03:00
|
|
|
free(metaIgnorePathsStr);
|
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* Fetch a full line from fp - growing bufp if needed
|
|
|
|
* Return length in bufp.
|
|
|
|
*/
|
2020-07-03 11:13:23 +03:00
|
|
|
static int
|
2010-09-13 19:36:57 +04:00
|
|
|
fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
|
|
|
|
{
|
|
|
|
char *buf = *bufp;
|
|
|
|
size_t bufsz = *szp;
|
|
|
|
struct stat fs;
|
|
|
|
int x;
|
|
|
|
|
2020-10-18 14:54:43 +03:00
|
|
|
if (fgets(&buf[o], (int)bufsz - o, fp) != NULL) {
|
2010-09-13 19:36:57 +04:00
|
|
|
check_newline:
|
2020-10-18 14:54:43 +03:00
|
|
|
x = o + (int)strlen(&buf[o]);
|
2010-09-13 19:36:57 +04:00
|
|
|
if (buf[x - 1] == '\n')
|
|
|
|
return x;
|
|
|
|
/*
|
|
|
|
* We need to grow the buffer.
|
|
|
|
* The meta file can give us a clue.
|
|
|
|
*/
|
|
|
|
if (fstat(fileno(fp), &fs) == 0) {
|
|
|
|
size_t newsz;
|
|
|
|
char *p;
|
|
|
|
|
2020-10-18 14:54:43 +03:00
|
|
|
newsz = ROUNDUP(((size_t)fs.st_size / 2), BUFSIZ);
|
2010-09-13 19:36:57 +04:00
|
|
|
if (newsz <= bufsz)
|
2020-10-18 14:54:43 +03:00
|
|
|
newsz = ROUNDUP((size_t)fs.st_size, BUFSIZ);
|
2017-07-09 07:54:00 +03:00
|
|
|
if (newsz <= bufsz)
|
|
|
|
return x; /* truncated */
|
2020-12-14 00:27:45 +03:00
|
|
|
DEBUG2(META, "growing buffer %u -> %u\n",
|
|
|
|
(unsigned)bufsz, (unsigned)newsz);
|
2010-09-13 19:36:57 +04:00
|
|
|
p = bmake_realloc(buf, newsz);
|
2020-11-24 02:44:03 +03:00
|
|
|
*bufp = buf = p;
|
|
|
|
*szp = bufsz = newsz;
|
|
|
|
/* fetch the rest */
|
|
|
|
if (fgets(&buf[x], (int)bufsz - x, fp) == NULL)
|
|
|
|
return x; /* truncated! */
|
|
|
|
goto check_newline;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-11-27 11:07:26 +03:00
|
|
|
static Boolean
|
|
|
|
prefix_match(const char *prefix, const char *path)
|
2011-05-05 00:38:31 +04:00
|
|
|
{
|
|
|
|
size_t n = strlen(prefix);
|
|
|
|
|
2020-07-03 11:02:55 +03:00
|
|
|
return strncmp(path, prefix, n) == 0;
|
2011-05-05 00:38:31 +04:00
|
|
|
}
|
|
|
|
|
2020-11-27 11:07:26 +03:00
|
|
|
static Boolean
|
|
|
|
has_any_prefix(const char *path, StringList *prefixes)
|
|
|
|
{
|
|
|
|
StringListNode *ln;
|
|
|
|
|
|
|
|
for (ln = prefixes->first; ln != NULL; ln = ln->next)
|
|
|
|
if (prefix_match(ln->datum, path))
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-08-29 13:06:23 +03:00
|
|
|
/* See if the path equals prefix or starts with "prefix/". */
|
|
|
|
static Boolean
|
2020-10-24 13:17:21 +03:00
|
|
|
path_starts_with(const char *path, const char *prefix)
|
2016-08-10 21:25:00 +03:00
|
|
|
{
|
|
|
|
size_t n = strlen(prefix);
|
|
|
|
|
2020-08-29 13:06:23 +03:00
|
|
|
if (strncmp(path, prefix, n) != 0)
|
2020-09-12 17:41:00 +03:00
|
|
|
return FALSE;
|
2020-08-29 13:06:23 +03:00
|
|
|
return path[n] == '\0' || path[n] == '/';
|
2016-08-10 21:25:00 +03:00
|
|
|
}
|
|
|
|
|
2021-01-11 00:20:46 +03:00
|
|
|
static Boolean
|
2016-08-17 18:52:42 +03:00
|
|
|
meta_ignore(GNode *gn, const char *p)
|
|
|
|
{
|
|
|
|
char fname[MAXPATHLEN];
|
|
|
|
|
|
|
|
if (p == NULL)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (*p == '/') {
|
|
|
|
cached_realpath(p, fname); /* clean it up */
|
2020-11-30 00:28:06 +03:00
|
|
|
if (has_any_prefix(fname, &metaIgnorePaths)) {
|
2016-08-17 18:52:42 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "meta_oodate: ignoring path: %s\n", p);
|
2016-08-17 18:52:42 +03:00
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (metaIgnorePatterns) {
|
2020-08-22 20:34:25 +03:00
|
|
|
const char *expr;
|
|
|
|
char *pm;
|
2020-08-03 23:26:09 +03:00
|
|
|
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(".p.", p, gn);
|
2020-08-03 23:26:09 +03:00
|
|
|
expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}";
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst(expr, gn, VARE_WANTRES, &pm);
|
|
|
|
/* TODO: handle errors */
|
2020-11-23 23:52:59 +03:00
|
|
|
if (pm[0] != '\0') {
|
2016-08-17 18:52:42 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "meta_oodate: ignoring pattern: %s\n", p);
|
2016-08-17 18:52:42 +03:00
|
|
|
#endif
|
|
|
|
free(pm);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
free(pm);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (metaIgnoreFilter) {
|
|
|
|
char *fm;
|
|
|
|
|
|
|
|
/* skip if filter result is empty */
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(fname, sizeof fname,
|
2016-08-17 18:52:42 +03:00
|
|
|
"${%s:L:${%s:ts:}}",
|
|
|
|
p, MAKE_META_IGNORE_FILTER);
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst(fname, gn, VARE_WANTRES, &fm);
|
|
|
|
/* TODO: handle errors */
|
2016-08-17 18:52:42 +03:00
|
|
|
if (*fm == '\0') {
|
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "meta_oodate: ignoring filtered: %s\n", p);
|
2016-08-17 18:52:42 +03:00
|
|
|
#endif
|
|
|
|
free(fm);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
free(fm);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* When running with 'meta' functionality, a target can be out-of-date
|
2014-10-18 12:33:23 +04:00
|
|
|
* if any of the references in its meta data file is more recent.
|
2010-12-10 01:30:16 +03:00
|
|
|
* We have to track the latestdir on a per-process basis.
|
2010-09-13 19:36:57 +04:00
|
|
|
*/
|
2015-04-11 08:24:30 +03:00
|
|
|
#define LCWD_VNAME_FMT ".meta.%d.lcwd"
|
2010-12-10 01:30:16 +03:00
|
|
|
#define LDIR_VNAME_FMT ".meta.%d.ldir"
|
|
|
|
|
2011-06-23 01:13:12 +04:00
|
|
|
/*
|
|
|
|
* It is possible that a .meta file is corrupted,
|
|
|
|
* if we detect this we want to reproduce it.
|
|
|
|
* Setting oodate TRUE will have that effect.
|
|
|
|
*/
|
2021-01-11 00:20:46 +03:00
|
|
|
#define CHECK_VALID_META(p) if (!(p != NULL && *p != '\0')) { \
|
2011-06-23 01:13:12 +04:00
|
|
|
warnx("%s: %d: malformed", fname, lineno); \
|
|
|
|
oodate = TRUE; \
|
|
|
|
continue; \
|
|
|
|
}
|
|
|
|
|
2013-10-01 09:37:17 +04:00
|
|
|
#define DEQUOTE(p) if (*p == '\'') { \
|
|
|
|
char *ep; \
|
|
|
|
p++; \
|
2020-12-31 20:39:36 +03:00
|
|
|
if ((ep = strchr(p, '\'')) != NULL) \
|
2013-10-01 09:37:17 +04:00
|
|
|
*ep = '\0'; \
|
|
|
|
}
|
|
|
|
|
2020-10-24 13:32:25 +03:00
|
|
|
static void
|
|
|
|
append_if_new(StringList *list, const char *str)
|
|
|
|
{
|
|
|
|
StringListNode *ln;
|
|
|
|
|
|
|
|
for (ln = list->first; ln != NULL; ln = ln->next)
|
2020-10-30 18:39:17 +03:00
|
|
|
if (strcmp(ln->datum, str) == 0)
|
2020-10-24 13:32:25 +03:00
|
|
|
return;
|
|
|
|
Lst_Append(list, bmake_strdup(str));
|
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
Boolean
|
|
|
|
meta_oodate(GNode *gn, Boolean oodate)
|
|
|
|
{
|
2010-12-10 01:30:16 +03:00
|
|
|
static char *tmpdir = NULL;
|
2011-03-06 20:41:11 +03:00
|
|
|
static char cwd[MAXPATHLEN];
|
2015-04-11 08:24:30 +03:00
|
|
|
char lcwd_vname[64];
|
2010-12-10 01:30:16 +03:00
|
|
|
char ldir_vname[64];
|
2015-04-11 08:24:30 +03:00
|
|
|
char lcwd[MAXPATHLEN];
|
2010-09-13 19:36:57 +04:00
|
|
|
char latestdir[MAXPATHLEN];
|
|
|
|
char fname[MAXPATHLEN];
|
|
|
|
char fname1[MAXPATHLEN];
|
2010-12-10 01:30:16 +03:00
|
|
|
char fname2[MAXPATHLEN];
|
2015-04-11 08:24:30 +03:00
|
|
|
char fname3[MAXPATHLEN];
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr dname;
|
2016-06-03 04:16:27 +03:00
|
|
|
const char *tname;
|
2010-09-13 19:36:57 +04:00
|
|
|
char *p;
|
2013-10-01 09:37:17 +04:00
|
|
|
char *link_src;
|
|
|
|
char *move_target;
|
2011-03-06 20:41:11 +03:00
|
|
|
static size_t cwdlen = 0;
|
2011-02-08 08:29:13 +03:00
|
|
|
static size_t tmplen = 0;
|
2010-09-13 19:36:57 +04:00
|
|
|
FILE *fp;
|
2013-01-19 08:23:37 +04:00
|
|
|
Boolean needOODATE = FALSE;
|
2020-11-30 00:31:55 +03:00
|
|
|
StringList missingFiles;
|
2020-11-08 18:07:37 +03:00
|
|
|
Boolean have_filemon = FALSE;
|
2016-06-03 04:16:27 +03:00
|
|
|
|
When a source file moves, make will ignore the stale dependency,
but if the file in question is one that needs to be compiled (.c or .cc),
it still hands the bogus name to the compiler.
If Dir_MTime() cannot find such a file (gn->iParents is not empty),
see if the basename can be found via .PATH, and if so set gn->path to
the found file. This prevents the stale path being given to the
compiler.
In meta_oodate(), if a referenced file no longer exists, consider the
target out-of-date.
Also, if meta_oodate() decides a target is out-of-date, and it
it uses .OODATE in its commands, we need .OODATE recomputed.
Undo our call to Make_DoAllVar() so that the call from Make_OODate()
will do the right thing.
2010-11-27 08:02:35 +03:00
|
|
|
if (oodate)
|
|
|
|
return oodate; /* we're done */
|
|
|
|
|
2020-12-20 17:32:13 +03:00
|
|
|
dname = Var_Value(".OBJDIR", gn);
|
2020-10-31 14:54:33 +03:00
|
|
|
tname = GNode_VarTarget(gn);
|
2016-06-03 04:16:27 +03:00
|
|
|
|
|
|
|
/* if this succeeds fname3 is realpath of dname */
|
2020-12-20 17:32:13 +03:00
|
|
|
if (!meta_needed(gn, dname.str, fname3, FALSE))
|
2016-06-03 04:16:27 +03:00
|
|
|
goto oodate_out;
|
2020-12-20 17:32:13 +03:00
|
|
|
dname.str = fname3;
|
2016-06-03 04:16:27 +03:00
|
|
|
|
2020-11-30 00:31:55 +03:00
|
|
|
Lst_Init(&missingFiles);
|
2011-05-05 00:38:31 +04:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* We need to check if the target is out-of-date. This includes
|
|
|
|
* checking if the expanded command has changed. This in turn
|
|
|
|
* requires that all variables are set in the same way that they
|
|
|
|
* would be if the target needs to be re-built.
|
|
|
|
*/
|
|
|
|
Make_DoAllVar(gn);
|
|
|
|
|
2020-12-20 17:32:13 +03:00
|
|
|
meta_name(fname, sizeof fname, dname.str, tname, dname.str);
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2011-02-14 00:22:41 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "meta_oodate: %s\n", fname);
|
2011-02-14 00:22:41 +03:00
|
|
|
#endif
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
if ((fp = fopen(fname, "r")) != NULL) {
|
|
|
|
static char *buf = NULL;
|
|
|
|
static size_t bufsz;
|
|
|
|
int lineno = 0;
|
2010-12-10 01:30:16 +03:00
|
|
|
int lastpid = 0;
|
|
|
|
int pid;
|
2010-09-13 19:36:57 +04:00
|
|
|
int x;
|
2020-09-21 20:44:25 +03:00
|
|
|
StringListNode *cmdNode;
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
struct cached_stat cst;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-11-08 18:07:37 +03:00
|
|
|
if (buf == NULL) {
|
2010-09-13 19:36:57 +04:00
|
|
|
bufsz = 8 * BUFSIZ;
|
|
|
|
buf = bmake_malloc(bufsz);
|
|
|
|
}
|
2010-12-10 01:30:16 +03:00
|
|
|
|
2020-11-08 18:07:37 +03:00
|
|
|
if (cwdlen == 0) {
|
2020-11-05 20:27:16 +03:00
|
|
|
if (getcwd(cwd, sizeof cwd) == NULL)
|
2011-03-06 20:41:11 +03:00
|
|
|
err(1, "Could not get current working directory");
|
|
|
|
cwdlen = strlen(cwd);
|
|
|
|
}
|
2020-11-05 20:27:16 +03:00
|
|
|
strlcpy(lcwd, cwd, sizeof lcwd);
|
|
|
|
strlcpy(latestdir, cwd, sizeof latestdir);
|
2011-03-06 20:41:11 +03:00
|
|
|
|
2020-11-08 18:07:37 +03:00
|
|
|
if (tmpdir == NULL) {
|
2010-12-10 01:30:16 +03:00
|
|
|
tmpdir = getTmpdir();
|
|
|
|
tmplen = strlen(tmpdir);
|
|
|
|
}
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/* we want to track all the .meta we read */
|
|
|
|
Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
|
|
|
|
|
2020-11-28 21:55:52 +03:00
|
|
|
cmdNode = gn->commands.first;
|
2010-09-13 19:36:57 +04:00
|
|
|
while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
|
|
|
|
lineno++;
|
|
|
|
if (buf[x - 1] == '\n')
|
|
|
|
buf[x - 1] = '\0';
|
2011-06-23 01:13:12 +04:00
|
|
|
else {
|
2010-09-13 19:36:57 +04:00
|
|
|
warnx("%s: %d: line truncated at %u", fname, lineno, x);
|
2011-06-23 01:13:12 +04:00
|
|
|
oodate = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
2013-10-01 09:37:17 +04:00
|
|
|
link_src = NULL;
|
|
|
|
move_target = NULL;
|
2010-09-13 19:36:57 +04:00
|
|
|
/* Find the start of the build monitor section. */
|
2016-06-03 04:16:27 +03:00
|
|
|
if (!have_filemon) {
|
2010-09-13 19:36:57 +04:00
|
|
|
if (strncmp(buf, "-- filemon", 10) == 0) {
|
2016-06-03 04:16:27 +03:00
|
|
|
have_filemon = TRUE;
|
2010-09-13 19:36:57 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (strncmp(buf, "# buildmon", 10) == 0) {
|
2016-06-03 04:16:27 +03:00
|
|
|
have_filemon = TRUE;
|
2010-09-13 19:36:57 +04:00
|
|
|
continue;
|
|
|
|
}
|
2020-07-03 11:13:23 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
|
|
|
|
/* Delimit the record type. */
|
|
|
|
p = buf;
|
2011-02-08 08:29:13 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG3(META, "%s: %d: %s\n", fname, lineno, buf);
|
2011-02-08 08:29:13 +03:00
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
strsep(&p, " ");
|
2016-06-03 04:16:27 +03:00
|
|
|
if (have_filemon) {
|
2010-12-10 01:30:16 +03:00
|
|
|
/*
|
|
|
|
* We are in the 'filemon' output section.
|
|
|
|
* Each record from filemon follows the general form:
|
|
|
|
*
|
|
|
|
* <key> <pid> <data>
|
|
|
|
*
|
|
|
|
* Where:
|
|
|
|
* <key> is a single letter, denoting the syscall.
|
|
|
|
* <pid> is the process that made the syscall.
|
|
|
|
* <data> is the arguments (of interest).
|
|
|
|
*/
|
|
|
|
switch(buf[0]) {
|
|
|
|
case '#': /* comment */
|
|
|
|
case 'V': /* version */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* We need to track pathnames per-process.
|
|
|
|
*
|
2021-02-02 00:32:54 +03:00
|
|
|
* Each process run by make starts off in the 'CWD'
|
2010-12-10 01:30:16 +03:00
|
|
|
* recorded in the .meta file, if it chdirs ('C')
|
|
|
|
* elsewhere we need to track that - but only for
|
|
|
|
* that process. If it forks ('F'), we initialize
|
|
|
|
* the child to have the same cwd as its parent.
|
|
|
|
*
|
|
|
|
* We also need to track the 'latestdir' of
|
|
|
|
* interest. This is usually the same as cwd, but
|
|
|
|
* not if a process is reading directories.
|
|
|
|
*
|
|
|
|
* Each time we spot a different process ('pid')
|
|
|
|
* we save the current value of 'latestdir' in a
|
|
|
|
* variable qualified by 'lastpid', and
|
|
|
|
* re-initialize 'latestdir' to any pre-saved
|
|
|
|
* value for the current 'pid' and 'CWD' if none.
|
|
|
|
*/
|
2011-06-23 01:13:12 +04:00
|
|
|
CHECK_VALID_META(p);
|
2010-12-10 01:30:16 +03:00
|
|
|
pid = atoi(p);
|
|
|
|
if (pid > 0 && pid != lastpid) {
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr ldir;
|
2020-07-02 18:47:38 +03:00
|
|
|
|
2010-12-10 01:30:16 +03:00
|
|
|
if (lastpid > 0) {
|
2015-04-11 08:24:30 +03:00
|
|
|
/* We need to remember these. */
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(lcwd_vname, lcwd, VAR_GLOBAL);
|
|
|
|
Var_Set(ldir_vname, latestdir, VAR_GLOBAL);
|
2010-12-10 01:30:16 +03:00
|
|
|
}
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(lcwd_vname, sizeof lcwd_vname, LCWD_VNAME_FMT, pid);
|
|
|
|
snprintf(ldir_vname, sizeof ldir_vname, LDIR_VNAME_FMT, pid);
|
2010-12-10 01:30:16 +03:00
|
|
|
lastpid = pid;
|
2020-12-20 17:32:13 +03:00
|
|
|
ldir = Var_Value(ldir_vname, VAR_GLOBAL);
|
|
|
|
if (ldir.str != NULL) {
|
|
|
|
strlcpy(latestdir, ldir.str, sizeof latestdir);
|
|
|
|
FStr_Done(&ldir);
|
2015-04-11 08:24:30 +03:00
|
|
|
}
|
2020-12-20 17:32:13 +03:00
|
|
|
ldir = Var_Value(lcwd_vname, VAR_GLOBAL);
|
|
|
|
if (ldir.str != NULL) {
|
|
|
|
strlcpy(lcwd, ldir.str, sizeof lcwd);
|
|
|
|
FStr_Done(&ldir);
|
2015-04-11 08:24:30 +03:00
|
|
|
}
|
2010-12-10 01:30:16 +03:00
|
|
|
}
|
|
|
|
/* Skip past the pid. */
|
|
|
|
if (strsep(&p, " ") == NULL)
|
|
|
|
continue;
|
2011-02-08 08:29:13 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
|
|
|
if (DEBUG(META))
|
2020-09-29 01:23:35 +03:00
|
|
|
debug_printf("%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
|
|
|
|
fname, lineno,
|
|
|
|
pid, buf[0], cwd, lcwd, latestdir);
|
2011-02-08 08:29:13 +03:00
|
|
|
#endif
|
2010-12-10 01:30:16 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-06-23 01:13:12 +04:00
|
|
|
CHECK_VALID_META(p);
|
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/* Process according to record type. */
|
|
|
|
switch (buf[0]) {
|
2010-12-10 01:30:16 +03:00
|
|
|
case 'X': /* eXit */
|
2015-04-11 08:24:30 +03:00
|
|
|
Var_Delete(lcwd_vname, VAR_GLOBAL);
|
2010-12-10 01:30:16 +03:00
|
|
|
Var_Delete(ldir_vname, VAR_GLOBAL);
|
|
|
|
lastpid = 0; /* no need to save ldir_vname */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F': /* [v]Fork */
|
|
|
|
{
|
|
|
|
char cldir[64];
|
|
|
|
int child;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2010-12-10 01:30:16 +03:00
|
|
|
child = atoi(p);
|
|
|
|
if (child > 0) {
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(cldir, sizeof cldir, LCWD_VNAME_FMT, child);
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(cldir, lcwd, VAR_GLOBAL);
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(cldir, sizeof cldir, LDIR_VNAME_FMT, child);
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(cldir, latestdir, VAR_GLOBAL);
|
2015-04-11 08:24:30 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
|
|
|
if (DEBUG(META))
|
2020-09-29 01:23:35 +03:00
|
|
|
debug_printf(
|
|
|
|
"%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
|
|
|
|
fname, lineno,
|
|
|
|
child, cwd, lcwd, latestdir);
|
2015-04-11 08:24:30 +03:00
|
|
|
#endif
|
2010-12-10 01:30:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'C': /* Chdir */
|
2015-04-11 08:24:30 +03:00
|
|
|
/* Update lcwd and latest directory. */
|
2020-11-05 20:27:16 +03:00
|
|
|
strlcpy(latestdir, p, sizeof latestdir);
|
|
|
|
strlcpy(lcwd, p, sizeof lcwd);
|
2020-07-02 18:47:38 +03:00
|
|
|
Var_Set(lcwd_vname, lcwd, VAR_GLOBAL);
|
|
|
|
Var_Set(ldir_vname, lcwd, VAR_GLOBAL);
|
2015-04-11 08:24:30 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG4(META, "%s: %d: cwd=%s ldir=%s\n",
|
|
|
|
fname, lineno, cwd, lcwd);
|
2015-04-11 08:24:30 +03:00
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
break;
|
|
|
|
|
2011-05-05 00:38:31 +04:00
|
|
|
case 'M': /* renaMe */
|
2013-10-01 09:37:17 +04:00
|
|
|
/*
|
|
|
|
* For 'M'oves we want to check
|
|
|
|
* the src as for 'R'ead
|
|
|
|
* and the target as for 'W'rite.
|
|
|
|
*/
|
2020-12-21 01:12:36 +03:00
|
|
|
{
|
|
|
|
char *cp = p; /* save this for a second */
|
|
|
|
/* now get target */
|
|
|
|
if (strsep(&p, " ") == NULL)
|
|
|
|
continue;
|
|
|
|
CHECK_VALID_META(p);
|
|
|
|
move_target = p;
|
|
|
|
p = cp;
|
|
|
|
}
|
2011-05-05 00:38:31 +04:00
|
|
|
/* 'L' and 'M' put single quotes around the args */
|
2013-10-01 09:37:17 +04:00
|
|
|
DEQUOTE(p);
|
|
|
|
DEQUOTE(move_target);
|
2011-05-05 00:38:31 +04:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case 'D': /* unlink */
|
2020-10-24 13:17:21 +03:00
|
|
|
if (*p == '/') {
|
2016-08-10 21:25:00 +03:00
|
|
|
/* remove any missingFiles entries that match p */
|
2020-11-30 00:31:55 +03:00
|
|
|
StringListNode *ln = missingFiles.first;
|
2020-10-24 13:17:21 +03:00
|
|
|
while (ln != NULL) {
|
|
|
|
StringListNode *next = ln->next;
|
|
|
|
if (path_starts_with(ln->datum, p)) {
|
2020-10-30 18:39:17 +03:00
|
|
|
free(ln->datum);
|
2020-11-30 00:31:55 +03:00
|
|
|
Lst_Remove(&missingFiles, ln);
|
2020-10-24 13:17:21 +03:00
|
|
|
}
|
|
|
|
ln = next;
|
2011-05-05 00:38:31 +04:00
|
|
|
}
|
|
|
|
}
|
2013-10-01 09:37:17 +04:00
|
|
|
if (buf[0] == 'M') {
|
|
|
|
/* the target of the mv is a file 'W'ritten */
|
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG2(META, "meta_oodate: M %s -> %s\n",
|
|
|
|
p, move_target);
|
2013-10-01 09:37:17 +04:00
|
|
|
#endif
|
|
|
|
p = move_target;
|
|
|
|
goto check_write;
|
|
|
|
}
|
2011-05-05 00:38:31 +04:00
|
|
|
break;
|
|
|
|
case 'L': /* Link */
|
2013-10-01 09:37:17 +04:00
|
|
|
/*
|
|
|
|
* For 'L'inks check
|
|
|
|
* the src as for 'R'ead
|
|
|
|
* and the target as for 'W'rite.
|
|
|
|
*/
|
|
|
|
link_src = p;
|
|
|
|
/* now get target */
|
2011-05-05 00:38:31 +04:00
|
|
|
if (strsep(&p, " ") == NULL)
|
|
|
|
continue;
|
2011-06-23 01:13:12 +04:00
|
|
|
CHECK_VALID_META(p);
|
2011-05-05 00:38:31 +04:00
|
|
|
/* 'L' and 'M' put single quotes around the args */
|
2013-10-01 09:37:17 +04:00
|
|
|
DEQUOTE(p);
|
|
|
|
DEQUOTE(link_src);
|
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG2(META, "meta_oodate: L %s -> %s\n", link_src, p);
|
2013-10-01 09:37:17 +04:00
|
|
|
#endif
|
2011-05-05 00:38:31 +04:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case 'W': /* Write */
|
2013-10-01 09:37:17 +04:00
|
|
|
check_write:
|
2011-05-05 00:38:31 +04:00
|
|
|
/*
|
|
|
|
* If a file we generated within our bailiwick
|
|
|
|
* but outside of .OBJDIR is missing,
|
2020-07-03 11:13:23 +03:00
|
|
|
* we need to do it again.
|
2011-05-05 00:38:31 +04:00
|
|
|
*/
|
|
|
|
/* ignore non-absolute paths */
|
|
|
|
if (*p != '/')
|
|
|
|
break;
|
|
|
|
|
2020-11-30 00:28:06 +03:00
|
|
|
if (Lst_IsEmpty(&metaBailiwick))
|
2011-05-05 00:38:31 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* ignore cwd - normal dependencies handle those */
|
|
|
|
if (strncmp(p, cwd, cwdlen) == 0)
|
|
|
|
break;
|
|
|
|
|
2020-11-30 00:28:06 +03:00
|
|
|
if (!has_any_prefix(p, &metaBailiwick))
|
2011-05-05 00:38:31 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* tmpdir might be within */
|
|
|
|
if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* ignore anything containing the string "tmp" */
|
make(1): clean up make.h, meta.c, parse.c, str.c
The main changes are in the comments, which have been shortened and
corrected.
Some local variables changed their names.
In ParseErrorInternal, the scope of va_start is now narrower.
In ParseDoDependency, the type of tOp has been fixed.
ParseGetLine doesn't take flags anymore but instead a parsing mode.
Previously, the flags had not been combined anyway.
At the beginning of Parse_File, fatals is already guaranteed to be 0, and
even if not, it would be wrong to just discard the fatal errors.
2020-11-15 15:02:44 +03:00
|
|
|
/* XXX: The arguments to strstr must be swapped. */
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr("tmp", p) != NULL)
|
2011-05-05 00:38:31 +04:00
|
|
|
break;
|
|
|
|
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
if ((link_src != NULL && cached_lstat(p, &cst) < 0) ||
|
|
|
|
(link_src == NULL && cached_stat(p, &cst) < 0)) {
|
2020-10-24 13:32:25 +03:00
|
|
|
if (!meta_ignore(gn, p))
|
2020-11-30 00:31:55 +03:00
|
|
|
append_if_new(&missingFiles, p);
|
2011-05-05 00:38:31 +04:00
|
|
|
}
|
|
|
|
break;
|
2013-10-01 09:37:17 +04:00
|
|
|
check_link_src:
|
|
|
|
p = link_src;
|
|
|
|
link_src = NULL;
|
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "meta_oodate: L src %s\n", p);
|
2013-10-01 09:37:17 +04:00
|
|
|
#endif
|
|
|
|
/* FALLTHROUGH */
|
2010-12-10 01:30:16 +03:00
|
|
|
case 'R': /* Read */
|
|
|
|
case 'E': /* Exec */
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* Check for runtime files that can't
|
|
|
|
* be part of the dependencies because
|
|
|
|
* they are _expected_ to change.
|
|
|
|
*/
|
2016-08-17 18:52:42 +03:00
|
|
|
if (meta_ignore(gn, p))
|
|
|
|
break;
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
2010-12-10 01:30:16 +03:00
|
|
|
* The rest of the record is the file name.
|
|
|
|
* Check if it's not an absolute path.
|
2010-09-13 19:36:57 +04:00
|
|
|
*/
|
2010-12-10 01:30:16 +03:00
|
|
|
{
|
|
|
|
char *sdirs[4];
|
|
|
|
char **sdp;
|
|
|
|
int sdx = 0;
|
2020-11-24 02:41:11 +03:00
|
|
|
Boolean found = FALSE;
|
2010-12-10 01:30:16 +03:00
|
|
|
|
|
|
|
if (*p == '/') {
|
|
|
|
sdirs[sdx++] = p; /* done */
|
|
|
|
} else {
|
|
|
|
if (strcmp(".", p) == 0)
|
2020-11-23 23:41:20 +03:00
|
|
|
continue; /* no point */
|
2010-12-10 01:30:16 +03:00
|
|
|
|
|
|
|
/* Check vs latestdir */
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(fname1, sizeof fname1, "%s/%s", latestdir, p);
|
2010-12-10 01:30:16 +03:00
|
|
|
sdirs[sdx++] = fname1;
|
|
|
|
|
2015-04-11 08:24:30 +03:00
|
|
|
if (strcmp(latestdir, lcwd) != 0) {
|
|
|
|
/* Check vs lcwd */
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(fname2, sizeof fname2, "%s/%s", lcwd, p);
|
2010-12-10 01:30:16 +03:00
|
|
|
sdirs[sdx++] = fname2;
|
|
|
|
}
|
2015-04-11 08:24:30 +03:00
|
|
|
if (strcmp(lcwd, cwd) != 0) {
|
|
|
|
/* Check vs cwd */
|
2020-11-05 20:27:16 +03:00
|
|
|
snprintf(fname3, sizeof fname3, "%s/%s", cwd, p);
|
2015-04-11 08:24:30 +03:00
|
|
|
sdirs[sdx++] = fname3;
|
|
|
|
}
|
2010-12-10 01:30:16 +03:00
|
|
|
}
|
|
|
|
sdirs[sdx++] = NULL;
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2021-01-11 00:20:46 +03:00
|
|
|
for (sdp = sdirs; *sdp != NULL && !found; sdp++) {
|
2011-02-08 08:29:13 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG3(META, "%s: %d: looking for: %s\n",
|
|
|
|
fname, lineno, *sdp);
|
2011-02-08 08:29:13 +03:00
|
|
|
#endif
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
if (cached_stat(*sdp, &cst) == 0) {
|
2020-11-24 02:41:11 +03:00
|
|
|
found = TRUE;
|
2010-12-10 01:30:16 +03:00
|
|
|
p = *sdp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found) {
|
2011-02-08 08:29:13 +03:00
|
|
|
#ifdef DEBUG_META_MODE
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG3(META, "%s: %d: found: %s\n",
|
|
|
|
fname, lineno, p);
|
2011-02-08 08:29:13 +03:00
|
|
|
#endif
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
if (!S_ISDIR(cst.cst_mode) &&
|
|
|
|
cst.cst_mtime > gn->mtime) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG3(META, "%s: %d: file '%s' is newer than the target...\n",
|
|
|
|
fname, lineno, p);
|
2010-12-10 01:30:16 +03:00
|
|
|
oodate = TRUE;
|
make(1): remove redundant struct make_stat
In the cache for stat(2) and lstat(2), only one of the two timestamps
was ever used. To prevent a result from stat(2) leaking into the cache
for lstat(2), there have been two completely separate caches all the
time. Using different fields in the struct was therefore unnecessary.
By removing the redundant field, the internal struct in the cache is the
same as the external struct. This makes one of them redundant, thus
struct make_stat has been renamed to cached_stat, which better describes
its purpose, and the internal struct cache_st has been removed.
Just as before, the cache prevents any direct access to its internal
data. When passing it to the caller, it is copied.
Just as before, the field names of struct cached_stat cannot correspond
to those from struct stat, since the latter are often defined as macros.
Therefore they are prefixed with cst instead of st.
The redundancy had been added on 2020-06-05.
2020-11-14 22:24:24 +03:00
|
|
|
} else if (S_ISDIR(cst.cst_mode)) {
|
2010-12-10 01:30:16 +03:00
|
|
|
/* Update the latest directory. */
|
2016-06-03 04:21:59 +03:00
|
|
|
cached_realpath(p, latestdir);
|
2010-12-10 01:30:16 +03:00
|
|
|
}
|
|
|
|
} else if (errno == ENOENT && *p == '/' &&
|
|
|
|
strncmp(p, cwd, cwdlen) != 0) {
|
|
|
|
/*
|
|
|
|
* A referenced file outside of CWD is missing.
|
|
|
|
* We cannot catch every eventuality here...
|
|
|
|
*/
|
2020-11-30 00:31:55 +03:00
|
|
|
append_if_new(&missingFiles, p);
|
When a source file moves, make will ignore the stale dependency,
but if the file in question is one that needs to be compiled (.c or .cc),
it still hands the bogus name to the compiler.
If Dir_MTime() cannot find such a file (gn->iParents is not empty),
see if the basename can be found via .PATH, and if so set gn->path to
the found file. This prevents the stale path being given to the
compiler.
In meta_oodate(), if a referenced file no longer exists, consider the
target out-of-date.
Also, if meta_oodate() decides a target is out-of-date, and it
it uses .OODATE in its commands, we need .OODATE recomputed.
Undo our call to Make_DoAllVar() so that the call from Make_OODate()
will do the right thing.
2010-11-27 08:02:35 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2015-04-11 08:24:30 +03:00
|
|
|
if (buf[0] == 'E') {
|
|
|
|
/* previous latestdir is no longer relevant */
|
2020-11-05 20:27:16 +03:00
|
|
|
strlcpy(latestdir, lcwd, sizeof latestdir);
|
2015-04-11 08:24:30 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-10-01 09:37:17 +04:00
|
|
|
if (!oodate && buf[0] == 'L' && link_src != NULL)
|
|
|
|
goto check_link_src;
|
2010-12-10 01:30:16 +03:00
|
|
|
} else if (strcmp(buf, "CMD") == 0) {
|
2010-09-13 19:36:57 +04:00
|
|
|
/*
|
|
|
|
* Compare the current command with the one in the
|
|
|
|
* meta data file.
|
|
|
|
*/
|
2020-09-21 20:44:25 +03:00
|
|
|
if (cmdNode == NULL) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG2(META, "%s: %d: there were more build commands in the meta data file than there are now...\n",
|
|
|
|
fname, lineno);
|
2010-09-13 19:36:57 +04:00
|
|
|
oodate = TRUE;
|
|
|
|
} else {
|
2020-12-21 01:12:36 +03:00
|
|
|
const char *cp;
|
2020-10-20 00:57:37 +03:00
|
|
|
char *cmd = cmdNode->datum;
|
2013-03-31 09:49:51 +04:00
|
|
|
Boolean hasOODATE = FALSE;
|
|
|
|
|
2020-12-31 20:39:36 +03:00
|
|
|
if (strstr(cmd, "$?") != NULL)
|
2013-03-31 09:49:51 +04:00
|
|
|
hasOODATE = TRUE;
|
2020-12-31 20:39:36 +03:00
|
|
|
else if ((cp = strstr(cmd, ".OODATE")) != NULL) {
|
2013-03-31 09:49:51 +04:00
|
|
|
/* check for $[{(].OODATE[:)}] */
|
|
|
|
if (cp > cmd + 2 && cp[-2] == '$')
|
|
|
|
hasOODATE = TRUE;
|
|
|
|
}
|
|
|
|
if (hasOODATE) {
|
|
|
|
needOODATE = TRUE;
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG2(META, "%s: %d: cannot compare command using .OODATE\n",
|
|
|
|
fname, lineno);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2020-09-22 23:19:46 +03:00
|
|
|
(void)Var_Subst(cmd, gn, VARE_WANTRES|VARE_UNDEFERR, &cmd);
|
|
|
|
/* TODO: handle errors */
|
2010-09-13 19:36:57 +04:00
|
|
|
|
2020-12-31 20:39:36 +03:00
|
|
|
if ((cp = strchr(cmd, '\n')) != NULL) {
|
2010-09-13 19:36:57 +04:00
|
|
|
int n;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This command contains newlines, we need to
|
|
|
|
* fetch more from the .meta file before we
|
|
|
|
* attempt a comparison.
|
|
|
|
*/
|
|
|
|
/* first put the newline back at buf[x - 1] */
|
|
|
|
buf[x - 1] = '\n';
|
|
|
|
do {
|
|
|
|
/* now fetch the next line */
|
|
|
|
if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
|
|
|
|
break;
|
|
|
|
x = n;
|
|
|
|
lineno++;
|
|
|
|
if (buf[x - 1] != '\n') {
|
|
|
|
warnx("%s: %d: line truncated at %u", fname, lineno, x);
|
|
|
|
break;
|
|
|
|
}
|
2020-12-21 01:36:40 +03:00
|
|
|
cp = strchr(cp + 1, '\n');
|
2020-11-24 02:41:11 +03:00
|
|
|
} while (cp != NULL);
|
2010-09-13 19:36:57 +04:00
|
|
|
if (buf[x - 1] == '\n')
|
|
|
|
buf[x - 1] = '\0';
|
|
|
|
}
|
2020-11-07 13:16:18 +03:00
|
|
|
if (p != NULL &&
|
2020-04-03 06:32:28 +03:00
|
|
|
!hasOODATE &&
|
2010-09-13 19:36:57 +04:00
|
|
|
!(gn->type & OP_NOMETA_CMP) &&
|
2020-11-07 13:16:18 +03:00
|
|
|
(strcmp(p, cmd) != 0)) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG4(META, "%s: %d: a build command has changed\n%s\nvs\n%s\n",
|
|
|
|
fname, lineno, p, cmd);
|
2010-09-13 19:36:57 +04:00
|
|
|
if (!metaIgnoreCMDs)
|
|
|
|
oodate = TRUE;
|
|
|
|
}
|
|
|
|
free(cmd);
|
2020-09-26 20:15:20 +03:00
|
|
|
cmdNode = cmdNode->next;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
} else if (strcmp(buf, "CWD") == 0) {
|
2011-03-29 21:29:20 +04:00
|
|
|
/*
|
|
|
|
* Check if there are extra commands now
|
|
|
|
* that weren't in the meta data file.
|
|
|
|
*/
|
2020-09-21 20:44:25 +03:00
|
|
|
if (!oodate && cmdNode != NULL) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG2(META, "%s: %d: there are extra build commands now that weren't in the meta data file\n",
|
|
|
|
fname, lineno);
|
2011-03-29 21:29:20 +04:00
|
|
|
oodate = TRUE;
|
|
|
|
}
|
2020-03-19 02:53:02 +03:00
|
|
|
CHECK_VALID_META(p);
|
2011-03-06 20:41:11 +03:00
|
|
|
if (strcmp(p, cwd) != 0) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG4(META, "%s: %d: the current working directory has changed from '%s' to '%s'\n",
|
|
|
|
fname, lineno, p, curdir);
|
2010-09-13 19:36:57 +04:00
|
|
|
oodate = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
2020-11-30 00:31:55 +03:00
|
|
|
if (!Lst_IsEmpty(&missingFiles)) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG2(META, "%s: missing files: %s...\n",
|
2020-11-30 00:31:55 +03:00
|
|
|
fname, (char *)missingFiles.first->datum);
|
2011-05-05 00:38:31 +04:00
|
|
|
oodate = TRUE;
|
|
|
|
}
|
2016-06-05 01:17:14 +03:00
|
|
|
if (!oodate && !have_filemon && filemonMissing) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "%s: missing filemon data\n", fname);
|
2011-08-18 04:00:21 +04:00
|
|
|
oodate = TRUE;
|
|
|
|
}
|
2016-06-05 01:17:14 +03:00
|
|
|
} else {
|
2020-07-11 03:39:53 +03:00
|
|
|
if (writeMeta && (metaMissing || (gn->type & OP_META))) {
|
2020-12-21 01:12:36 +03:00
|
|
|
const char *cp = NULL;
|
2016-02-27 19:17:26 +03:00
|
|
|
|
2016-06-05 01:17:14 +03:00
|
|
|
/* if target is in .CURDIR we do not need a meta file */
|
2021-01-11 00:20:46 +03:00
|
|
|
if (gn->path != NULL && (cp = strrchr(gn->path, '/')) != NULL &&
|
|
|
|
(cp > gn->path)) {
|
2020-10-18 14:54:43 +03:00
|
|
|
if (strncmp(curdir, gn->path, (size_t)(cp - gn->path)) != 0) {
|
2016-06-05 01:17:14 +03:00
|
|
|
cp = NULL; /* not in .CURDIR */
|
|
|
|
}
|
|
|
|
}
|
2020-11-08 18:07:37 +03:00
|
|
|
if (cp == NULL) {
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(META, "%s: required but missing\n", fname);
|
2016-06-05 01:17:14 +03:00
|
|
|
oodate = TRUE;
|
2016-06-14 21:16:06 +03:00
|
|
|
needOODATE = TRUE; /* assume the worst */
|
2016-06-05 01:17:14 +03:00
|
|
|
}
|
|
|
|
}
|
2016-06-03 04:16:27 +03:00
|
|
|
}
|
|
|
|
|
2020-11-30 00:31:55 +03:00
|
|
|
Lst_DoneCall(&missingFiles, free);
|
2016-02-27 19:17:26 +03:00
|
|
|
|
2013-01-19 08:23:37 +04:00
|
|
|
if (oodate && needOODATE) {
|
When a source file moves, make will ignore the stale dependency,
but if the file in question is one that needs to be compiled (.c or .cc),
it still hands the bogus name to the compiler.
If Dir_MTime() cannot find such a file (gn->iParents is not empty),
see if the basename can be found via .PATH, and if so set gn->path to
the found file. This prevents the stale path being given to the
compiler.
In meta_oodate(), if a referenced file no longer exists, consider the
target out-of-date.
Also, if meta_oodate() decides a target is out-of-date, and it
it uses .OODATE in its commands, we need .OODATE recomputed.
Undo our call to Make_DoAllVar() so that the call from Make_OODate()
will do the right thing.
2010-11-27 08:02:35 +03:00
|
|
|
/*
|
2013-01-19 08:23:37 +04:00
|
|
|
* Target uses .OODATE which is empty; or we wouldn't be here.
|
|
|
|
* We have decided it is oodate, so .OODATE needs to be set.
|
|
|
|
* All we can sanely do is set it to .ALLSRC.
|
When a source file moves, make will ignore the stale dependency,
but if the file in question is one that needs to be compiled (.c or .cc),
it still hands the bogus name to the compiler.
If Dir_MTime() cannot find such a file (gn->iParents is not empty),
see if the basename can be found via .PATH, and if so set gn->path to
the found file. This prevents the stale path being given to the
compiler.
In meta_oodate(), if a referenced file no longer exists, consider the
target out-of-date.
Also, if meta_oodate() decides a target is out-of-date, and it
it uses .OODATE in its commands, we need .OODATE recomputed.
Undo our call to Make_DoAllVar() so that the call from Make_OODate()
will do the right thing.
2010-11-27 08:02:35 +03:00
|
|
|
*/
|
|
|
|
Var_Delete(OODATE, gn);
|
2020-10-31 14:54:33 +03:00
|
|
|
Var_Set(OODATE, GNode_VarAllsrc(gn), gn);
|
When a source file moves, make will ignore the stale dependency,
but if the file in question is one that needs to be compiled (.c or .cc),
it still hands the bogus name to the compiler.
If Dir_MTime() cannot find such a file (gn->iParents is not empty),
see if the basename can be found via .PATH, and if so set gn->path to
the found file. This prevents the stale path being given to the
compiler.
In meta_oodate(), if a referenced file no longer exists, consider the
target out-of-date.
Also, if meta_oodate() decides a target is out-of-date, and it
it uses .OODATE in its commands, we need .OODATE recomputed.
Undo our call to Make_DoAllVar() so that the call from Make_OODate()
will do the right thing.
2010-11-27 08:02:35 +03:00
|
|
|
}
|
2016-06-03 04:16:27 +03:00
|
|
|
|
|
|
|
oodate_out:
|
2020-12-20 17:32:13 +03:00
|
|
|
FStr_Done(&dname);
|
2010-09-13 19:36:57 +04:00
|
|
|
return oodate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* support for compat mode */
|
|
|
|
|
|
|
|
static int childPipe[2];
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_compat_start(void)
|
|
|
|
{
|
2019-12-19 10:14:07 +03:00
|
|
|
#ifdef USE_FILEMON_ONCE
|
|
|
|
/*
|
|
|
|
* We need to re-open filemon for each cmd.
|
|
|
|
*/
|
|
|
|
BuildMon *pbm = &Mybm;
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2019-12-19 10:14:07 +03:00
|
|
|
if (pbm->mfp != NULL && useFilemon) {
|
2020-01-19 22:42:32 +03:00
|
|
|
meta_open_filemon(pbm);
|
2019-12-19 10:14:07 +03:00
|
|
|
} else {
|
2020-01-19 22:42:32 +03:00
|
|
|
pbm->mon_fd = -1;
|
|
|
|
pbm->filemon = NULL;
|
2019-12-19 10:14:07 +03:00
|
|
|
}
|
|
|
|
#endif
|
2010-09-13 19:36:57 +04:00
|
|
|
if (pipe(childPipe) < 0)
|
|
|
|
Punt("Cannot create pipe: %s", strerror(errno));
|
|
|
|
/* Set close-on-exec flag for both */
|
2016-01-17 18:30:23 +03:00
|
|
|
(void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC);
|
|
|
|
(void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC);
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_compat_child(void)
|
|
|
|
{
|
|
|
|
meta_job_child(NULL);
|
2020-10-18 10:46:04 +03:00
|
|
|
if (dup2(childPipe[1], 1) < 0 || dup2(1, 2) < 0)
|
|
|
|
execDie("dup2", "pipe");
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-01-19 22:42:32 +03:00
|
|
|
meta_compat_parent(pid_t child)
|
2010-09-13 19:36:57 +04:00
|
|
|
{
|
2020-01-19 22:42:32 +03:00
|
|
|
int outfd, metafd, maxfd, nfds;
|
2020-02-06 04:13:19 +03:00
|
|
|
char buf[BUFSIZ+1];
|
2020-01-19 22:42:32 +03:00
|
|
|
fd_set readfds;
|
|
|
|
|
|
|
|
meta_job_parent(NULL, child);
|
2010-09-13 19:36:57 +04:00
|
|
|
close(childPipe[1]); /* child side */
|
2020-01-19 22:42:32 +03:00
|
|
|
outfd = childPipe[0];
|
2020-02-12 19:50:37 +03:00
|
|
|
#ifdef USE_FILEMON
|
2021-01-11 00:20:46 +03:00
|
|
|
metafd = Mybm.filemon != NULL ? filemon_readfd(Mybm.filemon) : -1;
|
2020-02-12 19:50:37 +03:00
|
|
|
#else
|
|
|
|
metafd = -1;
|
|
|
|
#endif
|
2020-01-19 22:42:32 +03:00
|
|
|
maxfd = -1;
|
|
|
|
if (outfd > maxfd)
|
|
|
|
maxfd = outfd;
|
|
|
|
if (metafd > maxfd)
|
|
|
|
maxfd = metafd;
|
|
|
|
|
|
|
|
while (outfd != -1 || metafd != -1) {
|
|
|
|
FD_ZERO(&readfds);
|
|
|
|
if (outfd != -1) {
|
|
|
|
FD_SET(outfd, &readfds);
|
|
|
|
}
|
|
|
|
if (metafd != -1) {
|
|
|
|
FD_SET(metafd, &readfds);
|
|
|
|
}
|
|
|
|
nfds = select(maxfd + 1, &readfds, NULL, NULL, NULL);
|
|
|
|
if (nfds == -1) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
err(1, "select");
|
|
|
|
}
|
|
|
|
|
2021-01-11 00:20:46 +03:00
|
|
|
if (outfd != -1 && FD_ISSET(outfd, &readfds) != 0) do {
|
2020-01-19 22:42:32 +03:00
|
|
|
/* XXX this is not line-buffered */
|
2020-11-05 20:27:16 +03:00
|
|
|
ssize_t nread = read(outfd, buf, sizeof buf - 1);
|
2020-01-19 22:42:32 +03:00
|
|
|
if (nread == -1)
|
|
|
|
err(1, "read");
|
|
|
|
if (nread == 0) {
|
|
|
|
close(outfd);
|
|
|
|
outfd = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fwrite(buf, 1, (size_t)nread, stdout);
|
|
|
|
fflush(stdout);
|
2020-02-06 04:13:19 +03:00
|
|
|
buf[nread] = '\0';
|
|
|
|
meta_job_output(NULL, buf, "");
|
2021-01-16 23:49:31 +03:00
|
|
|
} while (/*CONSTCOND*/FALSE);
|
2021-01-11 00:20:46 +03:00
|
|
|
if (metafd != -1 && FD_ISSET(metafd, &readfds) != 0) {
|
2020-01-19 22:42:32 +03:00
|
|
|
if (meta_job_event(NULL) <= 0)
|
|
|
|
metafd = -1;
|
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
}
|
2010-09-14 01:31:59 +04:00
|
|
|
|
2020-11-29 12:27:40 +03:00
|
|
|
#endif /* USE_META */
|