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.

Reply via email to