I could identify the following bugs in make(1), concerning the
"%" character on a variable substitution:

- If there's no "%" in the left or right hand side string of a
  variable substitution, make(1) prepends one into them.  Thus
  ${SRCS:.c=.o} is equivalent to ${SRCS:%.c=%.o}.  That's fine
  when both left- and right-hand side have no "%" in them; but
  works unexpectedly when one has a "%" and the other has not.

- The "%" character cannot be escaped, neither by backslashing
  or by doubling it.

This is what make(1) says about the '%' (the "pattern matching
character") in this kind of expressions (called "AT&T System V
UNIX variable substitutions):

| :old_string=new_string
|    This is the AT&T System V UNIX style variable substitution.
|    It must be the last modifier specified.  If old_string or
|    new_string do not contain the pattern matching character '%'
|    then it is assumed that they are anchored at the end of each
|    word, so only suffixes or entire words may be replaced.
|    Otherwise '%' is the substring of old_string to be replaced
|    in new_string.  The right-hand side (new_string) may contain
|    variable values, which will be expanded.  To put an actual
|    single dollar, just double it.

For example, consider the following makefile:

| $ cat makefile
| VAR = foohellobar
| FOO = foo%foo
| all:
|       @echo "${VAR:foo%bar=% world}"  # 0. % on both sides
|       @echo "${VAR:foo%bar= world}"   # 1. % at left only
|       @echo "${VAR:hellobar=%world}"  # 2. % at right only
|       @echo "${VAR:foo%bar=\% world}" # 3. right % escape
|       @echo "${FOO:\%foo=bar}"        # 4. left % escape

Running GNU gmake on it prints:

| $ gmake
| hello world
|  world
| foo%world
| % world
| foobar

0. "%" in old_string matches "hello", and "%" in new_string is
   replaced with it.

1. "%" in old_string matches "hello", no replacement occurs in
   new_string (there is no "%" in it).

2. There is no "%" in old_string to match anything, the "%" in
   new_string is ignored.

3. "%" in old_string matches "hello", and "%" in new_string is
   escaped and thus not replaced (behaves as 2).

4. "%" in old_string is escaped, the suffix "%foo" is replaced
   with new_string.

Now run OpenBSD make on the same makefile:

| $ make
| hello world
| hello world
| fooworld
| \hello world
| foo%foo

0. "%" in both sides.  No bug here.

1. It works as if there were an implicit "%" inserted into the
   begining of new_string.

2. It works as if there were an implicit "%" inserted into the
   begining of old_string.

3. It works as if "%" were not escaped, and the backslash were
   a regular character before it.

4. It works as if "%" were not escaped, and the backslash were
   a regular character before it.

                                              -- Lucas de Sena

Reply via email to