Reputation: 180
I have a build procedure roughly described by the following Makefile example:
a: b
@echo "Build a, just using b. Don't care about c."
touch a
b: c
@echo "Constructing b from c is cheap..."
touch b
@echo "Once accomplished, I no longer need c."
c:
@echo "Constructing c is very expensive..."
@echo "Work work work..."
touch c
clean:
$(RM) a b c
example: clean
make a
$(RM) c
make a
The point is: I need c
to build b
, but once I have b
, I never again need c
. When I do make example
, make
makes c
, b
, and a
(as expected), deletes c
, and then, in the last make a
invocation, just remakes c
(and does NOT re-make b
and a
, even though, I'd have thought they were stale now). But, since my goal is a
and b
hasn't changed, I don't want to remake c
. Forget about it! Who cares! a
should be considered up-to-date.
Another peculiar thing, is that when I
make a
rm c
make a
(rather than make example
), in the second invocation make
rebuilds everything (while in make example
the second invocation just rebuilds c
).
How do I prevent make
from building c
when its goal is a
and all of a
's immediate prerequisites exist and is fresher than they are (a
isn't stale compared to b
), even though the prerequisites of the prerequisites do not?
Edit: I think that what I may want is to treat every file as old (eg. with --old-file
) unless that file doesn't exist.
Upvotes: 1
Views: 253
Reputation: 17383
It looks like you want make
to treat the file c
as an intermediate file, a file that does not have any importance to you other than as an intermediate result when generating another file or other files. This concept is explained in section 10.4 Chains of Implicit Rules of the manual. Since your example does not use any implicit rules, you can manually mark your file c
as .INTERMEDIATE
.
This makefile shows c
as an intermediate file.
a: b
@echo "Build a, just using b. Dont care about c."
touch a
b: c
@echo "Constructing b from c is cheap..."
touch b
@echo "Once accomplished, I no longer need c."
c: d
@echo "Constructing c is very expensive..."
@echo "Work work work..."
touch c
.INTERMEDIATE: c
.PRECIOUS: c
I added a file d
, based on your comment, although it is not needed for this example to work.
Before invoking make
, the file d
has to exist, it is the starting point of the chain. When invoking make
, the following happens:
$ touch d
$ make
Constructing c is very expensive...
Work work work...
touch c
Constructing b from c is cheap...
touch b
Once accomplished, I no longer need c.
Build a, just using b. Dont care about c.
touch a
Now deleting c
will not have any impact on the build:
$ rm c
$ make
make: `a' is up to date.
Other than that, the update behavior based on dependencies is "the same as usual".
The .PRECIOUS
target is optional. It is a built-in that instructs make
not to delete the intermediate file named c
. You can see for yourself what happens if you remove that line.
Upvotes: 3
Reputation: 7005
b
might be built from c
, but you don't want to tell Make that b
depends on c
— if b
merely exists, then that's good enough. So you might write b
's recipe as
b:
$(MAKE) c
@echo "Constructing b from c is cheap..."
touch b
@echo "Once accomplished, I no longer need c."
or if c
is only used in making b
, you could just fold the commands for making c
into the recipe for b
and not expose the existence of c
to Make at all.
Maybe there are more elegant ways of expressing this, without invoking sub-makes. And if c
has some prerequisites that would cause it to be rebuilt if they were updated, I guess they would need to be listed as reprequisites of b
as well.
Upvotes: 0