用于条件渲染Rmarkdown文件的Makefile

时间:2017-11-09 11:56:55

标签: makefile rstudio r-markdown gnu-make

我是一个Makefile新手,我想用它来更改时间戳时渲染Rmarkdown文件,以生成相应的.pdf文件。文件data_prep_1.Rmd将呈现为.pdf,并另外生成输出文件all_sample_data.csv。更改data_prep_1.Rmd(或更改其时间戳)时,应该重新呈现它,../bioinformatics/Reads_by_sample.Rmddistance_matrices.Rmd应该重新呈现,因为它们依赖于.csv文件。如果../bioinformatics/Reads_by_sample.Rmd的时间戳相对于其.pdf更改,则只应重新呈现此.Rmd文件。

将all:和.pdf.csv文件放在第一行将导致每次调用make时都会运行两个块。
我有:

../../data/all_sample_data.csv : data_prep_1.Rmd
    Rscript -e "rmarkdown::render('data_prep_1.Rmd')"
    Rscript -e "rmarkdown::render('../bioinformatics/Reads_by_sample.Rmd')"
    Rscript -e "rmarkdown::render('distance_matrices.Rmd')"

../bioinformatics/Reads_by_sample.pdf :  ../bioinformatics/Reads_by_sample.Rmd
    Rscript -e "rmarkdown::render('../bioinformatics/Reads_by_sample.Rmd')"

如果我执行touch data_prep_1.Rmd,然后make,则第一个块会根据需要运行 但是如果我touch ../bioinformatics/Reads_by_sample.Rmd,那么make

我得到make: '../../data/all_sample_data.csv is up to date'

我知道这是对Makefile的笨拙使用,但我怎样才能在单个Makefile中获得我想要的行为?

1 个答案:

答案 0 :(得分:0)

上述评论令人困惑,但隐藏答案。

make运行时,它不会尝试在makefile中构建每个目标。相反,它只尝试在makefile中构建第一个目标。在你的makefile中,第一个目标是../../data/all_sample_data.csv,因此唯一的目标make将尝试构建。

您可以通过将其添加到命令行来构建其他目标;例如make ../bioinformatics/Reads_by_sample.pdf

如果您总是想要一组特定目标,那么您将创建一个新目标作为makefile中的第一个目标,该目标列出了您要创建的所有其他目标作为先决条件。按照惯例,但只有惯例,该目标通常称为all。所以它看起来像这样:

all: ../../data/all_sample_data.csv ../bioinformatics/Reads_by_sample.pdf
.PHONY: all

../../data/all_sample_data.csv : data_prep_1.Rmd
        Rscript -e "rmarkdown::render('data_prep_1.Rmd')"
        Rscript -e "rmarkdown::render('../bioinformatics/Reads_by_sample.Rmd')"
        Rscript -e "rmarkdown::render('distance_matrices.Rmd')"

../bioinformatics/Reads_by_sample.pdf :  ../bioinformatics/Reads_by_sample.Rmd
        Rscript -e "rmarkdown::render('../bioinformatics/Reads_by_sample.Rmd')"

.PHONY不是必需的,但很有用,它告诉make all不是真正的文件,而只是makefile中的虚拟目标。

您还应该考虑创建一些make变量并使用automatic variables来简化您的makefile,例如:

BIODIR := ../bioinformatics
DATADIR := ../../data

all: $(DATADIR)/all_sample_data.csv $(BIODIR)/Reads_by_sample.pdf
.PHONY: all

$(DATADIR)/all_sample_data.csv : data_prep_1.Rmd
        Rscript -e "rmarkdown::render('$<')"
        Rscript -e "rmarkdown::render('$(BIODIR)/Reads_by_sample.Rmd')"
        Rscript -e "rmarkdown::render('distance_matrices.Rmd')"

$(BIODIR)/Reads_by_sample.pdf :  $(BIODIR)/Reads_by_sample.Rmd
        Rscript -e "rmarkdown::render('$<')"

如果你有很多这类文件,你可以进一步使用模式规则等。

此外, 您的第一个目标不仅取决于data_prep_1.Rmd,还取决于distance_matrices.RmdReads_by_sample.Rmd;如果有任何改变,你不想重建吗?