help-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Conditionals in define


From: Philip Guenther
Subject: Re: Conditionals in define
Date: Sun, 29 Jul 2007 17:12:26 -0600

On 7/29/07, David A. Greene <address@hidden> wrote:
> Why does this print:
>    bye
>    hello
> ?
>
> test.mk:
>
> define test_impl
>
> ifeq (hello,bye)
>   $(info bye)
> else
>   $(info hello)
> endif
>
> endef
>
> test = $(eval $(call test_impl))
>
> $(call test)
>
> all:

Gack up a moment a think about what the argument to the $(eval) is.
GNU make has to expand $(call test_impl) to get that value, so it
expands the 'test_impl' variable.  As part of that expansion, it
recursively expands the variable and function references inside
test_impl's value.  In particular, it expands both $(info) calls,
because at this point it's just performing variable expansion and not
evaluation.  Once the expansion of $(call test_impl) is complete, it
then evaluates the result as makefile syntax, including another round
of variable expansion.

In general, when using $(eval), you need to think carefully about each
variable and function used in the makefile input and whether you want
that use to be expanded _before_ the evaluation or as _part_ of the
evaluation.  Normally, the only variables uses that you want to expand
before the evaluation are those that actually contain makefile syntax
(ifeq, define, assignments, rules, etc).  Other variables uses that
only appear as part of the above should be expanded as part of the
evaluation so that they can be affected by the make syntax rules.


So, in this case, the solution is simple: you want to expand
'test_impl' before the evaluation (because it contains the makefile
syntax of interest) but you don't want any variables *inside*
'temp_impl' to be expanded before the evaluation.  GNU make has a
handy function for doing that: $(value).  If you change the line:

    test = $(eval $(call test_impl))
to
    test = $(eval $(value test_impl))

Then things will work the way you expect.

That solution is simple because it uses a simple rule: don't expand
*any* variables or functions inside 'temp_impl' before evaluation.  If
you need some variables or functions inside of 'temp_impl' to be
expanded before evaluation, then instead of using $(value) you'll need
to change 'temp_impl' to mark which should be delayed.  For example,
consider the following, where we want to expand the $(set_foo) inside
'temp_impl' but not the $(info) calls.  To do so, we mark the latter
by doubling the dollar-sign.

set_foo = foo = bar

define test_impl

$(set_foo)
ifeq (hello,bye)
 $$(info bye)
else
 $$(info hello)
endif

endef

test = $(eval $(test_impl))

$(test)

all:
        @echo $(foo)


With the above, the expansion of $(test_impl) results in the text:
----
foo = bar
ifeq (hello,bye)
 $(info bye)
else
 $(info hello)
endif
----

Thus, the $(info) calls are delayed until the eval.


Two final points:

1) When you're not sure what an $(eval) is doing, try replacing it with $(info),
    thus letting you see exactly what make is doing the evaluation of.
 If you don't
    see a variable reference in the output that you expected, then it
was expanded
    too soon!

2) Your original example had two uses of $(call variable), where there are no
    arguments to be 'passed'.  That is almost exactly equivalent to
simply saying
    $(variable).  If you don't actually know what the differences
between them are,
    then you should use the simpler $(variable) form, as *one* of the
differences
    is that $(call) disables one of GNU make's checks for infinite
loops.  Disabling
    that check without a good reason is a easy way to waste your own time
    debugging makefiles.

    (The other difference between $(call foo) and $(foo) that I can
think of is that
    the former clears all the argument variables ($1, $2, etc) during
the expansion
    of 'foo'.)


Philip Guenther




reply via email to

[Prev in Thread] Current Thread [Next in Thread]