intermediate targets not working as expected

From:

gmake

Subject:

intermediate targets not working as expected

Date:

Sun, 30 Jul 2006 11:37:48 -0500 (CDT)

I have a large number of files (over 1000) and have pattern rules such
as these to build them:
####################################################### Begin Makefile
RES_DIR := results
EXE_DIR := exe
SOURCE_DIR := source
RUNEX := a* c* d* s* x*
RES := $(sort $(foreach NAME,$(RUNEX),$(patsubst %.f,$(RES_DIR)/%.r,$(notdir
$(wildcard $(SOURCE_DIR)/$(NAME).f)))))
all: $(RES)
$(RES_DIR)/%.r: $(EXE_DIR)/%.exe
@mkdir -p $(@D)
$< > $@
$(EXE_DIR)/%.exe: $(SOURCE_DIR)/%.f
@mkdir -p $(@D)
$(F90) $^ -o $@
.INTERMEDIATE: $(patsubst $(RES_DIR)/%.r,$(EXE_DIR)/%.exe,$(RES))
.PHONY: all
####################################################### End Makefile
(Linux make 3.79.1; the above is a simplification of much larger code.)
RES is thousands of files long.
Each .r file in RES is generated by running an .exe, which in turn is
generated by compiling a .f.
Everything builds and runs okay, but the .INTERMEDIATE target does not
work the way I expect, in two ways:
1. It does not remove each .exe after using it to build a .r. When a
single .r has finished being built, I expect its intermediate .exe
prerequisite to be removed. Instead, it does not get removed until all
.r's finish getting built. By then, the disk is full of .exe's.
Does the fact that "all" depends on every file in RES, delay the removal
of the %.exe prerequisites, until all the RES are built? It shouldn't.
I tried a smaller, similar makefile, and it removed the .exe's after
every target was built. But it did not have as many files, and it did
not use pattern rules.
If I try my originaly makefile, with RES having a smaller number of
entries, the problem still cocurs.
2. It does not remove any .exe files if it is aborted by user interrupt
(CTRL-C). All .exe files remain. This build is part of a recursive make,
if that is important (higher-level makes call this one, but they don't
do anything to the targets of this make invocation).
I could of course explicitly add the rm to the end of the %.r pattern
rule, but that would still not remove it if make were interrupted.
When are intermediate targets removed, if they are prerequisites to a
large number of pattern targets, which in turn are prerequisites to a
single target? The docs are not clear on exactly when removal occurs
and whether it is delayed, and whether parallelism (-j) or recursive
makes can change when an intermediate target is removed.
(If the docs are clear on this, they are not well indexed or
searchable.)
I can use another level of recursion to force the remove after every
.r gets built, by forcing each .r to be its own make invocation:
all: $(RES:r=junk)
$(RES:r=junk):
$(MAKE) $(@:junk=r)
.PHONY: $(RES:r=junk)
This also fixes the problem of make not removing the file on user
interrupt. But it seems like overkill.
Thanks,
Lee