1) 和 2)
您可能应该查看 make 的自动变量:
$ cat Makefile
.NOTPARALLEL:
OUTPUT := output
R = R CMD BATCH --no-save --no-restore
PDF := fig_A.pdf fig_B.pdf
CSV := interim_data.csv source_data.csv
all: $(PDF) $(CSV)
$(PDF): plot_figs.R interim_data.csv
interim_data.csv: source_to_interim.R source_data.csv
source_data.csv: download_source.R
$(CSV) $(PDF):
$(R) $<
mv $<out $(OUTPUT)
$ make
R CMD BATCH --no-save --no-restore download_source.R
mv download_source.Rout output
R CMD BATCH --no-save --no-restore source_to_interim.R
mv source_to_interim.Rout output
R CMD BATCH --no-save --no-restore plot_figs.R
mv plot_figs.Rout output
自动变量通过 make 作为当前目标的$<
第一个先决条件进行扩展(这就是我重新排序fig_A.pdf
,fig_B.pdf
和的先决条件的原因interim_data.csv
)。此外,您可以将带有配方的规则和带有先决条件的规则(和没有配方)分开。
请注意,.NOTPARALLEL
它告诉 make 不要并行运行多个配方。在您的情况下,它是必需的,因为您有两个目标 (fig_A.pdf
和fig_B.pdf
) 生产相同plot_figs.Rout
的副产品,这些副产品会被相同的配方移出。如果允许 make 以并行模式运行,则存在竞争条件的风险。
3)
这有点困难,因为您的食谱会产生 2 个不同的输出:*.csv
(或*.pdf
) 和*.Rout
. 并且在设计时并未考虑到这种情况。它更倾向于一种配方=一种文件产品。但我们可以尝试使用宏 ( R
) 隐藏这些文件移动:
$ cat Makefile
.NOTPARALLEL:
OUTPUT := output
R = R CMD BATCH --no-save --no-restore $(1) && mv $(1)out $(OUTPUT)
PDF := fig_A.pdf fig_B.pdf
CSV := interim_data.csv source_data.csv
all: $(PDF) $(CSV)
$(PDF): plot_figs.R interim_data.csv
interim_data.csv: source_to_interim.R source_data.csv
source_data.csv: download_source.R
$(CSV) $(PDF):
$(call R,$<)
$ make
R CMD BATCH --no-save --no-restore download_source.R && mv download_source.Rout output
R CMD BATCH --no-save --no-restore source_to_interim.R && mv source_to_interim.Rout output
R CMD BATCH --no-save --no-restore plot_figs.R && mv plot_figs.Rout output
make函数$(call...)
扩展为其第一个参数变量(R
$(1)
$<
$(2)
注意 的定义R
:它使用递归赋值运算符 ( =
),而不是简单的赋值运算符 ( :=
),因为我们希望它仅在需要时展开,就在 make 将配方传递给 shell 执行之前。