BSD make -- Malformed conditional
Conrad J. Sabatier
conrads at cox.net
Fri Feb 3 21:20:18 UTC 2012
On Fri, 27 Jan 2012 16:05:37 +0000
Matthew Seaman <m.seaman at infracaninophile.co.uk> wrote:
>
> Dear all,
>
> Posting this mostly for the archives, but it's probably relevant to
> some people here too.
>
> 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 use ${LIST:Mthis} instead, but using this construct can
> be a bit tricky in itself...
>
> % 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}} = }
>
> Cheers,
>
> Matthew
>
Wow, that is a pretty obscure bit of an oddity, isn't it? How'd you
ever discover that?
Looking at the man page, it seems more than a little misleading, as it
does call the iterator in .for loops a "variable" (which for all
intents and purposes, I'd say that it is, in fact). One could easily
lose one's marbles trying to "debug" something like this!
Looks like a bug, smells like a bug to me. Or at least, some *very*
quirky behavior/a serious design flaw that surely wouldn't be missed,
were someone to take the initiative to change it. <hint-hint> No
language should require you to jump through this sort of torturous,
totally anti-intuitive hoop to accomplish what you want to do. Talk
about your POLA! :-)
--
Conrad J. Sabatier
conrads at cox.net
More information about the freebsd-ports
mailing list