[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: |
Wed, 10 Oct 2007 16:35:15 -0400 (EDT) |
User-agent: |
SquirrelMail/1.4.8-4.fc5 |
> That's because $(VARIABLE) is going to be expanded after you've read in
> all the Makefiles (because it's inside a rule) and hence it takes the
> last value that VARIABLE was set to (which is bar_variable). The best
> way to do with will be with a target-specific variable where you do
>
> foo: VARIABLE := foo_variable
>
> and
>
> bar: VARIABLE := bar_variable
Thank you for the clear explanation, that really helps my understanding of
the problem.
What you suggest is a good idea, unfortunately it won't quite work in the
makefile structure that I am using.
Essentially, I have written a single makefile that defines a bunch of
templates that all get invoked once for each makefile "fragment" file (as
I call the incomplete Makefiles that get included by the main makefile).
For example, a fragment file can do something like this:
LIBRARIES = libfoo libbar
libfoo_SOURCES = foo.cpp foo2.cpp
libbar_SOURCES = bar.cpp bar2.cpp
And the main makefile will invoke templates to cause libfoo and libbar to
have rules defined for building them, based on the sources to compile and
link into the library.
Whereas I typically expect the specific libraries to have unique names,
and so the variables like "libfoo_SOURCES" and "libbar_SOURCES" will be
unique and not subject to the
rules-only-use-the-last-definition-of-a-variable problem, the "LIBRARIES"
variable will be defined once per fragment and so its value needs to be
used for all parts of the template in the invocation of the template for
that fragment - both the targets and rules parts.
In general, my approach is working well because all of my templates pass
in the target names as template parameters, which *do* work the way I want
in rules (I guess that variables of the form $(1) are "special" and when
$(call) is invoked on a template, the variable expansion happens
immediately even inside rules - I wish that were true for all variables!).
The only one that is giving me trouble is my "clean" rule, which is NOT
generated by a template invocation, and thus does not use $(call)
parameters in the rule.
I guess that I will have to make up a template for the clean rule too,
which will I believe solve my problem in the way that works best for me.
As an aside, I think that the power of $(call) and $(eval) in GNU make are
just incredible. They allow one to define a "template" system where a
project can be broken up into multiple sub-directories (as most good
software projects that I have worked on are) that are built in order, and
have each sub-directory define the libraries, executables, etc, that it
needs to build in a very straightforward fashion without defining any
rules at all but just by setting variables that the main makefile uses to
generate all of the complex rules necessary. This really gives great
bang-for-the-buck, where some care and effort in creating a good Makefile
with really comprehensive templates allows all of the sub-directory
makefile "fragments" to be small, simple, and clean, and yet to result in
very complex behaviors in the resulting make system.
However, I find that some aspects of how GNU make syntax works to be
conter-intuitive and confusing. Some of them probably are just me being
dense (all of the double-escaping of variables necessary (i.e. $$(foo) so
that $(eval $(call)) works as expected), and getting that wrong half the
time), but the topic of this email in particular - the fact that variables
are evaluated differently inside rules than outside rules - makes things
much more difficult than necessary.
Does anyone know the reason behind this behavior? I can't think of why
doing it this way is better. But I am sure I will be proven wrong as is
often the case when I question the design of established software written
by smart people :)
Consider: if the variables in rules are only ever substituted once, when
the rule is invoked (which I believe is what is happening right?) then any
variable which is set more than once in a makefile will only ever use its
final value in rules. That means that something like this will never work
the way I want:
CC = gcc
foo: foo.c
$(CC) -o $@ $^
CC = g++
bar: bar.cpp
$(CC) -o $@ $^
This is a very contrived example - I know that in this particular example
there would be many ways to work around this problem. But in more complex
examples, especially those using templates, it becomes much more difficult
to work around.
Now, if instead, variables inside rules worked just like any other
variable - they were evaluated and substituted into the text of the
makefile the moment that the text is parsed by make and incorporated into
make's internal data structures - then the above *would* work.
In the case where a variable is only ever set once in a makefile, both
approaches would be identical. But in the case where a variable is set
more than once, the current functionality of gnu make where the variable
is only ever evaluated in the rule when the rule is invoked (instead of
when the rule is defined), makes setting the variable multiple times
meaningless. I am just advocating making the user's intentions in setting
a variable multiple times (which surely they did because they wanted the
value most recently assigned to apply to all make constructs up until the
next assignment of the variable) come through instead of being stifled.
Comments?
Thank you, and best wishes,
Bryan