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