On 2023-12-10, Lucas de Sena wrote: > 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 >
Yearly bump.