| /* Command processing for GNU Make. | |
| Copyright (C) 1988-2025 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 3 of the License, 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 | |
| this program. If not, see <https://www.gnu.org/licenses/>. */ | |
| #include "makeint.h" | |
| #include "commands.h" | |
| #if MK_OS_W32 | |
| #include <windows.h> | |
| #include "w32err.h" | |
| #endif | |
| #include "dep.h" | |
| #include "filedef.h" | |
| #include "job.h" | |
| #include "os.h" | |
| #include "variable.h" | |
| #if MK_OS_VMS | |
| # define FILE_LIST_SEPARATOR (vms_comma_separator ? ',' : ' ') | |
| #else | |
| # define FILE_LIST_SEPARATOR ' ' | |
| #endif | |
| static unsigned long | |
| dep_hash_1 (const void *key) | |
| { | |
| const struct dep *d = key; | |
| return_STRING_HASH_1 (dep_name (d)); | |
| } | |
| static unsigned long | |
| dep_hash_2 (const void *key) | |
| { | |
| const struct dep *d = key; | |
| return_STRING_HASH_2 (dep_name (d)); | |
| } | |
| static int | |
| dep_hash_cmp (const void *x, const void *y) | |
| { | |
| const struct dep *dx = x; | |
| const struct dep *dy = y; | |
| return strcmp (dep_name (dx), dep_name (dy)); | |
| } | |
| /* Set FILE's automatic variables up. | |
| * Use STEM to set $*. | |
| * If STEM is 0, then set FILE->STEM and $* to the target name with any | |
| * suffix in the .SUFFIXES list stripped off. */ | |
| void | |
| set_file_variables (struct file *file, const char *stem) | |
| { | |
| struct dep *d; | |
| const 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)) | |
| { | |
| size_t len; | |
| const char *cp; | |
| char *p; | |
| cp = strchr (file->name, '('); | |
| p = alloca (cp - file->name + 1); | |
| memcpy (p, file->name, cp - file->name); | |
| p[cp - file->name] = '\0'; | |
| at = p; | |
| len = strlen (cp + 1); | |
| p = alloca (len); | |
| memcpy (p, cp + 1, len - 1); | |
| p[len - 1] = '\0'; | |
| percent = p; | |
| } | |
| else | |
| #endif /* NO_ARCHIVES. */ | |
| { | |
| at = file->name; | |
| percent = ""; | |
| } | |
| /* $* is the stem from an implicit or static pattern rule. */ | |
| if (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. */ | |
| const char *name; | |
| size_t len; | |
| #ifndef NO_ARCHIVES | |
| if (ar_name (file->name)) | |
| { | |
| name = strchr (file->name, '(') + 1; | |
| len = strlen (name) - 1; | |
| } | |
| else | |
| #endif | |
| { | |
| name = file->name; | |
| len = strlen (name); | |
| } | |
| for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next) | |
| { | |
| const char *dn = dep_name (d); | |
| size_t slen = strlen (dn); | |
| if (len > slen && memcmp (dn, name + (len - slen), slen) == 0) | |
| { | |
| file->stem = stem = strcache_add_len (name, len - slen); | |
| break; | |
| } | |
| } | |
| if (d == 0) | |
| file->stem = stem = ""; | |
| } | |
| star = stem; | |
| /* $< is the first not order-only dependency. */ | |
| less = ""; | |
| for (d = file->deps; d != 0; d = d->next) | |
| if (!d->ignore_mtime && !d->ignore_automatic_vars && !d->need_2nd_expansion) | |
| { | |
| less = dep_name (d); | |
| break; | |
| } | |
| if (file->cmds != 0 && 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 $|. */ | |
| { | |
| static char *plus_value=0, *bar_value=0, *qmark_value=0; | |
| static size_t plus_max=0, bar_max=0, qmark_max=0; | |
| size_t qmark_len, plus_len, bar_len; | |
| char *cp; | |
| char *caret_value; | |
| char *qp; | |
| char *bp; | |
| size_t len; | |
| struct hash_table dep_hash; | |
| void **slot; | |
| /* Compute first the value for $+, which is supposed to contain | |
| duplicate dependencies as they were listed in the makefile. */ | |
| plus_len = 0; | |
| bar_len = 0; | |
| for (d = file->deps; d != 0; d = d->next) | |
| { | |
| if (!d->need_2nd_expansion && !d->ignore_automatic_vars) | |
| { | |
| if (d->ignore_mtime) | |
| bar_len += strlen (dep_name (d)) + 1; | |
| else | |
| plus_len += strlen (dep_name (d)) + 1; | |
| } | |
| } | |
| if (bar_len == 0) | |
| bar_len++; | |
| if (plus_len == 0) | |
| plus_len++; | |
| if (plus_len > plus_max) | |
| plus_value = xrealloc (plus_value, plus_max = plus_len); | |
| cp = plus_value; | |
| qmark_len = plus_len + 1; /* Will be this or less. */ | |
| for (d = file->deps; d != 0; d = d->next) | |
| if (! d->ignore_mtime && ! d->need_2nd_expansion && ! d->ignore_automatic_vars) | |
| { | |
| const char *c = dep_name (d); | |
| #ifndef NO_ARCHIVES | |
| if (ar_name (c)) | |
| { | |
| c = strchr (c, '(') + 1; | |
| len = strlen (c) - 1; | |
| } | |
| else | |
| #endif | |
| len = strlen (c); | |
| cp = mempcpy (cp, c, len); | |
| *cp++ = FILE_LIST_SEPARATOR; | |
| if (! (d->changed || always_make_flag)) | |
| 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); | |
| /* Compute the values for $^, $?, and $|. */ | |
| cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */ | |
| if (qmark_len > qmark_max) | |
| qmark_value = xrealloc (qmark_value, qmark_max = qmark_len); | |
| qp = qmark_value; | |
| if (bar_len > bar_max) | |
| bar_value = xrealloc (bar_value, bar_max = bar_len); | |
| bp = bar_value; | |
| /* Make sure that no dependencies are repeated in $^, $?, and $|. It | |
| would be natural to combine the next two loops but we can't do it | |
| because of a situation where we have two dep entries, the first | |
| is order-only and the second is normal (see below). */ | |
| hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp); | |
| for (d = file->deps; d != 0; d = d->next) | |
| { | |
| if (d->need_2nd_expansion || d->ignore_automatic_vars) | |
| continue; | |
| slot = hash_find_slot (&dep_hash, d); | |
| if (HASH_VACANT (*slot)) | |
| hash_insert_at (&dep_hash, d, slot); | |
| else | |
| { | |
| /* Check if the two prerequisites have different ignore_mtime. | |
| If so then we need to "upgrade" one that is order-only. */ | |
| struct dep* hd = (struct dep*) *slot; | |
| if (d->ignore_mtime != hd->ignore_mtime) | |
| d->ignore_mtime = hd->ignore_mtime = 0; | |
| } | |
| } | |
| for (d = file->deps; d != 0; d = d->next) | |
| { | |
| const char *c; | |
| if (d->need_2nd_expansion || d->ignore_automatic_vars || hash_find_item (&dep_hash, d) != d) | |
| continue; | |
| c = dep_name (d); | |
| #ifndef NO_ARCHIVES | |
| if (ar_name (c)) | |
| { | |
| c = strchr (c, '(') + 1; | |
| len = strlen (c) - 1; | |
| } | |
| else | |
| #endif | |
| len = strlen (c); | |
| if (d->ignore_mtime) | |
| { | |
| bp = mempcpy (bp, c, len); | |
| *bp++ = FILE_LIST_SEPARATOR; | |
| } | |
| else | |
| { | |
| cp = mempcpy (cp, c, len); | |
| *cp++ = FILE_LIST_SEPARATOR; | |
| if (d->changed || always_make_flag) | |
| { | |
| qp = mempcpy (qp, c, len); | |
| *qp++ = FILE_LIST_SEPARATOR; | |
| } | |
| } | |
| } | |
| hash_free (&dep_hash, 0); | |
| /* 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); | |
| bp[bp > bar_value ? -1 : 0] = '\0'; | |
| DEFINE_VARIABLE ("|", 1, bar_value); | |
| } | |
| #undef DEFINE_VARIABLE | |
| } | |
| /* Chop CMDS up into individual command lines if necessary. | |
| Also set the 'lines_flags' and 'any_recurse' members. */ | |
| void | |
| chop_commands (struct commands *cmds) | |
| { | |
| unsigned short nlines; | |
| unsigned short i; | |
| char **lines; | |
| /* If we don't have any commands, or we already parsed them, never mind. */ | |
| if (!cmds || cmds->command_lines != NULL) | |
| return; | |
| /* Chop CMDS->commands up into lines in CMDS->command_lines. */ | |
| if (one_shell) | |
| { | |
| size_t l = strlen (cmds->commands); | |
| nlines = 1; | |
| lines = xmalloc (nlines * sizeof (char *)); | |
| lines[0] = xstrdup (cmds->commands); | |
| /* Strip the trailing newline. */ | |
| if (l > 0 && lines[0][l-1] == '\n') | |
| lines[0][l-1] = '\0'; | |
| } | |
| else | |
| { | |
| const char *p = cmds->commands; | |
| size_t max = 5; | |
| nlines = 0; | |
| lines = xmalloc (max * sizeof (char *)); | |
| while (*p != '\0') | |
| { | |
| const char *end = p; | |
| find_end:; | |
| end = strchr (end, '\n'); | |
| if (end == NULL) | |
| end = p + strlen (p); | |
| else if (end > p && end[-1] == '\\') | |
| { | |
| int backslash = 1; | |
| if (end > p + 1) | |
| { | |
| const char *b; | |
| for (b = end - 2; b >= p && *b == '\\'; --b) | |
| backslash = !backslash; | |
| } | |
| if (backslash) | |
| { | |
| ++end; | |
| goto find_end; | |
| } | |
| } | |
| if (nlines == USHRT_MAX) | |
| ON (fatal, &cmds->fileinfo, | |
| _("recipe has too many lines (limit %hu)"), nlines); | |
| if (nlines == max) | |
| { | |
| max += 2; | |
| lines = xrealloc (lines, max * sizeof (char *)); | |
| } | |
| lines[nlines++] = xstrndup (p, (size_t) (end - p)); | |
| p = end; | |
| if (*p != '\0') | |
| ++p; | |
| } | |
| } | |
| /* Finally, set the corresponding CMDS->lines_flags elements and the | |
| CMDS->any_recurse flag. */ | |
| cmds->ncommand_lines = nlines; | |
| cmds->command_lines = lines; | |
| cmds->any_recurse = 0; | |
| cmds->lines_flags = xmalloc (nlines); | |
| for (i = 0; i < nlines; ++i) | |
| { | |
| unsigned char flags = 0; | |
| const char *p = lines[i]; | |
| while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+') | |
| switch (*(p++)) | |
| { | |
| case '+': | |
| flags |= COMMANDS_RECURSE; | |
| break; | |
| case '@': | |
| flags |= COMMANDS_SILENT; | |
| break; | |
| case '-': | |
| flags |= COMMANDS_NOERROR; | |
| break; | |
| } | |
| /* If no explicit '+' was given, look for MAKE variable references. */ | |
| if (! ANY_SET (flags, COMMANDS_RECURSE) | |
| && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) | |
| flags |= COMMANDS_RECURSE; | |
| cmds->lines_flags[i] = flags; | |
| cmds->any_recurse |= ANY_SET (flags, COMMANDS_RECURSE) ? 1 : 0; | |
| } | |
| } | |
| /* 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 (struct file *file) | |
| { | |
| const 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 != '@' && *p != '+') | |
| break; | |
| if (*p == '\0') | |
| { | |
| /* If there are no commands, assume everything worked. */ | |
| set_command_state (file, cs_running); | |
| file->update_status = us_success; | |
| notice_finished_file (file); | |
| return; | |
| } | |
| /* First set the automatic variables according to this file. */ | |
| initialize_file_variables (file, 0); | |
| set_file_variables (file, file->stem); | |
| /* Some systems don't support overwriting a loaded object so if this one | |
| unload it before remaking. Keep its name in .LOADED: it will be rebuilt | |
| and loaded again. If rebuilding or loading again fail, then we'll exit | |
| anyway and it won't matter. */ | |
| if (file->loaded && unload_file (file->name) == 0) | |
| { | |
| file->loaded = 0; | |
| file->unloaded = 1; | |
| } | |
| /* Start the commands running. */ | |
| new_job (file); | |
| } | |
| /* This is set while we are inside fatal_error_signal, | |
| so things can avoid nonreentrant operations. */ | |
| volatile sig_atomic_t handling_fatal_signal = 0; | |
| /* Handle fatal signals. */ | |
| void | |
| fatal_error_signal (int sig) | |
| { | |
| #if MK_OS_DOS | |
| 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 (EXIT_FAILURE); | |
| #else /* not MK_OS_DOS */ | |
| #if MK_OS_W32 | |
| extern HANDLE main_thread; | |
| /* Windows creates a separate thread for handling Ctrl+C, so we need | |
| to suspend the main thread, or else we will have race conditions | |
| when both threads call reap_children. */ | |
| if (main_thread) | |
| { | |
| DWORD susp_count = SuspendThread (main_thread); | |
| if (susp_count != 0) | |
| fprintf (stderr, "SuspendThread: suspend count = %lu\n", susp_count); | |
| else if (susp_count == (DWORD)-1) | |
| { | |
| DWORD ierr = GetLastError (); | |
| fprintf (stderr, "SuspendThread: error %lu: %s\n", | |
| ierr, map_windows32_error_to_string (ierr)); | |
| } | |
| } | |
| #endif | |
| 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); | |
| temp_stdin_unlink (); | |
| osync_clear (); | |
| jobserver_clear (); | |
| /* A termination signal won't be sent to the entire | |
| process group, but it means we want to kill the children. */ | |
| if (sig == SIGTERM) | |
| { | |
| struct child *c; | |
| for (c = children; c != 0; c = c->next) | |
| if (!c->remote && c->pid > 0) | |
| (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 | |
| ) | |
| { | |
| 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 && c->pid > 0) | |
| (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 (MAKE_TROUBLE); | |
| #endif | |
| #if MK_OS_W32 | |
| if (main_thread) | |
| CloseHandle (main_thread); | |
| /* Cannot call W32_kill with a pid (it needs a handle). The exit | |
| status of 130 emulates what happens in Bash. */ | |
| exit (130); | |
| #else | |
| /* 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 (make_pid (), sig) < 0) | |
| pfatal_with_name ("kill"); | |
| #endif /* not MK_OS_W32 */ | |
| #endif /* not MK_OS_DOS */ | |
| } | |
| /* 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 (struct file *file, const char *on_behalf_of) | |
| { | |
| struct stat st; | |
| int e; | |
| if (file->precious || file->phony) | |
| return; | |
| #ifndef NO_ARCHIVES | |
| if (ar_name (file->name)) | |
| { | |
| time_t file_date = (file->last_mtime == NONEXISTENT_MTIME | |
| ? (time_t) -1 | |
| : (time_t) FILE_TIMESTAMP_S (file->last_mtime)); | |
| if (ar_member_date (file->name) != file_date) | |
| { | |
| if (on_behalf_of) | |
| OSS (error, NILF, | |
| _("*** [%s] archive member '%s' may be bogus; not deleted"), | |
| on_behalf_of, file->name); | |
| else | |
| OS (error, NILF, | |
| _("*** archive member '%s' may be bogus; not deleted"), | |
| file->name); | |
| } | |
| return; | |
| } | |
| #endif | |
| EINTRLOOP (e, stat (file->name, &st)); | |
| if (e == 0 | |
| && S_ISREG (st.st_mode) | |
| && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime) | |
| { | |
| if (on_behalf_of) | |
| OSS (error, NILF, | |
| _("*** [%s] deleting file '%s'"), on_behalf_of, file->name); | |
| else | |
| OS (error, NILF, _("*** 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 (struct child *child) | |
| { | |
| struct dep *d; | |
| if (child->deleted || child->pid < 0) | |
| return; | |
| /* Delete the target file if it changed. */ | |
| delete_target (child->file, NULL); | |
| /* 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 (const struct commands *cmds) | |
| { | |
| const char *s; | |
| fputs (_("# recipe to execute"), stdout); | |
| if (cmds->fileinfo.filenm == 0) | |
| puts (_(" (built-in):")); | |
| else | |
| printf (_(" (from '%s', line %lu):\n"), | |
| cmds->fileinfo.filenm, cmds->fileinfo.lineno); | |
| s = cmds->commands; | |
| while (*s != '\0') | |
| { | |
| const char *end; | |
| int bs; | |
| /* Print one full logical recipe line: find a non-escaped newline. */ | |
| for (end = s, bs = 0; *end != '\0'; ++end) | |
| { | |
| if (*end == '\n' && !bs) | |
| break; | |
| bs = *end == '\\' ? !bs : 0; | |
| } | |
| printf ("%c%.*s\n", cmd_prefix, (int) (end - s), s); | |
| s = end + (end[0] == '\n'); | |
| } | |
| } |