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)); }
static int update_file_1 (struct file *file, unsigned int depth) { FILE_TIMESTAMP this_mtime; int noexist, must_make, deps_changed; int dep_status = 0; struct file *ofile; struct dep *d, *ad; struct dep amake; int running = 0; DBF (DB_VERBOSE, _("Considering target file '%s'.\n")); if (file->updated) { if (file->update_status > 0) { DBF (DB_VERBOSE, _("Recently tried and failed to update file '%s'.\n")); /* If the file we tried to make is marked no_diag then no message was printed about it when it failed during the makefile rebuild. If we're trying to build it again in the normal rebuild, print a message now. */ if (file->no_diag && !file->dontcare) complain (file); return file->update_status; } DBF (DB_VERBOSE, _("File '%s' was considered already.\n")); return 0; } switch (file->command_state) { case cs_not_started: case cs_deps_running: break; case cs_running: DBF (DB_VERBOSE, _("Still updating file '%s'.\n")); return 0; case cs_finished: DBF (DB_VERBOSE, _("Finished updating file '%s'.\n")); return file->update_status; default: abort (); } /* Determine whether the diagnostics will be issued should this update fail. */ file->no_diag = file->dontcare; ++depth; /* Notice recursive update of the same file. */ start_updating (file); /* We might change file if we find a different one via vpath; remember this one to turn off updating. */ ofile = file; /* Looking at the file's modtime beforehand allows the possibility that its name may be changed by a VPATH search, and thus it may not need an implicit rule. If this were not done, the file might get implicit commands that apply to its initial name, only to have that name replaced with another found by VPATH search. */ this_mtime = file_mtime (file); check_renamed (file); noexist = this_mtime == NONEXISTENT_MTIME; if (noexist) DBF (DB_BASIC, _("File '%s' does not exist.\n")); else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX && file->low_resolution_time) { /* Avoid spurious rebuilds due to low resolution time stamps. */ int ns = FILE_TIMESTAMP_NS (this_mtime); if (ns != 0) error (NILF, _("*** Warning: .LOW_RESOLUTION_TIME file '%s' has a high resolution time stamp"), file->name); this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns; } must_make = noexist; /* If file was specified as a target with no commands, come up with some default commands. */ if (!file->phony && file->cmds == 0 && !file->tried_implicit) { if (try_implicit_rule (file, depth)) DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n")); else DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n")); file->tried_implicit = 1; } if (file->cmds == 0 && !file->is_target && default_file != 0 && default_file->cmds != 0) { DBF (DB_IMPLICIT, _("Using default recipe for '%s'.\n")); file->cmds = default_file->cmds; } /* Update all non-intermediate files we depend on, if necessary, and see whether any of them is more recent than this file. We need to walk our deps, AND the deps of any also_make targets to ensure everything happens in the correct order. */ amake.file = file; amake.next = file->also_make; ad = &amake; while (ad) { struct dep *lastd = 0; /* Find the deps we're scanning */ d = ad->file->deps; ad = ad->next; while (d) { FILE_TIMESTAMP mtime; int maybe_make; int dontcare = 0; check_renamed (d->file); mtime = file_mtime (d->file); check_renamed (d->file); if (is_updating (d->file)) { error (NILF, _("Circular %s <- %s dependency dropped."), file->name, d->file->name); /* We cannot free D here because our the caller will still have a reference to it when we were called recursively via check_dep below. */ if (lastd == 0) file->deps = d->next; else lastd->next = d->next; d = d->next; continue; } d->file->parent = file; maybe_make = must_make; /* Inherit dontcare flag from our parent. */ if (rebuilding_makefiles) { dontcare = d->file->dontcare; d->file->dontcare = file->dontcare; } dep_status |= check_dep (d->file, depth, this_mtime, &maybe_make); /* Restore original dontcare flag. */ if (rebuilding_makefiles) d->file->dontcare = dontcare; if (! d->ignore_mtime) must_make = maybe_make; check_renamed (d->file); { register struct file *f = d->file; if (f->double_colon) f = f->double_colon; do { running |= (f->command_state == cs_running || f->command_state == cs_deps_running); f = f->prev; } while (f != 0); } if (dep_status != 0 && !keep_going_flag) break; if (!running) /* The prereq is considered changed if the timestamp has changed while it was built, OR it doesn't exist. */ d->changed = ((file_mtime (d->file) != mtime) || (mtime == NONEXISTENT_MTIME)); lastd = d; d = d->next; } } /* Now we know whether this target needs updating. If it does, update all the intermediate files we depend on. */ if (must_make || always_make_flag) { for (d = file->deps; d != 0; d = d->next) if (d->file->intermediate) { int dontcare = 0; FILE_TIMESTAMP mtime = file_mtime (d->file); check_renamed (d->file); d->file->parent = file; /* Inherit dontcare flag from our parent. */ if (rebuilding_makefiles) { dontcare = d->file->dontcare; d->file->dontcare = file->dontcare; } dep_status |= update_file (d->file, depth); /* Restore original dontcare flag. */ if (rebuilding_makefiles) d->file->dontcare = dontcare; check_renamed (d->file); { register struct file *f = d->file; if (f->double_colon) f = f->double_colon; do { running |= (f->command_state == cs_running || f->command_state == cs_deps_running); f = f->prev; } while (f != 0); } if (dep_status != 0 && !keep_going_flag) break; if (!running) d->changed = ((file->phony && file->cmds != 0) || file_mtime (d->file) != mtime); } } finish_updating (file); finish_updating (ofile); DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n")); if (running) { set_command_state (file, cs_deps_running); --depth; DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n")); return 0; } /* If any dependency failed, give up now. */ if (dep_status != 0) { file->update_status = dep_status; notice_finished_file (file); --depth; DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n")); if (depth == 0 && keep_going_flag && !just_print_flag && !question_flag) error (NILF, _("Target '%s' not remade because of errors."), file->name); return dep_status; } if (file->command_state == cs_deps_running) /* The commands for some deps were running on the last iteration, but they have finished now. Reset the command_state to not_started to simplify later bookkeeping. It is important that we do this only when the prior state was cs_deps_running, because that prior state was definitely propagated to FILE's also_make's by set_command_state (called above), but in another state an also_make may have independently changed to finished state, and we would confuse that file's bookkeeping (updated, but not_started is bogus state). */ set_command_state (file, cs_not_started); /* Now record which prerequisites are more recent than this file, so we can define $?. */ deps_changed = 0; for (d = file->deps; d != 0; d = d->next) { FILE_TIMESTAMP d_mtime = file_mtime (d->file); check_renamed (d->file); if (! d->ignore_mtime) { #if 1 /* %%% In version 4, remove this code completely to implement not remaking deps if their deps are newer than their parents. */ if (d_mtime == NONEXISTENT_MTIME && !d->file->intermediate) /* We must remake if this dep does not exist and is not intermediate. */ must_make = 1; #endif /* Set DEPS_CHANGED if this dep actually changed. */ deps_changed |= d->changed; } /* Set D->changed if either this dep actually changed, or its dependent, FILE, is older or does not exist. */ d->changed |= noexist || d_mtime > this_mtime; if (!noexist && ISDB (DB_BASIC|DB_VERBOSE)) { const char *fmt = 0; if (d->ignore_mtime) { if (ISDB (DB_VERBOSE)) fmt = _("Prerequisite '%s' is order-only for target '%s'.\n"); } else if (d_mtime == NONEXISTENT_MTIME) { if (ISDB (DB_BASIC)) fmt = _("Prerequisite '%s' of target '%s' does not exist.\n"); } else if (d->changed) { if (ISDB (DB_BASIC)) fmt = _("Prerequisite '%s' is newer than target '%s'.\n"); } else if (ISDB (DB_VERBOSE)) fmt = _("Prerequisite '%s' is older than target '%s'.\n"); if (fmt) { print_spaces (depth); printf (fmt, dep_name (d), file->name); fflush (stdout); } } } /* Here depth returns to the value it had when we were called. */ depth--; if (file->double_colon && file->deps == 0) { must_make = 1; DBF (DB_BASIC, _("Target '%s' is double-colon and has no prerequisites.\n")); } else if (!noexist && file->is_target && !deps_changed && file->cmds == 0 && !always_make_flag) { must_make = 0; DBF (DB_VERBOSE, _("No recipe for '%s' and no prerequisites actually changed.\n")); } else if (!must_make && file->cmds != 0 && always_make_flag) { must_make = 1; DBF (DB_VERBOSE, _("Making '%s' due to always-make flag.\n")); } if (!must_make) { if (ISDB (DB_VERBOSE)) { print_spaces (depth); printf (_("No need to remake target '%s'"), file->name); if (!streq (file->name, file->hname)) printf (_("; using VPATH name '%s'"), file->hname); puts ("."); fflush (stdout); } notice_finished_file (file); /* Since we don't need to remake the file, convert it to use the VPATH filename if we found one. hfile will be either the local name if no VPATH or the VPATH name if one was found. */ while (file) { file->name = file->hname; file = file->prev; } return 0; } DBF (DB_BASIC, _("Must remake target '%s'.\n")); /* It needs to be remade. If it's VPATH and not reset via GPATH, toss the VPATH. */ if (!streq(file->name, file->hname)) { DB (DB_BASIC, (_(" Ignoring VPATH name '%s'.\n"), file->hname)); file->ignore_vpath = 1; } /* Now, take appropriate actions to remake the file. */ remake_file (file); if (file->command_state != cs_finished) { DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n")); return 0; } switch (file->update_status) { case 2: DBF (DB_BASIC, _("Failed to remake target file '%s'.\n")); break; case 0: DBF (DB_BASIC, _("Successfully remade target file '%s'.\n")); break; case 1: DBF (DB_BASIC, _("Target file '%s' needs remade under -q.\n")); break; default: assert (file->update_status >= 0 && file->update_status <= 2); break; } file->updated = 1; return file->update_status; }
void set_file_variables (struct file *file) { 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)) { unsigned int 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 (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. */ const char *name; unsigned int 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) { unsigned int slen = strlen (dep_name (d)); if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) { file->stem = strcache_add_len (name, len - slen); break; } } if (d == 0) file->stem = ""; } star = file->stem; /* $< is the first not order-only dependency. */ less = ""; for (d = file->deps; d != 0; d = d->next) if (!d->ignore_mtime) { if (!d->need_2nd_expansion) less = dep_name (d); break; } 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 $|. */ { static char *plus_value=0, *bar_value=0, *qmark_value=0; static unsigned int plus_max=0, bar_max=0, qmark_max=0; unsigned int qmark_len, plus_len, bar_len; char *cp; char *caret_value; char *qp; char *bp; unsigned int 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) { 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) { 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); memcpy (cp, c, len); cp += 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) 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 || 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) { memcpy (bp, c, len); bp += len; *bp++ = FILE_LIST_SEPARATOR; } else { memcpy (cp, c, len); cp += len; *cp++ = FILE_LIST_SEPARATOR; if (d->changed || always_make_flag) { memcpy (qp, c, len); qp += 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 }
static unsigned long dep_hash_2 (const void *key) { const struct dep *d = key; return_STRING_HASH_2 (dep_name (d)); }
void count_implicit_rule_limits (void) { char *name; int namelen; struct rule *rule, *lastrule; num_pattern_rules = max_pattern_targets = max_pattern_deps = 0; max_pattern_dep_length = 0; name = 0; namelen = 0; rule = pattern_rules; lastrule = 0; while (rule != 0) { unsigned int ndeps = 0; struct dep *dep; struct rule *next = rule->next; ++num_pattern_rules; if (rule->num > max_pattern_targets) max_pattern_targets = rule->num; for (dep = rule->deps; dep != 0; dep = dep->next) { const char *dname = dep_name (dep); unsigned int len = strlen (dname); #ifdef VMS const char *p = strrchr (dname, ']'); const char *p2; if (p == 0) p = strrchr (dname, ':'); p2 = p != 0 ? strchr (dname, '%') : 0; #else const char *p = strrchr (dname, '/'); const char *p2 = p != 0 ? strchr (dname, '%') : 0; #endif ndeps++; if (len > max_pattern_dep_length) max_pattern_dep_length = len; if (p != 0 && p2 > p) { /* There is a slash before the % in the dep name. Extract the directory name. */ if (p == dname) ++p; if (p - dname > namelen) { namelen = p - dname; name = xrealloc (name, namelen + 1); } memcpy (name, dname, p - dname); name[p - dname] = '\0'; /* In the deps of an implicit rule the 'changed' flag actually indicates that the dependency is in a nonexistent subdirectory. */ dep->changed = !dir_file_exists_p (name, ""); } else /* This dependency does not reside in a subdirectory. */ dep->changed = 0; } if (ndeps > max_pattern_deps) max_pattern_deps = ndeps; lastrule = rule; rule = next; } if (name != 0) free (name); }
void convert_to_pattern (void) { struct dep *d, *d2; char *rulename; /* We will compute every potential suffix rule (.x.y) from the list of suffixes in the .SUFFIXES target's dependencies and see if it exists. First find the longest of the suffixes. */ maxsuffix = 0; for (d = suffix_file->deps; d != 0; d = d->next) { unsigned int l = strlen (dep_name (d)); if (l > maxsuffix) maxsuffix = l; } /* Space to construct the suffix rule target name. */ rulename = alloca ((maxsuffix * 2) + 1); for (d = suffix_file->deps; d != 0; d = d->next) { unsigned int slen; /* Make a rule that is just the suffix, with no deps or commands. This rule exists solely to disqualify match-anything rules. */ convert_suffix_rule (dep_name (d), 0, 0); if (d->file->cmds != 0) /* Record a pattern for this suffix's null-suffix rule. */ convert_suffix_rule ("", dep_name (d), d->file->cmds); /* Add every other suffix to this one and see if it exists as a two-suffix rule. */ slen = strlen (dep_name (d)); memcpy (rulename, dep_name (d), slen); for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { struct file *f; unsigned int s2len; s2len = strlen (dep_name (d2)); /* Can't build something from itself. */ if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; memcpy (rulename + slen, dep_name (d2), s2len + 1); f = lookup_file (rulename); if (f == 0 || f->cmds == 0) continue; if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a') /* A suffix rule '.X.a:' generates the pattern rule '(%.o): %.X'. It also generates a normal '%.a: %.X' rule below. */ convert_suffix_rule (NULL, /* Indicates '(%.o)'. */ dep_name (d), f->cmds); /* The suffix rule '.X.Y:' is converted to the pattern rule '%.Y: %.X'. */ convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds); } } }
void convert_to_pattern (void) { register struct dep *d, *d2; register struct file *f; register char *rulename; register unsigned int slen, s2len; /* Compute maximum length of all the suffixes. */ maxsuffix = 0; for (d = suffix_file->deps; d != 0; d = d->next) { register unsigned int namelen = strlen (dep_name (d)); if (namelen > maxsuffix) maxsuffix = namelen; } rulename = (char *) alloca ((maxsuffix * 2) + 1); for (d = suffix_file->deps; d != 0; d = d->next) { /* Make a rule that is just the suffix, with no deps or commands. This rule exists solely to disqualify match-anything rules. */ convert_suffix_rule (dep_name (d), (char *) 0, (struct commands *) 0); f = d->file; if (f->cmds != 0) /* Record a pattern for this suffix's null-suffix rule. */ convert_suffix_rule ("", dep_name (d), f->cmds); /* Record a pattern for each of this suffix's two-suffix rules. */ slen = strlen (dep_name (d)); bcopy (dep_name (d), rulename, slen); for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { s2len = strlen (dep_name (d2)); if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; bcopy (dep_name (d2), rulename + slen, s2len + 1); f = lookup_file (rulename); if (f == 0 || f->cmds == 0) continue; if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a') /* A suffix rule `.X.a:' generates the pattern rule `(%.o): %.X'. It also generates a normal `%.a: %.X' rule below. */ convert_suffix_rule ((char *) 0, /* Indicates `(%.o)'. */ dep_name (d), f->cmds); /* The suffix rule `.X.Y:' is converted to the pattern rule `%.Y: %.X'. */ convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds); } } }
void convert_to_pattern () { register struct dep *d, *d2, *newd; register struct file *f; register char *rulename; register unsigned int slen, s2len; register char *name, **names; /* Compute maximum length of all the suffixes. */ maxsuffix = 0; for (d = suffix_file->deps; d != 0; d = d->next) { register unsigned int namelen = strlen (dep_name (d)); if (namelen > maxsuffix) maxsuffix = namelen; } rulename = (char *) alloca ((maxsuffix * 2) + 1); for (d = suffix_file->deps; d != 0; d = d->next) { /* Make a rule that is just the suffix, with no deps or commands. This rule exists solely to disqualify match-anything rules. */ slen = strlen (dep_name (d)); name = (char *) xmalloc (1 + slen + 1); name[0] = '%'; bcopy (dep_name (d), name + 1, slen + 1); names = (char **) xmalloc (2 * sizeof (char *)); names[0] = name; names[1] = 0; create_pattern_rule (names, (char **) 0, 0, (struct dep *) 0, (struct commands *) 0, 0); f = d->file; if (f->cmds != 0) { /* Record a pattern for this suffix's null-suffix rule. */ newd = (struct dep *) xmalloc (sizeof (struct dep)); /* Construct this again rather than using the contents of NAME (above), since that may have been freed by create_pattern_rule. */ newd->name = (char *) xmalloc (1 + slen + 1); newd->name[0] = '%'; bcopy (dep_name (d), newd->name + 1, slen + 1); newd->next = 0; names = (char **) xmalloc (2 * sizeof (char *)); names[0] = savestring ("%", 1); names[1] = 0; create_pattern_rule (names, (char **) 0, 0, newd, f->cmds, 0); } /* Record a pattern for each of this suffix's two-suffix rules. */ bcopy (dep_name (d), rulename, slen); for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { s2len = strlen (dep_name (d2)); if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; bcopy (dep_name (d2), rulename + slen, s2len + 1); f = lookup_file (rulename); if (f == 0 || f->cmds == 0) continue; if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a') /* The suffix rule `.X.a:' is converted to the pattern rule `(%.o): %.X'. */ name = savestring ("(%.o)", 5); else { /* The suffix rule `.X.Y:' is converted to the pattern rule `%.Y: %.X'. */ name = (char *) xmalloc (1 + s2len + 1); name[0] = '%'; bcopy (dep_name (d2), name + 1, s2len + 1); } names = (char **) xmalloc (2 * sizeof (char *)); names[0] = name; names[1] = 0; newd = (struct dep *) xmalloc (sizeof (struct dep)); newd->next = 0; /* Construct this again (see comment above). */ newd->name = (char *) xmalloc (1 + slen + 1); newd->name[0] = '%'; bcopy (dep_name (d), newd->name + 1, slen + 1); create_pattern_rule (names, (char **) 0, 0, newd, f->cmds, 0); } } }