2021-12-15 16:03:33 +03:00
|
|
|
/* $NetBSD: compat.c,v 1.233 2021/12/15 13:03:33 rillig Exp $ */
|
1995-06-14 19:18:37 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
2003-08-07 15:13:06 +04:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Adam de Boor.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
1993-03-21 12:45:37 +03:00
|
|
|
* Copyright (c) 1988, 1989 by Adam de Boor
|
|
|
|
* Copyright (c) 1989 by Berkeley Softworks
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Adam de Boor.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2021-01-19 23:51:46 +03:00
|
|
|
/*
|
1993-03-21 12:45:37 +03:00
|
|
|
* compat.c --
|
|
|
|
* The routines in this file implement the full-compatibility
|
|
|
|
* mode of PMake. Most of the special functionality of PMake
|
|
|
|
* is available in this mode. Things not supported:
|
|
|
|
* - different shells.
|
|
|
|
* - friendly variable substitution.
|
|
|
|
*
|
|
|
|
* Interface:
|
2020-09-28 00:35:16 +03:00
|
|
|
* Compat_Run Initialize things for this module and recreate
|
|
|
|
* thems as need creatin'
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
|
2020-10-05 22:27:47 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
2002-06-15 22:24:55 +04:00
|
|
|
|
2020-10-05 22:27:47 +03:00
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
2002-06-15 22:24:55 +04:00
|
|
|
|
2020-10-05 22:27:47 +03:00
|
|
|
#include "make.h"
|
|
|
|
#include "dir.h"
|
|
|
|
#include "job.h"
|
|
|
|
#include "metachar.h"
|
|
|
|
#include "pathnames.h"
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2020-09-13 18:15:51 +03:00
|
|
|
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
|
2021-12-15 16:03:33 +03:00
|
|
|
MAKE_RCSID("$NetBSD: compat.c,v 1.233 2021/12/15 13:03:33 rillig Exp $");
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2020-10-05 22:27:47 +03:00
|
|
|
static GNode *curTarg = NULL;
|
2017-07-20 22:29:54 +03:00
|
|
|
static pid_t compatChild;
|
|
|
|
static int compatSigno;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2016-08-27 02:28:39 +03:00
|
|
|
/*
|
2020-11-02 23:50:24 +03:00
|
|
|
* CompatDeleteTarget -- delete the file of a failed, interrupted, or
|
|
|
|
* otherwise duffed target if not inhibited by .PRECIOUS.
|
2016-08-27 02:28:39 +03:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
CompatDeleteTarget(GNode *gn)
|
|
|
|
{
|
2020-11-23 22:35:10 +03:00
|
|
|
if (gn != NULL && !Targ_Precious(gn)) {
|
|
|
|
const char *file = GNode_VarTarget(gn);
|
2016-08-27 02:28:39 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
if (!opts.noExecute && eunlink(file) != -1) {
|
|
|
|
Error("*** %s removed", file);
|
|
|
|
}
|
2016-08-27 02:28:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-30 13:03:16 +03:00
|
|
|
/*
|
|
|
|
* Interrupt the creation of the current target and remove it if it ain't
|
2020-08-29 15:36:20 +03:00
|
|
|
* precious. Then exit.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
2020-08-29 15:36:20 +03:00
|
|
|
* If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
2016-08-27 02:28:39 +03:00
|
|
|
* XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've
|
|
|
|
* left the logic alone for now. - dholland 20160826
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
static void
|
2002-06-15 22:24:55 +04:00
|
|
|
CompatInterrupt(int signo)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2020-11-23 22:35:10 +03:00
|
|
|
CompatDeleteTarget(curTarg);
|
|
|
|
|
|
|
|
if (curTarg != NULL && !Targ_Precious(curTarg)) {
|
|
|
|
/*
|
|
|
|
* Run .INTERRUPT only if hit with interrupt signal
|
|
|
|
*/
|
|
|
|
if (signo == SIGINT) {
|
|
|
|
GNode *gn = Targ_FindNode(".INTERRUPT");
|
|
|
|
if (gn != NULL) {
|
|
|
|
Compat_Make(gn, gn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (signo == SIGQUIT)
|
|
|
|
_exit(signo);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
2020-11-23 22:35:10 +03:00
|
|
|
* If there is a child running, pass the signal on.
|
|
|
|
* We will exist after it has exited.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2020-11-23 22:35:10 +03:00
|
|
|
compatSigno = signo;
|
|
|
|
if (compatChild > 0) {
|
|
|
|
KILLPG(compatChild, signo);
|
|
|
|
} else {
|
|
|
|
bmake_signal(signo, SIG_DFL);
|
|
|
|
kill(myPid, signo);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-22 11:01:34 +03:00
|
|
|
|
2020-11-23 22:14:24 +03:00
|
|
|
static void
|
2021-04-27 18:19:25 +03:00
|
|
|
DebugFailedTarget(const char *cmd, const GNode *gn)
|
2020-11-23 22:14:24 +03:00
|
|
|
{
|
|
|
|
const char *p = cmd;
|
|
|
|
debug_printf("\n*** Failed target: %s\n*** Failed command: ",
|
2021-12-15 16:03:33 +03:00
|
|
|
gn->name);
|
2020-11-23 22:14:24 +03:00
|
|
|
|
2021-12-15 15:58:01 +03:00
|
|
|
/*
|
|
|
|
* Replace runs of whitespace with a single space, to reduce the
|
|
|
|
* amount of whitespace for multi-line command lines.
|
|
|
|
*/
|
2020-11-23 22:14:24 +03:00
|
|
|
while (*p != '\0') {
|
|
|
|
if (ch_isspace(*p)) {
|
|
|
|
debug_printf(" ");
|
|
|
|
cpp_skip_whitespace(&p);
|
|
|
|
} else {
|
|
|
|
debug_printf("%c", *p);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debug_printf("\n");
|
|
|
|
}
|
|
|
|
|
2021-04-03 14:08:40 +03:00
|
|
|
static bool
|
2020-12-13 19:14:40 +03:00
|
|
|
UseShell(const char *cmd MAKE_ATTR_UNUSED)
|
|
|
|
{
|
|
|
|
#if !defined(MAKE_NATIVE)
|
|
|
|
/*
|
|
|
|
* In a non-native build, the host environment might be weird enough
|
|
|
|
* that it's necessary to go through a shell to get the correct
|
|
|
|
* behaviour. Or perhaps the shell has been replaced with something
|
|
|
|
* that does extra logging, and that should not be bypassed.
|
|
|
|
*/
|
2021-04-03 14:08:40 +03:00
|
|
|
return true;
|
2020-12-13 19:14:40 +03:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* Search for meta characters in the command. If there are no meta
|
|
|
|
* characters, there's no need to execute a shell to execute the
|
|
|
|
* command.
|
|
|
|
*
|
|
|
|
* Additionally variable assignments and empty commands
|
|
|
|
* go to the shell. Therefore treat '=' and ':' like shell
|
|
|
|
* meta characters as documented in make(1).
|
|
|
|
*/
|
|
|
|
|
|
|
|
return needshell(cmd);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-12-30 13:03:16 +03:00
|
|
|
/*
|
|
|
|
* Execute the next command for a target. If the command returns an error,
|
2020-10-05 22:27:47 +03:00
|
|
|
* the node's made field is set to ERROR and creation stops.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
2002-06-15 22:24:55 +04:00
|
|
|
* Input:
|
|
|
|
* cmdp Command to execute
|
2020-12-21 00:07:32 +03:00
|
|
|
* gn Node from which the command came
|
|
|
|
* ln List node that contains the command
|
2002-06-15 22:24:55 +04:00
|
|
|
*
|
1993-03-21 12:45:37 +03:00
|
|
|
* Results:
|
2021-12-15 13:04:49 +03:00
|
|
|
* true if the command succeeded.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2021-12-15 13:04:49 +03:00
|
|
|
bool
|
2020-12-21 00:07:32 +03:00
|
|
|
Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2020-11-23 22:35:10 +03:00
|
|
|
char *cmdStart; /* Start of expanded command */
|
|
|
|
char *bp;
|
2021-04-03 14:08:40 +03:00
|
|
|
bool silent; /* Don't print command */
|
|
|
|
bool doIt; /* Execute even if -n */
|
2021-12-15 16:03:33 +03:00
|
|
|
volatile bool errCheck; /* Check errors */
|
2020-11-23 22:35:10 +03:00
|
|
|
int reason; /* Reason for child's death */
|
|
|
|
int status; /* Description of child's death */
|
|
|
|
pid_t cpid; /* Child actually found */
|
|
|
|
pid_t retstat; /* Result of wait */
|
|
|
|
const char **volatile av; /* Argument vector for thing to exec */
|
|
|
|
char **volatile mav; /* Copy of the argument vector for freeing */
|
2021-12-15 16:03:33 +03:00
|
|
|
bool useShell; /* True if command should be executed using a
|
|
|
|
* shell */
|
2020-11-23 22:35:10 +03:00
|
|
|
const char *volatile cmd = cmdp;
|
|
|
|
|
2021-11-29 02:12:51 +03:00
|
|
|
silent = (gn->type & OP_SILENT) != OP_NONE;
|
2020-11-23 22:35:10 +03:00
|
|
|
errCheck = !(gn->type & OP_IGNORE);
|
2021-04-03 14:08:40 +03:00
|
|
|
doIt = false;
|
2020-11-23 22:35:10 +03:00
|
|
|
|
|
|
|
(void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart);
|
|
|
|
/* TODO: handle errors */
|
|
|
|
|
|
|
|
if (cmdStart[0] == '\0') {
|
|
|
|
free(cmdStart);
|
2021-12-15 13:04:49 +03:00
|
|
|
return true;
|
2020-11-23 22:35:10 +03:00
|
|
|
}
|
|
|
|
cmd = cmdStart;
|
2020-12-21 00:07:32 +03:00
|
|
|
LstNode_Set(ln, cmdStart);
|
2020-11-23 22:35:10 +03:00
|
|
|
|
|
|
|
if (gn->type & OP_SAVE_CMDS) {
|
|
|
|
GNode *endNode = Targ_GetEndNode();
|
|
|
|
if (gn != endNode) {
|
2020-12-13 21:57:44 +03:00
|
|
|
/*
|
|
|
|
* Append the expanded command, to prevent the
|
|
|
|
* local variables from being interpreted in the
|
2021-02-05 00:42:46 +03:00
|
|
|
* scope of the .END node.
|
2020-12-13 21:57:44 +03:00
|
|
|
*
|
|
|
|
* A probably unintended side effect of this is that
|
|
|
|
* the expanded command will be expanded again in the
|
|
|
|
* .END node. Therefore, a literal '$' in these
|
|
|
|
* commands must be written as '$$$$' instead of the
|
|
|
|
* usual '$$'.
|
|
|
|
*/
|
2020-11-28 21:55:52 +03:00
|
|
|
Lst_Append(&endNode->commands, cmdStart);
|
2021-12-15 13:04:49 +03:00
|
|
|
return true;
|
2020-11-23 22:35:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strcmp(cmdStart, "...") == 0) {
|
|
|
|
gn->type |= OP_SAVE_CMDS;
|
2021-12-15 13:04:49 +03:00
|
|
|
return true;
|
2020-09-23 06:06:38 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
for (;;) {
|
|
|
|
if (*cmd == '@')
|
|
|
|
silent = !DEBUG(LOUD);
|
|
|
|
else if (*cmd == '-')
|
2021-04-03 14:08:40 +03:00
|
|
|
errCheck = false;
|
2020-11-23 22:35:10 +03:00
|
|
|
else if (*cmd == '+') {
|
2021-04-03 14:08:40 +03:00
|
|
|
doIt = true;
|
2021-01-11 00:20:46 +03:00
|
|
|
if (shellName == NULL) /* we came here from jobs */
|
2020-11-23 22:35:10 +03:00
|
|
|
Shell_Init();
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
cmd++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (ch_isspace(*cmd))
|
|
|
|
cmd++;
|
1996-11-06 20:58:58 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
/*
|
|
|
|
* If we did not end up with a command, just skip it.
|
|
|
|
*/
|
|
|
|
if (cmd[0] == '\0')
|
2021-12-15 13:04:49 +03:00
|
|
|
return true;
|
2012-05-31 01:42:04 +04:00
|
|
|
|
2020-12-13 19:14:40 +03:00
|
|
|
useShell = UseShell(cmd);
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
2020-11-23 22:35:10 +03:00
|
|
|
* Print the command before echoing if we're not supposed to be quiet
|
|
|
|
* for this one. We also print the command if -n given.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2020-11-23 22:35:10 +03:00
|
|
|
if (!silent || !GNode_ShouldExecute(gn)) {
|
|
|
|
printf("%s\n", cmd);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
2020-11-23 22:35:10 +03:00
|
|
|
* If we're not supposed to execute any commands, this is as far as
|
|
|
|
* we go...
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2020-11-23 22:35:10 +03:00
|
|
|
if (!doIt && !GNode_ShouldExecute(gn))
|
2021-12-15 13:04:49 +03:00
|
|
|
return true;
|
1996-11-06 20:58:58 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
DEBUG1(JOB, "Execute: '%s'\n", cmd);
|
|
|
|
|
|
|
|
if (useShell) {
|
|
|
|
/*
|
|
|
|
* We need to pass the command off to the shell, typically
|
|
|
|
* because the command contains a "meta" character.
|
|
|
|
*/
|
|
|
|
static const char *shargv[5];
|
|
|
|
|
|
|
|
/* The following work for any of the builtin shell specs. */
|
|
|
|
int shargc = 0;
|
|
|
|
shargv[shargc++] = shellPath;
|
2021-01-11 00:20:46 +03:00
|
|
|
if (errCheck && shellErrFlag != NULL)
|
2020-11-23 22:35:10 +03:00
|
|
|
shargv[shargc++] = shellErrFlag;
|
|
|
|
shargv[shargc++] = DEBUG(SHELL) ? "-xc" : "-c";
|
|
|
|
shargv[shargc++] = cmd;
|
|
|
|
shargv[shargc] = NULL;
|
|
|
|
av = shargv;
|
|
|
|
bp = NULL;
|
|
|
|
mav = NULL;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No meta-characters, so no need to exec a shell. Break the
|
|
|
|
* command into words to form an argument vector we can
|
|
|
|
* execute.
|
|
|
|
*/
|
2021-04-03 14:08:40 +03:00
|
|
|
Words words = Str_Words(cmd, false);
|
2020-11-23 22:35:10 +03:00
|
|
|
mav = words.words;
|
|
|
|
bp = words.freeIt;
|
|
|
|
av = (void *)mav;
|
|
|
|
}
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
#ifdef USE_META
|
|
|
|
if (useMeta) {
|
2020-11-23 22:35:10 +03:00
|
|
|
meta_compat_start();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-12-27 08:16:26 +03:00
|
|
|
Var_ReexportVars();
|
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
/*
|
|
|
|
* Fork and execute the single command. If the fork fails, we abort.
|
|
|
|
*/
|
make: always use vfork, never fork
Before compat.c 1.217, job.c 1.390 and main.c 1.504 from 2020-12-27, the
exported make variables were exported from each freshly forked child
process. There was no practical difference though between exporting the
variables from the parent process or the child process since these two
processes share the same address space, except that the forked process
is very limited in what it may actually do. This limitation was
violated on a regular basis.
When an exported variable referred to a variable that used the :sh
variable modifier, this led to a fork from within vfork, which is not
allowed. Since 2020-12-27, exporting the variables is done from the
main process, which prevents this situation from ever occurring.
Since that day, there is no need anymore to distinguish between vfork
and fork, which removes any need for the macro.
2021-02-02 00:04:10 +03:00
|
|
|
compatChild = cpid = vfork();
|
2020-11-23 22:35:10 +03:00
|
|
|
if (cpid < 0) {
|
|
|
|
Fatal("Could not fork");
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
2020-11-23 22:35:10 +03:00
|
|
|
if (cpid == 0) {
|
|
|
|
#ifdef USE_META
|
|
|
|
if (useMeta) {
|
|
|
|
meta_compat_child();
|
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
#endif
|
2020-11-23 22:35:10 +03:00
|
|
|
(void)execvp(av[0], (char *const *)UNCONST(av));
|
|
|
|
execDie("exec", av[0]);
|
|
|
|
}
|
2016-01-17 20:45:21 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
free(mav);
|
|
|
|
free(bp);
|
2016-01-17 20:45:21 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
/* XXX: Memory management looks suspicious here. */
|
|
|
|
/* XXX: Setting a list item to NULL is unexpected. */
|
2020-12-21 00:07:32 +03:00
|
|
|
LstNode_SetNull(ln);
|
1996-11-06 20:58:58 +03:00
|
|
|
|
2010-09-13 19:36:57 +04:00
|
|
|
#ifdef USE_META
|
2020-11-23 22:35:10 +03:00
|
|
|
if (useMeta) {
|
|
|
|
meta_compat_parent(cpid);
|
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
#endif
|
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
/*
|
|
|
|
* The child is off and running. Now all we can do is wait...
|
|
|
|
*/
|
|
|
|
while ((retstat = wait(&reason)) != cpid) {
|
|
|
|
if (retstat > 0)
|
2021-04-03 14:08:40 +03:00
|
|
|
JobReapChild(retstat, reason, false); /* not ours? */
|
2020-11-23 22:35:10 +03:00
|
|
|
if (retstat == -1 && errno != EINTR) {
|
|
|
|
break;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2020-09-13 09:36:54 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
if (retstat < 0)
|
|
|
|
Fatal("error in wait: %d: %s", retstat, strerror(errno));
|
1996-11-06 20:58:58 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
if (WIFSTOPPED(reason)) {
|
|
|
|
status = WSTOPSIG(reason); /* stopped */
|
|
|
|
} else if (WIFEXITED(reason)) {
|
|
|
|
status = WEXITSTATUS(reason); /* exited */
|
2019-12-19 10:14:07 +03:00
|
|
|
#if defined(USE_META) && defined(USE_FILEMON_ONCE)
|
2020-11-23 22:35:10 +03:00
|
|
|
if (useMeta) {
|
2021-12-15 15:24:13 +03:00
|
|
|
meta_cmd_finish(NULL);
|
2020-11-23 22:35:10 +03:00
|
|
|
}
|
2019-12-19 10:14:07 +03:00
|
|
|
#endif
|
2020-11-23 22:35:10 +03:00
|
|
|
if (status != 0) {
|
|
|
|
if (DEBUG(ERROR))
|
|
|
|
DebugFailedTarget(cmd, gn);
|
|
|
|
printf("*** Error code %d", status);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status = WTERMSIG(reason); /* signaled */
|
|
|
|
printf("*** Signal %d", status);
|
2020-09-13 09:36:54 +03:00
|
|
|
}
|
1996-11-06 20:58:58 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
if (!WIFEXITED(reason) || status != 0) {
|
|
|
|
if (errCheck) {
|
2010-09-13 19:36:57 +04:00
|
|
|
#ifdef USE_META
|
2020-11-23 22:35:10 +03:00
|
|
|
if (useMeta) {
|
2021-04-03 14:08:40 +03:00
|
|
|
meta_job_error(NULL, gn, false, status);
|
2020-11-23 22:35:10 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
#endif
|
2020-11-23 22:35:10 +03:00
|
|
|
gn->made = ERROR;
|
|
|
|
if (opts.keepgoing) {
|
|
|
|
/*
|
|
|
|
* Abort the current target,
|
|
|
|
* but let others continue.
|
|
|
|
*/
|
|
|
|
printf(" (continuing)\n");
|
|
|
|
} else {
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
if (deleteOnError)
|
|
|
|
CompatDeleteTarget(gn);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Continue executing commands for this target.
|
|
|
|
* If we return 0, this will happen...
|
|
|
|
*/
|
|
|
|
printf(" (ignored)\n");
|
|
|
|
status = 0;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2020-09-13 09:36:54 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
free(cmdStart);
|
|
|
|
compatChild = 0;
|
2020-11-24 02:41:11 +03:00
|
|
|
if (compatSigno != 0) {
|
2020-11-23 22:35:10 +03:00
|
|
|
bmake_signal(compatSigno, SIG_DFL);
|
|
|
|
kill(myPid, compatSigno);
|
|
|
|
}
|
2020-07-03 11:13:23 +03:00
|
|
|
|
2021-12-15 13:04:49 +03:00
|
|
|
return status == 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2020-08-22 11:01:34 +03:00
|
|
|
|
2020-09-27 14:43:46 +03:00
|
|
|
static void
|
|
|
|
RunCommands(GNode *gn)
|
2020-09-12 18:03:39 +03:00
|
|
|
{
|
2020-11-23 22:35:10 +03:00
|
|
|
StringListNode *ln;
|
|
|
|
|
2020-11-28 21:55:52 +03:00
|
|
|
for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
|
2020-11-23 22:35:10 +03:00
|
|
|
const char *cmd = ln->datum;
|
2021-12-15 13:04:49 +03:00
|
|
|
if (!Compat_RunCommand(cmd, gn, ln))
|
2020-11-23 22:35:10 +03:00
|
|
|
break;
|
|
|
|
}
|
2020-09-12 18:03:39 +03:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:42 +03:00
|
|
|
static void
|
|
|
|
MakeNodes(GNodeList *gnodes, GNode *pgn)
|
2020-09-12 18:10:55 +03:00
|
|
|
{
|
2020-11-23 22:35:10 +03:00
|
|
|
GNodeListNode *ln;
|
|
|
|
|
|
|
|
for (ln = gnodes->first; ln != NULL; ln = ln->next) {
|
|
|
|
GNode *cohort = ln->datum;
|
|
|
|
Compat_Make(cohort, pgn);
|
|
|
|
}
|
2020-09-12 18:10:55 +03:00
|
|
|
}
|
|
|
|
|
2021-04-03 14:08:40 +03:00
|
|
|
static bool
|
2020-12-12 03:33:25 +03:00
|
|
|
MakeUnmade(GNode *gn, GNode *pgn)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2020-11-24 20:42:31 +03:00
|
|
|
|
|
|
|
assert(gn->made == UNMADE);
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* First mark ourselves to be made, then apply whatever transformations
|
|
|
|
* the suffix module thinks are necessary. Once that's done, we can
|
|
|
|
* descend and make all our children. If any of them has an error
|
2021-04-03 14:08:40 +03:00
|
|
|
* but the -k flag was given, our 'make' field will be set to false
|
2020-11-07 17:32:12 +03:00
|
|
|
* again. This is our signal to not attempt to do anything but abort
|
|
|
|
* our parent as well.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2021-11-28 22:51:06 +03:00
|
|
|
gn->flags.remake = true;
|
1993-03-21 12:45:37 +03:00
|
|
|
gn->made = BEINGMADE;
|
2020-11-24 20:42:31 +03:00
|
|
|
|
2020-10-05 22:27:47 +03:00
|
|
|
if (!(gn->type & OP_MADE))
|
2020-11-23 22:27:20 +03:00
|
|
|
Suff_FindDeps(gn);
|
2020-11-24 20:42:31 +03:00
|
|
|
|
2020-11-28 22:12:28 +03:00
|
|
|
MakeNodes(&gn->children, gn);
|
2020-11-24 20:42:31 +03:00
|
|
|
|
2021-11-28 22:51:06 +03:00
|
|
|
if (!gn->flags.remake) {
|
2020-11-23 22:27:20 +03:00
|
|
|
gn->made = ABORTED;
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.remake = false;
|
2021-04-03 14:08:40 +03:00
|
|
|
return false;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2020-11-28 22:22:32 +03:00
|
|
|
if (Lst_FindDatum(&gn->implicitParents, pgn) != NULL)
|
2021-02-05 08:15:12 +03:00
|
|
|
Var_Set(pgn, IMPSRC, GNode_VarTarget(gn));
|
1996-11-06 20:58:58 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
2020-10-23 22:48:17 +03:00
|
|
|
* All the children were made ok. Now youngestChild->mtime contains the
|
2010-11-26 00:31:08 +03:00
|
|
|
* modification time of the newest child, we need to find out if we
|
|
|
|
* exist and when we were modified last. The criteria for datedness
|
2020-11-08 11:33:07 +03:00
|
|
|
* are defined by GNode_IsOODate.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2020-09-28 23:46:11 +03:00
|
|
|
DEBUG1(MAKE, "Examining %s...", gn->name);
|
2020-11-08 11:33:07 +03:00
|
|
|
if (!GNode_IsOODate(gn)) {
|
2020-11-23 22:27:20 +03:00
|
|
|
gn->made = UPTODATE;
|
|
|
|
DEBUG0(MAKE, "up-to-date.\n");
|
2021-04-03 14:08:40 +03:00
|
|
|
return false;
|
2020-11-24 20:42:31 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user is just seeing if something is out-of-date, exit now
|
|
|
|
* to tell him/her "yes".
|
|
|
|
*/
|
2020-11-24 20:42:31 +03:00
|
|
|
DEBUG0(MAKE, "out-of-date.\n");
|
2020-11-16 01:31:03 +03:00
|
|
|
if (opts.queryFlag)
|
2020-11-23 22:27:20 +03:00
|
|
|
exit(1);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
2020-11-24 20:42:31 +03:00
|
|
|
* We need to be re-made.
|
|
|
|
* Ensure that $? (.OODATE) and $> (.ALLSRC) are both set.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2021-04-04 13:05:08 +03:00
|
|
|
GNode_SetLocalVars(gn);
|
1996-11-06 20:58:58 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Alter our type to tell if errors should be ignored or things
|
2020-12-13 21:12:29 +03:00
|
|
|
* should not be printed so Compat_RunCommand knows what to do.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2020-12-12 03:05:05 +03:00
|
|
|
if (opts.ignoreErrors)
|
2020-11-23 22:27:20 +03:00
|
|
|
gn->type |= OP_IGNORE;
|
2020-12-12 03:05:05 +03:00
|
|
|
if (opts.beSilent)
|
2020-11-23 22:27:20 +03:00
|
|
|
gn->type |= OP_SILENT;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-02-16 18:11:52 +03:00
|
|
|
if (Job_CheckCommands(gn, Fatal)) {
|
2020-11-23 22:27:20 +03:00
|
|
|
/*
|
|
|
|
* Our commands are ok, but we still have to worry about
|
|
|
|
* the -t flag.
|
|
|
|
*/
|
|
|
|
if (!opts.touchFlag || (gn->type & OP_MAKE)) {
|
|
|
|
curTarg = gn;
|
2010-09-13 19:36:57 +04:00
|
|
|
#ifdef USE_META
|
2020-11-23 22:27:20 +03:00
|
|
|
if (useMeta && GNode_ShouldExecute(gn)) {
|
|
|
|
meta_job_start(NULL, gn);
|
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
#endif
|
2020-11-23 22:27:20 +03:00
|
|
|
RunCommands(gn);
|
|
|
|
curTarg = NULL;
|
|
|
|
} else {
|
2021-11-29 02:12:51 +03:00
|
|
|
Job_Touch(gn, (gn->type & OP_SILENT) != OP_NONE);
|
2020-11-23 22:27:20 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
} else {
|
2020-11-23 22:27:20 +03:00
|
|
|
gn->made = ERROR;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2010-09-13 19:36:57 +04:00
|
|
|
#ifdef USE_META
|
2020-11-01 20:47:26 +03:00
|
|
|
if (useMeta && GNode_ShouldExecute(gn)) {
|
2020-11-23 22:27:20 +03:00
|
|
|
if (meta_job_finish(NULL) != 0)
|
|
|
|
gn->made = ERROR;
|
2010-09-13 19:36:57 +04:00
|
|
|
}
|
|
|
|
#endif
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
if (gn->made != ERROR) {
|
2020-11-23 22:27:20 +03:00
|
|
|
/*
|
|
|
|
* If the node was made successfully, mark it so, update
|
|
|
|
* its modification time and timestamp all its parents.
|
|
|
|
* This is to keep its state from affecting that of its parent.
|
|
|
|
*/
|
|
|
|
gn->made = MADE;
|
|
|
|
if (Make_Recheck(gn) == 0)
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.force = true;
|
2020-11-23 22:27:20 +03:00
|
|
|
if (!(gn->type & OP_EXEC)) {
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.childMade = true;
|
2020-11-23 22:27:20 +03:00
|
|
|
GNode_UpdateYoungestChild(pgn, gn);
|
|
|
|
}
|
2020-10-27 00:34:10 +03:00
|
|
|
} else if (opts.keepgoing) {
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.remake = false;
|
1993-03-21 12:45:37 +03:00
|
|
|
} else {
|
2020-11-23 22:27:20 +03:00
|
|
|
PrintOnError(gn, "\nStop.");
|
|
|
|
exit(1);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2021-04-03 14:08:40 +03:00
|
|
|
return true;
|
2020-11-23 22:27:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
MakeOther(GNode *gn, GNode *pgn)
|
|
|
|
{
|
|
|
|
|
2020-11-28 22:22:32 +03:00
|
|
|
if (Lst_FindDatum(&gn->implicitParents, pgn) != NULL) {
|
2020-11-23 22:27:20 +03:00
|
|
|
const char *target = GNode_VarTarget(gn);
|
2021-02-05 08:15:12 +03:00
|
|
|
Var_Set(pgn, IMPSRC, target != NULL ? target : "");
|
2014-09-08 00:55:34 +04:00
|
|
|
}
|
2020-11-23 22:27:20 +03:00
|
|
|
|
2020-11-23 22:35:10 +03:00
|
|
|
switch (gn->made) {
|
2020-11-23 22:27:20 +03:00
|
|
|
case BEINGMADE:
|
2002-03-21 04:24:43 +03:00
|
|
|
Error("Graph cycles through %s", gn->name);
|
1993-03-21 12:45:37 +03:00
|
|
|
gn->made = ERROR;
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.remake = false;
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
2020-11-23 22:27:20 +03:00
|
|
|
case MADE:
|
2020-11-07 13:16:18 +03:00
|
|
|
if (!(gn->type & OP_EXEC)) {
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.childMade = true;
|
2020-11-23 22:27:20 +03:00
|
|
|
GNode_UpdateYoungestChild(pgn, gn);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
break;
|
2020-11-23 22:27:20 +03:00
|
|
|
case UPTODATE:
|
2020-11-07 13:16:18 +03:00
|
|
|
if (!(gn->type & OP_EXEC))
|
2020-11-23 22:27:20 +03:00
|
|
|
GNode_UpdateYoungestChild(pgn, gn);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
2020-11-23 22:27:20 +03:00
|
|
|
default:
|
1994-03-05 03:34:29 +03:00
|
|
|
break;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2020-11-23 22:27:20 +03:00
|
|
|
}
|
|
|
|
|
2020-12-30 13:03:16 +03:00
|
|
|
/*
|
|
|
|
* Make a target.
|
2020-11-23 22:27:20 +03:00
|
|
|
*
|
|
|
|
* If an error is detected and not being ignored, the process exits.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* gn The node to make
|
|
|
|
* pgn Parent to abort if necessary
|
2020-11-24 19:28:44 +03:00
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* gn->made
|
|
|
|
* UPTODATE gn was already up-to-date.
|
|
|
|
* MADE gn was recreated successfully.
|
|
|
|
* ERROR An error occurred while gn was being created,
|
|
|
|
* either due to missing commands or in -k mode.
|
|
|
|
* ABORTED gn was not remade because one of its
|
|
|
|
* dependencies could not be made due to errors.
|
2020-11-23 22:27:20 +03:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
Compat_Make(GNode *gn, GNode *pgn)
|
|
|
|
{
|
2020-11-23 22:35:10 +03:00
|
|
|
if (shellName == NULL) /* we came here from jobs */
|
|
|
|
Shell_Init();
|
|
|
|
|
|
|
|
if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) {
|
|
|
|
if (!MakeUnmade(gn, pgn))
|
|
|
|
goto cohorts;
|
2020-11-24 21:17:45 +03:00
|
|
|
|
|
|
|
/* XXX: Replace with GNode_IsError(gn) */
|
2020-11-23 22:35:10 +03:00
|
|
|
} else if (gn->made == ERROR) {
|
|
|
|
/*
|
|
|
|
* Already had an error when making this.
|
|
|
|
* Tell the parent to abort.
|
|
|
|
*/
|
2021-11-28 22:51:06 +03:00
|
|
|
pgn->flags.remake = false;
|
2020-11-23 22:35:10 +03:00
|
|
|
} else {
|
|
|
|
MakeOther(gn, pgn);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1999-09-16 04:49:48 +04:00
|
|
|
cohorts:
|
2020-11-28 22:20:03 +03:00
|
|
|
MakeNodes(&gn->cohorts, pgn);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2020-08-22 11:01:34 +03:00
|
|
|
|
2020-12-13 19:30:08 +03:00
|
|
|
static void
|
|
|
|
MakeBeginNode(void)
|
|
|
|
{
|
|
|
|
GNode *gn = Targ_FindNode(".BEGIN");
|
|
|
|
if (gn == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Compat_Make(gn, gn);
|
|
|
|
if (GNode_IsError(gn)) {
|
|
|
|
PrintOnError(gn, "\nStop.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-13 19:32:57 +03:00
|
|
|
static void
|
|
|
|
InitSignals(void)
|
|
|
|
{
|
|
|
|
if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN)
|
|
|
|
bmake_signal(SIGINT, CompatInterrupt);
|
|
|
|
if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN)
|
|
|
|
bmake_signal(SIGTERM, CompatInterrupt);
|
|
|
|
if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN)
|
|
|
|
bmake_signal(SIGHUP, CompatInterrupt);
|
|
|
|
if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN)
|
|
|
|
bmake_signal(SIGQUIT, CompatInterrupt);
|
|
|
|
}
|
|
|
|
|
2020-12-30 13:03:16 +03:00
|
|
|
/*
|
|
|
|
* Initialize this module and start making.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
2002-06-15 22:24:55 +04:00
|
|
|
* Input:
|
2020-08-29 15:36:20 +03:00
|
|
|
* targs The target nodes to re-create
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
void
|
2020-09-22 07:05:41 +03:00
|
|
|
Compat_Run(GNodeList *targs)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2020-12-13 22:33:53 +03:00
|
|
|
GNode *errorNode = NULL;
|
2020-11-23 22:35:10 +03:00
|
|
|
|
2021-01-11 00:20:46 +03:00
|
|
|
if (shellName == NULL)
|
2020-11-23 22:35:10 +03:00
|
|
|
Shell_Init();
|
|
|
|
|
2020-12-13 19:32:57 +03:00
|
|
|
InitSignals();
|
2020-11-23 22:35:10 +03:00
|
|
|
|
2021-12-15 15:58:01 +03:00
|
|
|
/*
|
|
|
|
* Create the .END node now, to keep the (debug) output of the
|
|
|
|
* counter.mk test the same as before 2020-09-23. This
|
|
|
|
* implementation detail probably doesn't matter though.
|
|
|
|
*/
|
2020-11-23 22:35:10 +03:00
|
|
|
(void)Targ_GetEndNode();
|
|
|
|
|
2020-12-13 19:30:08 +03:00
|
|
|
if (!opts.queryFlag)
|
|
|
|
MakeBeginNode();
|
2020-11-23 22:35:10 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Expand .USE nodes right now, because they can modify the structure
|
|
|
|
* of the tree.
|
|
|
|
*/
|
|
|
|
Make_ExpandUse(targs);
|
|
|
|
|
|
|
|
while (!Lst_IsEmpty(targs)) {
|
2020-12-13 22:33:53 +03:00
|
|
|
GNode *gn = Lst_Dequeue(targs);
|
2020-11-23 22:35:10 +03:00
|
|
|
Compat_Make(gn, gn);
|
|
|
|
|
|
|
|
if (gn->made == UPTODATE) {
|
|
|
|
printf("`%s' is up to date.\n", gn->name);
|
|
|
|
} else if (gn->made == ABORTED) {
|
|
|
|
printf("`%s' not remade because of errors.\n",
|
2021-12-15 15:24:13 +03:00
|
|
|
gn->name);
|
2020-11-23 22:35:10 +03:00
|
|
|
}
|
2020-12-13 22:33:53 +03:00
|
|
|
if (GNode_IsError(gn) && errorNode == NULL)
|
|
|
|
errorNode = gn;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2020-11-23 22:35:10 +03:00
|
|
|
|
2020-12-07 04:35:33 +03:00
|
|
|
/* If the user has defined a .END target, run its commands. */
|
2020-12-13 22:33:53 +03:00
|
|
|
if (errorNode == NULL) {
|
2020-11-23 22:35:10 +03:00
|
|
|
GNode *endNode = Targ_GetEndNode();
|
|
|
|
Compat_Make(endNode, endNode);
|
2020-12-13 22:33:53 +03:00
|
|
|
if (GNode_IsError(endNode))
|
|
|
|
errorNode = endNode;
|
2020-12-07 04:10:03 +03:00
|
|
|
}
|
2020-12-07 02:02:56 +03:00
|
|
|
|
2020-12-13 22:33:53 +03:00
|
|
|
if (errorNode != NULL) {
|
2021-02-02 20:47:56 +03:00
|
|
|
if (DEBUG(GRAPH2))
|
|
|
|
Targ_PrintGraph(2);
|
|
|
|
else if (DEBUG(GRAPH3))
|
|
|
|
Targ_PrintGraph(3);
|
2020-12-13 22:33:53 +03:00
|
|
|
PrintOnError(errorNode, "\nStop.");
|
2020-12-07 02:02:56 +03:00
|
|
|
exit(1);
|
2001-10-16 22:50:12 +04:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|