make always rebuilds Makefile targets

2019-01-27 08:51发布

问题:

I redesigned most of the Makefile files for my dissertation project in order to correctly reflect the workflow (Creating make rules for dependencies across targets in project's sub-directories). However, in a particular sub-directory (prepare), make always rebuilds all targets, even when there are no changes in dependencies. What could be the reason for this unexpected behavior?

NOTE: sf.done is a real file (of type, which I call "flag files"), located in a different sub-directory and created/updated upon completion of data collection (import) - dependent step for the target transform.

prepare/Makefile:

IMPORT_DIR=../import

prepare: import \
         transform \
         cleanup \
         merge \
         sample

import: $(IMPORT_DIR)/sf.done
transform: transform.done
cleanup: cleanup.done
merge: merge.done
sample: sample.done

transform.done: transform.R import
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

cleanup.done: cleanup.R transform
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

merge.done: merge.R cleanup
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

sample.done: sample.R merge
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

.PHONY: import transform cleanup merge sample clean

# remove intermediate files
clean:
    rm -f tmp*.bz2 *.Rdata .Rout

UPDATE:

IMPORT_DIR = ../import
IMPORT_DONE = $(IMPORT_DIR)/sf.done

prepare: import \
         transform \
         cleanup \
         merge \
         sample

import: import.done
transform: transform.done
cleanup: cleanup.done
merge: merge.done
sample: sample.done

import.done: $(IMPORT_DONE)
    @cd $(IMPORT_DIR) && $(MAKE)

transform.done: transform.R import.done
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

cleanup.done: cleanup.R transform.done
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

merge.done: merge.R cleanup.done
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

sample.done: sample.R merge.done
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@

.PHONY: import transform cleanup merge sample clean

回答1:

You've declared the targets import transform cleanup merge sample clean to be .PHONY. That means that make will always consider them to be out of date.

Then you declare the various .done targets to depend on those .PHONY targets. Since the phony targets are always considered out of date, those .done targets always need to be updated, and the recipes always fire.