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