Date: Fri, 3 Feb 2012 15:20:10 -0600 From: "Conrad J. Sabatier" <conrads@cox.net> To: Matthew Seaman <m.seaman@infracaninophile.co.uk> Cc: freebsd-ports <freebsd-ports@freebsd.org> Subject: Re: BSD make -- Malformed conditional Message-ID: <20120203152010.3b4d0588@cox.net> In-Reply-To: <4F22CB51.6070507@infracaninophile.co.uk> References: <4F22CB51.6070507@infracaninophile.co.uk>
next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 27 Jan 2012 16:05:37 +0000 Matthew Seaman <m.seaman@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@cox.net
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120203152010.3b4d0588>