【问题标题】:make always rebuilds Makefile targetsmake 总是重建 Makefile 目标
【发布时间】:2014-07-20 07:31:52
【问题描述】:

我为我的论文项目重新设计了大部分 Makefile 文件,以正确反映工作流程 (Creating make rules for dependencies across targets in project's sub-directories)。但是,在特定的子目录 (prepare) 中,make 总是 会重建 所有目标,即使依赖项没有变化。 出现这种意外行为的原因可能是什么?

注意:sf.done 是一个真实文件(类型,我称之为“标志文件”),位于不同的子目录中,并在数据收集完成时创建/更新 (import) - 依赖于步骤目标transform

准备/生成文件:

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

更新:

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

【问题讨论】:

  • 请查看我对@MadScientist 答案的最新评论。

标签: r makefile dependencies workflow


【解决方案1】:

您已将目标 import transform cleanup merge sample clean 声明为 .PHONY。这意味着 make 将始终认为它们已过时。

然后你声明各种.done 目标依赖于那些.PHONY 目标。由于虚假目标总是被认为是过时的,那些.done 目标总是需要更新,并且配方总是会触发。

【讨论】:

  • 我不确定你的意思只是基于文件的依赖项。 make 的工作方式是,当它读取一条规则时,它首先将每个先决条件视为一个目标,并尝试创建该目标及其依赖项等等,直到它无法再创建,然后展开递归并运行那些先决条件较新的目标的配方。对于每个先决条件,它必须要么已经存在,要么 make 必须知道如何构建它(必须有规则来构建它),否则 make 将失败。
  • 关于你的第一个问题:你应该做你所做的:让目标依赖于“标志文件”(我通常称它们为“哨兵文件”)而不是虚假目标。虚假目标主要用于提供命令行目标。
  • makefile 中的所有内容都依赖于import.done,并且该步骤需要../import/sf.done 文件,因为您已将其列为依赖项。如果该文件不存在,则任何内容都无法运行,因为您尚未告诉此 make 文件如何创建该目标。
  • make 不会只是随机开始运行配方,希望其中一个会创建文件!如果该文件不存在,您必须告诉 make 如何构建它。您可以通过声明要构建的文件是该规则的 target 的规则来做到这一点。您有一个目标是import 的规则,但这无助于理解如何构建$(IMPORT_DIR)/sf.done。如果你想运行该配方来构建$(IMPORT_DIR)/sf.done,那么目标必须是$(IMPORT_DIR)/sf.done,而不是import
  • 您的 makefile 中没有任何内容可以创建 import.done 文件。因此,它永远不会是最新的,并且配方将始终运行。我想您在import.done 目标上缺少touch $@ 命令,就像您在其他目标上一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多