[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Recursive $(call)
From: |
Philip Guenther |
Subject: |
Re: Recursive $(call) |
Date: |
Mon, 25 Feb 2002 21:14:48 -0800 |
"Paul D. Smith" <address@hidden> writes:
>%% Philip Guenther <address@hidden> writes:
>
> pg> It would greatly increase the expressiveness of GNU make's macro
> pg> expansion if it was possible to define recursive macro functions.
> pg> For example, here's a function that performs calculates the
> pg> transitive closure of a set of dependencies:
>
> pg> # If $(firstword) is car, this is cdr:
> pg> rest = $(wordlist 1,$(words ${1}),${1})
>
> pg> tclose = $(if ${1},$(firstword ${1}) \
> pg> $(call tclose,$(sort ${DEP_$(firstword ${1})} \
> pg> $(call rest,${1}))))
>
>Heh. I see your point, but I have to say that your example proves
>exactly the amount of danger involved with allowing this: your
>definition of "rest" has a bug which causes this series to loop
>infinitely! :)
Oops...
> pg> Unfortunately, the restriction on recursive macros not referencing
> pg> themselves includes references via $(call). I would argue that
> pg> GNU make should not try to protect someone from themself if the
> pg> write a recursive $(call). Yes, you can trivially write infinite
> pg> loops if it's allowed, but the increase in expressiveness is
> pg> substantial.
>
>OK, I buy this argument. As a test I removed the restriction on
>recursive variable definitions and (with the above fix) your example
>did work as you intended. Neat.
>
>However, I think the restriction is valid for normal variable
>expansions, and most if not all builtin functions. Are there any other
>builtins you think would benefit from loosening this restriction?
The only other one which could legitimately benefit would be $(foreach),
as it's the only other builtin which can change the value of a variable
during expansion. That is, just as self-reference in $(call) can be
done safely by conditioning the recursion on the values of the argument
variables, self-reference in $(foreach) can be done safely by
conditioning it on the value of the iteration variable.
In fact, I _think_ the following pair of assignments would again
implement transitive closure:
tclose_ = ${dep} $(foreach dep,${DEP_${dep}},${tclose_})
tclose = $(sort $(foreach dep,${1},${tclose_}))
...but I think that's harder to read than the $(call) version. From the
programming language perspective, $(call) is to be prefered as the
variable 'reassignment' is part of the recursion machinery, instead of
being done in the "parent's" $(foreach).
Philip Guenther