make/commands.c
Roland McGrath e99a3aca7e Thu May 9 13:54:49 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* GNUmakefile (globfiles): Add AmigaDOS support files.
	(distfiles): Add $(amigafiles).
	(amigafiles): New variable.

Thu Nov  7 10:18:16 1995  Aaron Digulla   <digulla@fh-konstanz.de>

	* Added Amiga support in commands.c, dir.c, function.c,
	job.c, main.c, make.h, read.c, remake.c
	* commands.c: Amiga has neither SIGHUP nor SIGQUIT
	* dir.c: Amiga has filenames with Upper- and Lowercase,
	but "FileName" is the same as "filename". Added strieq()
	which is use to compare filenames. This is like streq()
	on all other systems. Also there is no such thing as
	"." under AmigaDOS.
	* function.c: On Amiga, the environment is not passed as envp,
	there are no pipes and Amiga can't fork. Use my own function
	to create a new child.
	* job.c: default_shell is "" (The system automatically chooses
	a shell for me). Have to use the same workaround as MSDOS for
	running batch commands. Added HAVE_SYS_PARAM_H. NOFILE isn't
	known on Amiga. Cloned code to run children from MSDOS. Own
	version of sh_chars[] and sh_cmds[]. No dup2() or dup() on Amiga.
	* main.c: Force stack to 20000 bytes. Read environment from ENV:
	device. On Amiga, exec_command() does return, so I exit()
	afterwards.
	* make.h: Added strieq() to compare filenames.
	* read.c: Amiga needs special extension to have passwd. Only
	one include-dir. "Makefile" and "makefile" are the same.
	Added "SMakefile".  Added special code to handle device names (xxx:)
	and "./" in rules.
	* remake.c: Only one lib-dir. Amiga link-libs are named "%s.lib"
	instead of "lib%s.a".
	* main.c, rule.c, variable.c: Avoid floats at all costs.
	* vpath.c: Get rid of as many alloca()s as possible.
1996-05-09 18:02:06 +00:00

547 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Command processing for GNU Make.
Copyright (C) 1988, 89, 91, 92, 93, 94, 95 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Make is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
#include "dep.h"
#include "filedef.h"
#include "variable.h"
#include "job.h"
#include "commands.h"
extern int remote_kill PARAMS ((int id, int sig));
#ifndef HAVE_UNISTD_H
extern int getpid ();
#endif
/* Set FILE's automatic variables up. */
static void
set_file_variables (file)
register struct file *file;
{
register char *p;
char *at, *percent, *star, *less;
#ifndef NO_ARCHIVES
/* If the target is an archive member `lib(member)',
then $@ is `lib' and $% is `member'. */
if (ar_name (file->name))
{
unsigned int len;
p = index (file->name, '(');
at = (char *) alloca (p - file->name + 1);
bcopy (file->name, at, p - file->name);
at[p - file->name] = '\0';
len = strlen (p + 1);
percent = (char *) alloca (len);
bcopy (p + 1, percent, len - 1);
percent[len - 1] = '\0';
}
else
#endif /* NO_ARCHIVES. */
{
at = file->name;
percent = "";
}
/* $* is the stem from an implicit or static pattern rule. */
if (file->stem == 0)
{
/* In Unix make, $* is set to the target name with
any suffix in the .SUFFIXES list stripped off for
explicit rules. We store this in the `stem' member. */
register struct dep *d;
char *name;
unsigned int len;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
name = index (file->name, '(') + 1;
len = strlen (name) - 1;
}
else
#endif
{
name = file->name;
len = strlen (name);
}
for (d = enter_file (".SUFFIXES")->deps; d != 0; d = d->next)
{
unsigned int slen = strlen (dep_name (d));
if (len > slen && !strncmp (dep_name (d), name + (len - slen), slen))
{
file->stem = savestring (name, len - slen);
break;
}
}
if (d == 0)
file->stem = "";
}
star = file->stem;
/* $< is the first dependency. */
less = file->deps != 0 ? dep_name (file->deps) : "";
if (file->cmds == default_file->cmds)
/* This file got its commands from .DEFAULT.
In this case $< is the same as $@. */
less = at;
#define DEFINE_VARIABLE(name, len, value) \
(void) define_variable_for_file (name, len, value, o_automatic, 0, file)
/* Define the variables. */
DEFINE_VARIABLE ("<", 1, less);
DEFINE_VARIABLE ("*", 1, star);
DEFINE_VARIABLE ("@", 1, at);
DEFINE_VARIABLE ("%", 1, percent);
/* Compute the values for $^, $+, and $?. */
{
register unsigned int qmark_len, plus_len;
char *caret_value, *plus_value;
register char *cp;
char *qmark_value;
register char *qp;
register struct dep *d;
unsigned int len;
/* Compute first the value for $+, which is supposed to contain
duplicate dependencies as they were listed in the makefile. */
plus_len = 0;
for (d = file->deps; d != 0; d = d->next)
plus_len += strlen (dep_name (d)) + 1;
len = plus_len == 0 ? 1 : plus_len;
cp = plus_value = (char *) alloca (len);
qmark_len = plus_len; /* Will be this or less. */
for (d = file->deps; d != 0; d = d->next)
{
char *c = dep_name (d);
#ifndef NO_ARCHIVES
if (ar_name (c))
{
c = index (c, '(') + 1;
len = strlen (c) - 1;
}
else
#endif
len = strlen (c);
bcopy (c, cp, len);
cp += len;
#if VMS
*cp++ = ',';
#else
*cp++ = ' ';
#endif
if (! d->changed)
qmark_len -= len + 1; /* Don't space in $? for this one. */
}
/* Kill the last space and define the variable. */
cp[cp > plus_value ? -1 : 0] = '\0';
DEFINE_VARIABLE ("+", 1, plus_value);
/* Make sure that no dependencies are repeated. This does not
really matter for the purpose of updating targets, but it
might make some names be listed twice for $^ and $?. */
uniquize_deps (file->deps);
/* Compute the values for $^ and $?. */
cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */
len = qmark_len == 0 ? 1 : qmark_len;
qp = qmark_value = (char *) alloca (len);
for (d = file->deps; d != 0; d = d->next)
{
char *c = dep_name (d);
#ifndef NO_ARCHIVES
if (ar_name (c))
{
c = index (c, '(') + 1;
len = strlen (c) - 1;
}
else
#endif
len = strlen (c);
bcopy (c, cp, len);
cp += len;
#if VMS
*cp++ = ',';
#else
*cp++ = ' ';
#endif
if (d->changed)
{
bcopy (c, qp, len);
qp += len;
#if VMS
*qp++ = ',';
#else
*qp++ = ' ';
#endif
}
}
/* Kill the last spaces and define the variables. */
cp[cp > caret_value ? -1 : 0] = '\0';
DEFINE_VARIABLE ("^", 1, caret_value);
qp[qp > qmark_value ? -1 : 0] = '\0';
DEFINE_VARIABLE ("?", 1, qmark_value);
}
#undef DEFINE_VARIABLE
}
/* Chop CMDS up into individual command lines if necessary.
Also set the `lines_flag' and `any_recurse' members. */
void
chop_commands (cmds)
register struct commands *cmds;
{
if (cmds != 0 && cmds->command_lines == 0)
{
/* Chop CMDS->commands up into lines in CMDS->command_lines.
Also set the corresponding CMDS->lines_flags elements,
and the CMDS->any_recurse flag. */
register char *p;
unsigned int nlines, idx;
char **lines;
nlines = 5;
lines = (char **) xmalloc (5 * sizeof (char *));
idx = 0;
p = cmds->commands;
while (*p != '\0')
{
char *end = p;
find_end:;
end = index (end, '\n');
if (end == 0)
end = p + strlen (p);
else if (end > p && end[-1] == '\\')
{
int backslash = 1;
register char *b;
for (b = end - 2; b >= p && *b == '\\'; --b)
backslash = !backslash;
if (backslash)
{
++end;
goto find_end;
}
}
if (idx == nlines)
{
nlines += 2;
lines = (char **) xrealloc ((char *) lines,
nlines * sizeof (char *));
}
lines[idx++] = savestring (p, end - p);
p = end;
if (*p != '\0')
++p;
}
if (idx != nlines)
{
nlines = idx;
lines = (char **) xrealloc ((char *) lines,
nlines * sizeof (char *));
}
cmds->ncommand_lines = nlines;
cmds->command_lines = lines;
cmds->any_recurse = 0;
cmds->lines_flags = (char *) xmalloc (nlines);
for (idx = 0; idx < nlines; ++idx)
{
int flags = 0;
for (p = lines[idx];
isblank (*p) || *p == '-' || *p == '@' || *p == '+';
++p)
switch (*p)
{
case '+':
flags |= COMMANDS_RECURSE;
break;
case '@':
flags |= COMMANDS_SILENT;
break;
case '-':
flags |= COMMANDS_NOERROR;
break;
}
if (!(flags & COMMANDS_RECURSE))
{
unsigned int len = strlen (p);
if (sindex (p, len, "$(MAKE)", 7) != 0
|| sindex (p, len, "${MAKE}", 7) != 0)
flags |= COMMANDS_RECURSE;
}
cmds->lines_flags[idx] = flags;
cmds->any_recurse |= flags & COMMANDS_RECURSE;
}
}
}
/* Execute the commands to remake FILE. If they are currently executing,
return or have already finished executing, just return. Otherwise,
fork off a child process to run the first command line in the sequence. */
void
execute_file_commands (file)
struct file *file;
{
register char *p;
/* Don't go through all the preparations if
the commands are nothing but whitespace. */
for (p = file->cmds->commands; *p != '\0'; ++p)
if (!isspace (*p) && *p != '-' && *p != '@')
break;
if (*p == '\0')
{
/* We are all out of commands.
If we have gotten this far, all the previous commands
have run successfully, so we have winning update status. */
file->update_status = 0;
notice_finished_file (file);
return;
}
/* First set the automatic variables according to this file. */
initialize_file_variables (file);
set_file_variables (file);
/* Start the commands running. */
new_job (file);
}
/* This is set while we are inside fatal_error_signal,
so things can avoid nonreentrant operations. */
int handling_fatal_signal = 0;
/* Handle fatal signals. */
RETSIGTYPE
fatal_error_signal (sig)
int sig;
{
#if defined(__MSDOS__) || defined(_AMIGA)
remove_intermediates (1);
#ifdef _AMIGA
if (sig == SIGINT)
fputs ("*** Break.\n", stderr);
exit (10);
#else
exit (1);
#endif
#else /* Not MSDOS. */
handling_fatal_signal = 1;
/* Set the handling for this signal to the default.
It is blocked now while we run this handler. */
signal (sig, SIG_DFL);
/* A termination signal won't be sent to the entire
process group, but it means we want to kill the children. */
if (sig == SIGTERM)
{
register struct child *c;
for (c = children; c != 0; c = c->next)
if (!c->remote)
(void) kill (c->pid, SIGTERM);
}
/* If we got a signal that means the user
wanted to kill make, remove pending targets. */
if (sig == SIGTERM || sig == SIGINT
#ifdef SIGHUP
|| sig == SIGHUP
#endif
#ifdef SIGQUIT
|| sig == SIGQUIT
#endif
)
{
register struct child *c;
/* Remote children won't automatically get signals sent
to the process group, so we must send them. */
for (c = children; c != 0; c = c->next)
if (c->remote)
(void) remote_kill (c->pid, sig);
for (c = children; c != 0; c = c->next)
delete_child_targets (c);
/* Clean up the children. We don't just use the call below because
we don't want to print the "Waiting for children" message. */
while (job_slots_used > 0)
reap_children (1, 0);
}
else
/* Wait for our children to die. */
while (job_slots_used > 0)
reap_children (1, 1);
/* Delete any non-precious intermediate files that were made. */
remove_intermediates (1);
if (sig == SIGQUIT)
/* We don't want to send ourselves SIGQUIT, because it will
cause a core dump. Just exit instead. */
exit (EXIT_FAILURE);
/* Signal the same code; this time it will really be fatal. The signal
will be unblocked when we return and arrive then to kill us. */
if (kill (getpid (), sig) < 0)
pfatal_with_name ("kill");
#endif /* MSDOS. */
}
/* Delete FILE unless it's precious or not actually a file (phony),
and it has changed on disk since we last stat'd it. */
static void
delete_target (file, on_behalf_of)
struct file *file;
char *on_behalf_of;
{
struct stat st;
if (file->precious || file->phony)
return;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
if (ar_member_date (file->name) != file->last_mtime)
{
if (on_behalf_of)
error ("*** [%s] Archive member `%s' may be bogus; not deleted",
on_behalf_of, file->name);
else
error ("*** Archive member `%s' may be bogus; not deleted",
file->name);
}
return;
}
#endif
if (stat (file->name, &st) == 0
&& S_ISREG (st.st_mode)
&& (time_t) st.st_mtime != file->last_mtime)
{
if (on_behalf_of)
error ("*** [%s] Deleting file `%s'", on_behalf_of, file->name);
else
error ("*** Deleting file `%s'", file->name);
if (unlink (file->name) < 0
&& errno != ENOENT) /* It disappeared; so what. */
perror_with_name ("unlink: ", file->name);
}
}
/* Delete all non-precious targets of CHILD unless they were already deleted.
Set the flag in CHILD to say they've been deleted. */
void
delete_child_targets (child)
struct child *child;
{
struct dep *d;
if (child->deleted)
return;
/* Delete the target file if it changed. */
delete_target (child->file, (char *) 0);
/* Also remove any non-precious targets listed in the `also_make' member. */
for (d = child->file->also_make; d != 0; d = d->next)
delete_target (d->file, child->file->name);
child->deleted = 1;
}
/* Print out the commands in CMDS. */
void
print_commands (cmds)
register struct commands *cmds;
{
register char *s;
fputs ("# commands to execute", stdout);
if (cmds->filename == 0)
puts (" (built-in):");
else
printf (" (from `%s', line %u):\n", cmds->filename, cmds->lineno);
s = cmds->commands;
while (*s != '\0')
{
char *end;
while (isspace (*s))
++s;
end = index (s, '\n');
if (end == 0)
end = s + strlen (s);
printf ("\t%.*s\n", (int) (end - s), s);
s = end;
}
}