我的论文研究软件的源代码树(R)反映了传统的研究工作流程:“收集数据 – >准备数据 – >分析数据 – >收集结果 – >发布结果”.我使用make来建立和维护工作流(项目的大多数子目录都包含Makefile文件).
但是,我经常需要通过项目子目录中的特定Makefile目标(而不是通过顶级Makefile)执行工作流的各个部分.这会产生一个问题,即设置Makefile规则以维护来自工作流的不同部分的目标之间的依赖关系,换句话说 – 在Makefile文件中的目标之间,位于不同的子目录中.
以下代表我的论文项目的设置:
+-- diss-floss (Project's root) |-- import (data collection) |-- cache (R data objects (),representing different data sources,in sub-directories) |-+ prepare (data cleaning,transformation,merging and sampling) |-- R modules,including 'transform.R' |-- analysis (data analyses,including exploratory data analysis (EDA)) |-- R modules,including 'eda.R' |-+ results (results of the analyses,in sub-directories) |-+ eda (*.svg,*.pdf,...) |-- ... |-- present (auto-generated presentation for defense)
我的一些Makefile文件中的目标片段:
“〜/ diss-floss / Makefile”(几乎已满):
# Major variable definitions PROJECT="diss-floss" HOME_DIR="~/diss-floss" REPORT={$(PROJECT)-slides} COLLECTION_DIR=import PREPARATION_DIR=prepare ANALYSIS_DIR=analysis RESULTS_DIR=results PRESENTATION_DIR=present RSCRIPT=Rscript # Targets and rules all: rprofile collection preparation analysis results presentation rprofile: R CMD BATCH ./.Rprofile collection: cd $(COLLECTION_DIR) && $(MAKE) preparation: collection cd $(PREPARATION_DIR) && $(MAKE) analysis: preparation cd $(ANALYSIS_DIR) && $(MAKE) results: analysis cd $(RESULTS_DIR) && $(MAKE) presentation: results cd $(PRESENTATION_DIR) && $(MAKE) ## Phony targets and rules (for commands that do not produce files) #.html .PHONY: demo clean # run demo presentation slides demo: presentation # knitr(Markdown) => HTML page # HTML5 presentation via RStudio/RPubs or Slidify # OR # Shiny app # remove intermediate files clean: rm -f tmp*.bz2 *.Rdata
“〜/迪斯 – 牙线/进口/ Makefile文件”:
importFLOSSmole: getFLOSSmoledataxML.R @$(RSCRIPT) $(R_OPTS) $< ...
transform: transform.R $(RSCRIPT) $(R_OPTS) $< ...
“〜/迪斯 – 牙线/分析/ Makefile文件”:
eda: eda.R @$(RSCRIPT) $(R_OPTS) $<
目前,我担心创建以下依赖项:
通过在导入中从Makefile制作目标而收集的数据总是需要通过在准备之前使Makefile中的相应目标进行转换,例如eda.R.如果我在导入时手动运行make然后忘记转换,请在分析中运行make eda,事情进展不顺利.因此,我的问题是:
我怎样才能使用make实用程序的功能(以最简单的方式)来建立和维护不同目录中Makefile文件中目标之间依赖关系的规则?
您现在使用makefile的问题是您只将代码列为依赖项,而不是数据.这就是很多魔术发生的地方.如果“分析”知道它将使用哪些文件并且可以将它们列为依赖项,那么它可以回顾它们是如何制作的以及它们具有哪些依赖关系.如果管道中的早期文件已更新,那么它可以运行所有必要的步骤以使文件保持最新.例如
import: rawdata.csv rawdata.csv: scp remoteserver:/rawdata.csv . transform: tansdata.csv transdata.csv: gogo.pl rawdata.csv perl gogo.pl $< > $@ plot: plot.png plot.png: plot.R transdata.csv Rscript plot.R
因此,如果我进行make导入,它将下载一个新的csv文件.然后,如果我运行make plot,它将尝试make plot.png但这取决于transdata.csv并且这取决于rawdata.csv并且因为rawdata.csv已更新,所以它需要更新transdata.csv然后它将准备好运行R脚本.如果你没有明确设置很多文件依赖项,那么你就错过了很多make的强大功能.但是要失败,有时候在那里获得所有正确的依赖关系会很棘手(特别是如果你从一个步骤产生多个输出).