This is a reprise of an e-mail I sent to the freebsd-ports@freebsd.org mailing list last January.
When hacking on Makefiles, should you wish to match an item in a list, you might write something like this:
.for item in ${LIST}
.if ${item} == ${THING} # Ooops!
THING_FOUND=1
.endif
.endfor
This however is a snare and a delusion, and will lead to much weeping and wailing, and error messages like so:
% make
"Makefile", line 7: Malformed conditional (foo == ${THING})
"Makefile", line 9: if-less endif
"Makefile", line 7: Malformed conditional (bar == ${THING})
"Makefile", line 9: if-less endif
"Makefile", line 7: Malformed conditional (baz == ${THING})
"Makefile", line 9: if-less endif
"Makefile", line 7: Malformed conditional (blurfl == ${THING})
"Makefile", line 9: if-less endif
make: fatal errors encountered -- cannot continue
Instead you should write your loops like this:
.for item in ${LIST}
.if ${THING} == ${item}
THING_FOUND= 1
.endif
.endfor
As the make(1) manual page says on the subject of string comparisons using == or !=:
An expression may also be a numeric or string comparison: in this case, the left-hand side must be a variable expansion, whereas the right-hand side can be a constant or a variable expansion.
So it seems that despite appearing and behaving almost exactly like one, the iterator in a .for loop is not actually a variable as such. It also means that to match a constant string, you can't just write:
.for item in ${LIST}
.if ${item} == this # Ooops
THIS_FOUND=1
.endif
.endfor
but have to assign the text "this" to a variable somewhere, and use the second form.
Yes, you can (and preferrably should) use ${LIST:Mthis} instead, but using this construct only works when matching constant text:
% cat Makefile
LIST=foo bar baz blurfl
THING=baz
all:
@echo "OK \$${LIST:Mfoo} = ${LIST:Mfoo}"
@echo "Not OK \$${LIST:M\$${THING}} = ${LIST:M${THING}}"
% make
OK ${LIST:Mfoo} = foo
Not OK ${LIST:M${THING}} = }
Also note: as a matter of style, when matching a constant string, don't enclose that string in "quote marks" when it isn't necessary:
.if ${item} == "this" # Wrong!