Reputation: 13120
In (GNU) make, I want a variable to be assigned a value when the build chain of specific targets are starting. For targets a.so
and b.so
, each depending on b.o
, I can do this manually like this:
# Rules
all: a.so b.so
a.so: b.o
@echo Current .so is $(current)
touch $@
b.so: b.o
@echo Current .so is $(current)
touch $@
b.o:
@echo Current .so is $(current)
touch $@
# Set the "current" variable based on which .so is being build
a.so: current = a.so
b.so: current = b.so
Here, current
has the value a.so
when executing the rules for both a.so
and b.o
, while current
has the value b.so
only when executing the rule for b.so
. This is what I want. The mental model I have of this is that the line a.so: current = a.so
gets triggered as soon as make finds out that a.so
should be build (that is, before the rules of either a.so
or b.so
are run). Please correct me if I'm wrong.
In my actual case, I have many more .so
files, and so I want to replace the two last lines with something like this;
%.so: current = $@
or this;
sofiles = a b
$(addsuffix .so, $(sofiles)): current = $@
However, both of these result in the same, wrong behavior, where the current
variable gets set anew even when the b.o
target is about to be build. Why does the b.o
target trigger these lines? How can I achieve the same behavior as when manually writing a.so: current = a.so
for every .so
, but without actually wiring this for every single .so
?
Note: I know that the use case shown in the example code is weird and that the sought after effect can be achieved without this awkward current
variable. I am however not interested in any solution which solves the problem without using this variable.
Upvotes: 0
Views: 1336
Reputation: 101051
There are many things to discuss here. First, your mental model of how target-specific variables works is not quite accurate ("the line a.so: current = a.so gets triggered as soon as make finds out that a.so should be build"). What really happens is that each target make encounters creates a new "scope" which is active while that target and all its prerequisites are being created, and the target-specific variables for that target are in effect inside that scope. Once that scope exits (the target is finished) then those variable settings are gone.
In your example above, current
will have the value a.so
inside the recipe for b.o
only when b.o
is being created as a prerequisite of a.so
. If b.o
was being created as a prerequisite of b.so
, then current
would be b.so
. Because your makefile lists a.so
first it will be built first, and because b.o
will only be built once (per invocation of make), it may appear that it's always using a.so
as the value of current
but that's not precisely accurate. Consider this:
$ make all
Current .so is a.so
touch b.o
Current .so is a.so
touch a.so
Current .so is b.so
touch b.so
But also this:
$ rm -f b.o
$ make b.so
Current .so is b.so
touch b.o
Current .so is b.so
touch b.so
See how current
is set to b.so
if b.o
is built because it's a prerequisite of b.so
not a.so
.
And also this:
$ rm -f b.o
$ make b.o
Current .so is
touch b.o
Here because b.o
isn't a prerequisite of any .so
, then current
is not set at all!
The next thing to think about is this line:
%.so : current = $@
It's not true that this line is "triggered" for b.o
. However, this sets the pattern-specific variable current
to the value $@
(note, NOT to the expansion of the $@
variable!). This means that each time $(current)
is expanded it will expand to $@
, which is the current target name, for whatever recipe it's used in. So this won't expand to a.so
or b.so
unless the current target name is actually a.so
or b.so
. If the target name is b.o
then $@
expands to b.o
.
If you want to do this you can't use a variable like $@
, you have to use the real value. You can do this with eval
, for example:
sofiles = a b
$(foreach SO,$(sofiles),$(eval $(SO).so: current = $(SO).so))
However, based on the first comments above I'm not sure that's sufficient for your needs.
Upvotes: 1