Dear sir, There is currently an incompatibility between GNU make and Solaris make that causes me much grief with many of my makefiles. In Solaris make a pattern substitution in a variable expansion can accept multiple target wild cards. GNU make only accepts a single wild card. Here is an example makefile: A=rafile.o rbfile.o rcfile.o B=$(A:r%.o=pre%post.a pre%post.b) do: echo $(B) Which will result in the following output from GNU make 3.77: preafilepost.a pre%post.b prebfilepost.a pre%post.b precfilepost.a pre%post.b I would like to get the following output as is generated by Solaris make: preafilepost.a preafilepost.b prebfilepost.a prebfilepost.b precfilepost.a precfilepost.b I have included a proposed patch to make 3.77 that implements my proposal. Please consider including this are a similar fix into a future version of make. Thank you. -Richard Deken
diff -Naur make-3.77.orig/expand.c make-3.77/expand.c --- make-3.77.orig/expand.c Fri May 15 08:36:51 1998 +++ make-3.77/expand.c Sat Apr 1 22:08:12 2000 @@ -344,8 +344,8 @@ replace[replace_end - replace_beg] = '\0'; } - o = patsubst_expand (o, value, pattern, replace, - percent, (char *) 0); + o = rpatsubst_expand (o, value, pattern, replace, + percent); } else o = subst_expand (o, value, diff -Naur make-3.77.orig/function.c make-3.77/function.c --- make-3.77.orig/function.c Thu Jul 9 23:05:05 1998 +++ make-3.77/function.c Sat Apr 1 22:11:15 2000 @@ -213,6 +213,117 @@ return o; } +/* Store into VARIABLE_BUFFER at O the result of scanning TEXT + and replacing strings matching PATTERN with REPLACE (replace may contain + multiple matches. */ + +char * +rpatsubst_expand (o, text, pattern, replace, pattern_percent) + char *o; + char *text; + register char *pattern, *replace; + register char *pattern_percent; +{ + unsigned int pattern_prepercent_len, pattern_postpercent_len; + unsigned int replace_len; + char *replace_percent; + char *t, *l; + unsigned int len; + int doneany = 0; + + /* Find pattern percent */ + if (pattern_percent == 0) + pattern_percent = find_percent (pattern); + if (pattern_percent == 0) + /* With no % in the pattern, this is just a simple substitution. */ + return subst_expand (o, text, pattern, replace, strlen (pattern), + strlen (replace), 1, 0); + + /* Record the length of PATTERN before and after the % + so we don't have to compute it more than once. */ + pattern_prepercent_len = pattern_percent - pattern; + pattern_postpercent_len = strlen (pattern_percent + 1); + + while ((t = find_next_token (&text, &len)) != 0) + { + int fail = 0; + + /* Is it big enough to match? */ + if (len < pattern_prepercent_len + pattern_postpercent_len) + fail = 1; + + /* Does the prefix match? */ + if (!fail && pattern_prepercent_len > 0 + && (*t != *pattern + || t[pattern_prepercent_len - 1] != pattern_percent[-1] + || strncmp (t + 1, pattern + 1, pattern_prepercent_len - 1))) + fail = 1; + + /* Does the suffix match? */ + if (!fail && pattern_postpercent_len > 0 + && (t[len - 1] != pattern_percent[pattern_postpercent_len] + || t[len - pattern_postpercent_len] != pattern_percent[1] + || strncmp (&t[len - pattern_postpercent_len], + &pattern_percent[1], pattern_postpercent_len - 1))) + fail = 1; + + if (fail) + { + /* It didn't match. Output the string. */ + o = variable_buffer_output (o, t, len); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + else + { + /* It matched. Output the replacement. */ + fail = 1; + for (l = replace; replace_percent = find_percent (l); + l = replace_percent + 1) + { + /* Output the part of the replacement before the %. */ + replace_len = replace_percent - l; + if (replace_len) + { + o = variable_buffer_output (o, l, replace_len); + fail = 0; + } + + /* Output the part of the matched string that + matched the % in the pattern. */ + replace_len = len - (pattern_prepercent_len + + pattern_postpercent_len); + if (replace_len) + { + o = variable_buffer_output (o, t + pattern_prepercent_len, + replace_len); + fail = 0; + } + } + + /* Output the part of the replacement after the %. */ + replace_len = strlen (l); + if (replace_len) + { + o = variable_buffer_output (o, l, replace_len); + fail = 0; + } + + /* Add space if replacement was not "" */ + if (!fail) + { + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + } + if (doneany) + /* Kill the last space. */ + --o; + + return o; +} + /* Handle variable-expansion-time functions such as $(dir foo/bar) ==> foo/ */ /* These enumeration constants distinguish the @@ -1005,7 +1116,7 @@ p3 = expand_argument (p2 + 1, p); p2 = expand_argument (p + 1, end); - o = patsubst_expand (o, p2, text, p3, (char *) 0, (char *) 0); + o = rpatsubst_expand (o, p2, text, p3, (char*) 0); free (text); free (p3); diff -Naur make-3.77.orig/variable.h make-3.77/variable.h --- make-3.77.orig/variable.h Fri May 15 13:07:41 1998 +++ make-3.77/variable.h Sat Apr 1 22:13:09 2000 @@ -89,6 +89,8 @@ unsigned int slen, unsigned int rlen, int by_word, int suffix_only)); extern char *patsubst_expand PARAMS ((char *o, char *text, char *pattern, char *replace, char *pattern_percent, char *replace_percent)); +extern char *rpatsubst_expand PARAMS ((char *o, char *text, char *pattern, char +*replace, + char *pattern_percent)); /* expand.c */ extern char *recursively_expand PARAMS ((struct variable *v));