tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: make(1): is this a bug or PEBKAC?



Am 22.02.2023 um 03:01 schrieb Mouse:
    121	$(x:C;^.*\.([0-9].*)$$;$(INSTMANDIR)/cat\1;):

The same code works with 5.2's make (which, of course, says only
moderately little for its correctness...).

So, I'm wondering, is this a bug in 9.1's make, or am I doing something
wrong here?

TL;DR: There are several cases in which make silently ignores parse
errors, such as '$$' in variable modifiers. In other cases, it has
become stricter over time, or the accepted syntax just changed.

The crucial part in your example is the '$$'. In normal strings, '$$' is
used to escape a '$'. But in variable modifiers such as ':C', '\$' is
used instead to escape a '$'. Well, in most variable modifiers, as some
of them have their own parsing rules.

In netbsd-5.2:usr.bin/make/var.c, the '$$' is parsed as the variable
named '$', so the parser continues by looking at the ';', which is a
delimiter for the ':C' modifier, just as you expected. In
netbsd-9:usr.bin/make/var.c, the variable name '$$' is silently no
longer accepted, see the comment "Error out some really stupid names" in
var.c, but that's not even relevant in this case.

In netbsd-9:usr.bin/make/var.c, the parser looks at '$(x:...(...)$$)',
trying to figure out which parentheses match, see the comment "Attempt
to avoid ';' inside substitution patterns" in parse.c. In this case, the
parser fails. It counts the '$(' as starting a subexpression, then
ignores the following '(', and when it sees the first ')', it considers
the expression completed, leaving the '$$)' for a syntax error.

This ad-hoc parentheses-counting code is still present in the latest
version of make.

To avoid all these edge cases, you should rewrite your makefile:

* In the ':C' modifier, replace '$$' with '$', as there is no need to
double it.

* In dependency lines, avoid modifiers containing ';'.

To make the makefile easier readable and at the same time avoiding line
noise, you can use a multi-variable .for loop, which are available since
2000:

.for base ext in $(INSTALLMAN:C;^(.*)\.([0-9].*)$;\1 \2;)
install_files:: $(INSTMANDIR)/cat${ext}/${base}.0
.endfor

Roland



Home | Main Index | Thread Index | Old Index