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