Hi Kris,

On Sat, Feb 12, 2005 at 06:32:01PM -0800, Kris Kennaway wrote:
> The following small makefile doesn't behave as one would naively
> expect:
> 
> MANLANG?=foo ""
> all:
> .for i in ${MANLANG}
> .if empty(${i})
>         @echo foo ${i}
> .endif
> .endfor
> 
> ports-i386%make
> foo foo
> foo
> 
> I think this is because the .if evaluation is happening too early, and
> it's not being done after the .for loop is expanded and the i variable
> is set.
> 
This makefile is broken, you're abusing empty().  empty() expects
a variable name (without `$') as an argument, and ``.if empty(foo)''
means "true if ${foo} has an empty value".  Note that in 4.x, "foo"
also needs to be a defined variable, for this to work at all.  In
5.x and 6.x, undefined variables are treated like empty variable
by empty().

> In order to get this to work I seem to have to do the following:
> 
> MANLANG?=foo ""
> .for i in ${MANLANG}
> j=      ${i}
> .if (${j} != "\"\"")
> .for l in ${j}
> k+=     ${l}
> .endfor
> .endif
> .endfor
> all:
>         @echo ${k}
> 
> ports-i386%make
> foo
> 
> If I remove the inner .for it breaks, and if I remove the j assignment
> it breaks.  Also if I try and remove the use of k and put an echo
> inside the inner .for (with the all: preceding the whole loop) it
> breaks.
> 
> This is extremely nasty.
> 
Yes.  This behavior is documented in the BUGS section of the make(1)
manpage: .for loops are unrolled before tests, and .for variables
aren't real variables, so a fragment like this:

.for i in foo bar
.if ${i} == "foo"
        echo ${i}
.endif
.endfor

doesn't work.  This fragment is rewritten by make(1) before further
parsing as follows:

.if foo == "foo"
        echo foo
.endif
.if bar == "foo"
        echo bar
.endif

And since .if expects a ${variable} as its first argument, it fails.

About why you need an inner loop.  Remember again that .for loops
are unrolled before parsing, it means that a fragment like this:

.for i in foo bar
j=${i}
k+=${j}
.endfor

is equivalent to

j=foo
k+=${j}
j=bar
k+=${j}

which means that `k' will get a value of "bar bar".  When you use
an inner loop,

.for i in foo bar
j=${i}
.for l in ${j}
k+=${l}
.endfor
.endfor

it first gets rewritten to:

j=foo
.for l in ${j}
k+=${l}
.endfor
j=bar
.for l in ${j}
k+=${l}
.endfor

then to:

j=foo
k+=foo
j=bar
k+=bar

which DTRT, but also has a side effect of setting "j" to "bar".

> Am I missing an easier way to do this?
> 
May I suggest the following instead:

%%%
MANLANG?=       foo "" bar
all:
.for i in ${MANLANG:N""}
        @echo foo ${i}
.endfor
%%%

Note that `""' is not an empty value in make(1), it's just a
regular value consisting of two double quotes.


Cheers,
-- 
Ruslan Ermilov
[EMAIL PROTECTED]
FreeBSD committer

Attachment: pgpjj2c9e1zVG.pgp
Description: PGP signature

Reply via email to