(Make version 3.79.) Consider this Makefile: %.1 %.2: %.src cp $< $*.1 cp $< $*.2 Create a file sub/foo.src and 'make -Rp sub/foo.1'. Here's an excerpt from the output: # Not a target: sub/foo.1: sub/foo.src # Command-line target. # Implicit rule search has been done. # Implicit/static pattern stem: `sub/foo' # Also makes: foo.2 # Last modified 2000-06-15 17:49:23 # File has been updated. # Successfully updated. # automatic # ^ := sub/foo.src # automatic # @ := sub/foo.1 # automatic # + := sub/foo.src # automatic # ? := sub/foo.src # automatic # * := sub/foo # automatic # % := # automatic # < := sub/foo.src # 7 variables in 23 hash buckets. # average of 0.3 variables per bucket, max 2 in one bucket. # commands to execute (from `Makefile', line 2): cp $< $*.1 cp $< $*.2 # Not a target: foo.2: # Implicit rule search has not been done. # File does not exist. # File has been updated. # Successfully updated. Note that make is incorrectly dropping the subdirectory path from the extra targets. Here's a patch to fix it: diff -rc /x/sethml/src/make-3.79/implicit.c ./implicit.c *** /x/sethml/src/make-3.79/implicit.c Fri Jan 21 21:43:03 2000 --- ./implicit.c Thu Jun 15 17:28:50 2000 *************** *** 117,122 **** --- 117,123 ---- /* The start and length of the stem of FILENAME for the current rule. */ register char *stem = 0; register unsigned int stemlen = 0; + unsigned int fstemlen; /* Buffer in which we store all the rules that are possibly applicable. */ struct rule **tryrules *************** *** 582,599 **** } if (!checked_lastslash[foundrule]) ! /* Always allocate new storage, since STEM might be ! on the stack for an intermediate file. */ ! file->stem = savestring (stem, stemlen); else { /* We want to prepend the directory from the original FILENAME onto the stem. */ ! file->stem = (char *) xmalloc (((lastslash + 1) - filename) ! + stemlen + 1); bcopy (filename, file->stem, (lastslash + 1) - filename); bcopy (stem, file->stem + ((lastslash + 1) - filename), stemlen); ! file->stem[((lastslash + 1) - filename) + stemlen] = '\0'; } file->cmds = rule->cmds; --- 583,603 ---- } if (!checked_lastslash[foundrule]) ! { ! /* Always allocate new storage, since STEM might be ! on the stack for an intermediate file. */ ! file->stem = savestring (stem, stemlen); ! fstemlen = stemlen; ! } else { /* We want to prepend the directory from the original FILENAME onto the stem. */ ! fstemlen = ((lastslash + 1) - filename) + stemlen; ! file->stem = (char *) xmalloc (fstemlen + 1); bcopy (filename, file->stem, (lastslash + 1) - filename); bcopy (stem, file->stem + ((lastslash + 1) - filename), stemlen); ! file->stem[fstemlen] = '\0'; } file->cmds = rule->cmds; *************** *** 606,617 **** if (i != matches[foundrule]) { struct dep *new = (struct dep *) xmalloc (sizeof (struct dep)); ! new->name = p = (char *) xmalloc (rule->lens[i] + stemlen + 1); bcopy (rule->targets[i], p, rule->suffixes[i] - rule->targets[i] - 1); p += rule->suffixes[i] - rule->targets[i] - 1; ! bcopy (stem, p, stemlen); ! p += stemlen; bcopy (rule->suffixes[i], p, rule->lens[i] - (rule->suffixes[i] - rule->targets[i]) + 1); new->file = enter_file (new->name); --- 610,621 ---- if (i != matches[foundrule]) { struct dep *new = (struct dep *) xmalloc (sizeof (struct dep)); ! new->name = p = (char *) xmalloc (rule->lens[i] + fstemlen + 1); bcopy (rule->targets[i], p, rule->suffixes[i] - rule->targets[i] - 1); p += rule->suffixes[i] - rule->targets[i] - 1; ! bcopy (file->stem, p, fstemlen); ! p += fstemlen; bcopy (rule->suffixes[i], p, rule->lens[i] - (rule->suffixes[i] - rule->targets[i]) + 1); new->file = enter_file (new->name);