我是一个Makefile新手,我想用它来更改时间戳时渲染Rmarkdown文件,以生成相应的.pdf
文件。文件data_prep_1.Rmd
将呈现为.pdf
,并另外生成输出文件all_sample_data.csv
。更改data_prep_1.Rmd
(或更改其时间戳)时,应该重新呈现它,../bioinformatics/Reads_by_sample.Rmd
和distance_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中获得我想要的行为?
答案 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.Rmd
和Reads_by_sample.Rmd
;如果有任何改变,你不想重建吗?