[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Evaluation and expansion
From: |
Kaz Kylheku |
Subject: |
Re: Evaluation and expansion |
Date: |
Wed, 07 Jun 2023 00:08:22 -0700 |
User-agent: |
Roundcube Webmail/1.4.13 |
On 2023-06-06 15:14, Bartłomiej Wójcik wrote:
> Hi,
>
> I would like to ask you for help with clarifying the idea of evaluation and
> expansion related to makefile. As I understand, expansion refers to
> replacing macro reference by its value and there are two possible ways of
> expansion - *immediate* and *deferred* which depends on the construction
> itself. I also found that in the *immediate* context the expansion is done
> before evaluation, and for the *deferred* context, it is the opposite. But
> it is also stated that in the *immediate *context, the expansion is done
> while parsing, which would be contradictory, because as I understand the
> evaluation is the process of parsing and internalizating.
The terms "eager" and "lazy" could be used.
# eager/immediate: $(bar) is expanded, combined with abc, and assigned to foo
foo := $(bar) abc
# lazy/deferred: foo is assigned the unexpanded right hand side.
foo = $(bar) abc
# eager/immediate: here, the variable is not in the right hand side
# of a lazy definition's assignment; its value is required
# immediately, just like in the right hand side of :=
target: prerequisite $(foo)
build step
Outside the right side of an assignment, everything is immediate:
when the value of a variable is needed, it is replaced by its
content, which is fully expanded, as necessary.
Mostly, the syntax determines whether the right hand side of
an assignment is expanded immediately or deferred. Except
that certain kinds of assignments like += rely on whether the
variable was previously the target of a deferred or immediate
assignment. For the purpose of these operators, variables have
to track the style in which they were most recently assigned.
That attribute can optimize expansion. If we know that we
need the value of $(foo), and we know that it was assignned using
IMMEDIATE := IMMEDIATE, then we know we don't have to run an expansion
pass on it; just dump the content where we need it.
The documentation has a diagram like this:
IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE ::= IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
IMMEDIATE != IMMEDIATE
define IMMEDIATE
DEFERRED
endef
# ... etc ... not going to reproduce all of it
Why is there IMMEDIATE on the left hand sides? Because
left hand sides can contain expansions too: computed
variables. Things like:
OBJS_$(this_file) = foo.o bar.o
The above diagram tells us that this is IMMEDIATE = DEFERRED
which tells us that OBJS_$(this_file) is expanded immediately
in order to determine the name of the variable which receives
the right hand side body.