[Top][All Lists]

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

Re: Variable definition in eval'd function

From: Bryan Ischo
Subject: Re: Variable definition in eval'd function
Date: Thu, 3 Jan 2008 19:03:39 -0500 (EST)
User-agent: SquirrelMail/1.4.8-4.fc5

Philip Guenther wrote:
> You're missing section 3.9, "How `make' Reads a Makefile".  It's
> explained there how the expansion of variables occurs immediately (as
> the makefile is parsed) in some contexts and is deferred until the
> involved text is used in other contexts and which contexts are which.

Ah yes - that page brings back memories now; I am sure I have read it in
the past but forgotten about it.  Here is its Rule Definition section,
which I think is highly elucidating:

   A rule is always expanded the same way, regardless of the form:


   That is, the target and prerequisite sections are expanded
immediately, and the commands used to construct the target are always
deferred.  This general rule is true for explicit rules, pattern rules,
suffix rules, static pattern rules, and simple prerequisite definitions.

So we can see that evaluation of the commands text is DEFERRED, whereas
all other parts of a rule are evaluated IMMEDIATEly.

This is the behavior that I find very often confusing and leads to many
subtle problems with my makefiles.  I really wish there were some way
around this.

I realize that deferring the evaluation of commands is good for
performance; because if GNU Make isn't going to execute the command, then
there is no reason to spend the time evaluating it.  On the other hand,
unless the commands are evaluated at the same time as the rest of the
makefile, there is this "odd" (in my eyes) DEFERRED evaluation behavior.

> Instead of performing variable expansion on the commands immediately,
> how about saving the value(s) you want until when the commands _are_
> subject to expansion?  That's what target-specific variables get you.
> If were to contain
> ---
> foo: VARIABLE = foo_variable
> ---
> then you could easily obtain the desired results with just one
> $(eval).  Yes, that's a change to the 'specification', but:
> 1) it may just be an intermediate step to a solution that matches your
> original spec,
> 2) perhaps it should be reexamined why and are separate
> files instead
>     of being one file with two lines...

It's really hard to explain exactly what problems I was having that
resulted in me having difficulties with the deferred evaluation of some
variables.  I just know that I spent hours and hours and HOURS playing
with double-evals, double-dollar-signs to escape values, variable
assignments, := vs =, etc, etc; it was *incredibly* difficult to keep all
if it in order when the templates and function invocations got really
complex.  Getting all of the pieces to fit really did feel like putting
together a very difficult jigsaw puzzle.

My goal was to write one makefile defining all of the rules that I would
ever use in any particular project, and have each subdirectory of the
project define a single makefile that gave the specifics for that
particular subdirectory.  This goal of making all of the subdirectory
makefiles "seem" independent, when in reality they were all being glommed
together by being -include'd by the top-level makefile, led to some
inconsistencies that were difficult to rectify in the central makefile. 
The most difficult thing was making templates which themselves $(call)ed
other templates work properly, especially when the rules that eventually
were being created by the innermost templates included variable references
in the rule commands.

Anyway, back to the original question: can anyone tell me exactly why both
$(eval) functions are needed in this example?

--- begin ---
VARIABLE = foo_variable
--- end ---

--- begin
VARIABLE = bar_variable
--- end ---

--- begin Makefile ---

FRAGMENTS = foo bar

define TEST_RULE

.PHONY: $(1)
       @echo $$@
       @echo $(2)



-include $(1).mk

$$(eval $$(call TEST_RULE,$(1),$$(VARIABLE)))


$(foreach i, $(FRAGMENTS), $(eval $(call PROCESS_FRAGMENT,$(i))))

--- end Makefile ---

Why isn't just the outer $(eval) needed?  Shouldn't the outer $(eval) be
sufficient for evaluating the text produced by the recursive $(call)s?

And, why do I need to escape the variable references in the
PROCESS_FRAGMENT template using $$?  If I just use one dollar sign, it
doesn't work.

Thank you!

reply via email to

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