| /* Command processing for GNU Make. |
| Copyright (C) 1988,89,91,92,93,94,95,96,97 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; |
| { |
| #ifdef __MSDOS__ |
| extern int dos_status, dos_command_running; |
| |
| if (dos_command_running) |
| { |
| /* That was the child who got the signal, not us. */ |
| dos_status |= (sig << 8); |
| return; |
| } |
| remove_intermediates (1); |
| exit (1); |
| #else /* not __MSDOS__ */ |
| #ifdef _AMIGA |
| remove_intermediates (1); |
| if (sig == SIGINT) |
| fputs ("*** Break.\n", stderr); |
| |
| exit (10); |
| #else /* not Amiga */ |
| 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); |
| |
| #ifdef SIGQUIT |
| if (sig == SIGQUIT) |
| /* We don't want to send ourselves SIGQUIT, because it will |
| cause a core dump. Just exit instead. */ |
| exit (EXIT_FAILURE); |
| #endif |
| |
| /* 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 /* not Amiga */ |
| #endif /* not __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; |
| } |
| } |