为项目子目录中的目标创建依赖关系的make规则

时间:2014-05-28 11:12:34

标签: r makefile dependencies workflow

我的论文研究软件的源代码树(R)反映了传统的研究工作流程:"收集数据 - >准备数据 - >分析数据 - >收集结果 - >发布结果"。我使用make来建立和维护工作流程(大多数项目的子目录包含Makefile个文件)。

但是,我经常需要通过项目子目录中的特定Makefile目标(不是通过顶级Makefile)来执行工作流的各个部分。这会产生一个问题,即设置Makefile 规则以维护工作流不同部分的目标之间的依赖关系,换句话说 - {{1}中的目标之间文件,位于不同的子目录中。

以下代表我的论文项目的设置

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) 文件中的目标片段:

"〜/ DISS-牙线/生成文件" (几乎已满):

Makefile

"〜/ DISS-牙线/进口/生成文件":

# 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

"〜/ DISS-牙线/准备/生成文件":

importFLOSSmole: getFLOSSmoleDataXML.R
    @$(RSCRIPT) $(R_OPTS) $<
...

&#34;〜/ DISS-牙线/分析/生成文件&#34;:

transform: transform.R
    $(RSCRIPT) $(R_OPTS) $<
...

目前,我担心创建以下依赖项:

通过eda: eda.R @$(RSCRIPT) $(R_OPTS) $< 中的Makefile制作目标而收集的数据始终需要通过在importMakefile制作相应的目标进行转换,然后再进行分析,示例prepare。如果我在eda.R中手动运行make,然后忘记转换,请在import中运行make eda,事情进展不顺利。因此,我的问题是:

我如何使用analyze实用程序的功能(以最简单的方式)来建立和维护不同目录中make个文件的目标之间的依赖关系规则?

2 个答案:

答案 0 :(得分:1)

您现在使用makefile的问题是您只将代码列为依赖项,而不是数据。这就是很多魔法发生的地方。如果&#34;分析&#34;我知道它将使用哪些文件并将它们列为依赖项,它可以回顾它们是如何制作的以及它们具有的依赖关系。如果管道中的早期文件已更新,则可以运行所有必要的步骤以使文件保持最新。例如

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 import,它将下载新的csv文件。然后,如果我运行make plot,它会尝试生成plot.png,但这取决于transdata.csv,这取决于rawdata.csv,并且自rawdata.csv更新后,它将会更新需要更新transdata.csv然后它就可以运行R脚本了。如果您没有明确设置很多文件依赖项,那么您就会错失许多make的强大功能。但是要失败,有时候在那里获得所有正确的依赖关系会很棘手(特别是如果你从一个步骤产生多个输出)。

答案 1 :(得分:0)

以下是关于将我的研究工作流程的数据依赖性添加到项目当前的想法(来自@ MrFlick的一些想法 - 谢谢) make基础架构(使用代码段)。我还尝试通过在make 目标之间指定依赖关系来反映所需的工作流程。

导入/生成文件:

importFLOSSmole: getFLOSSmoleDataXML.R FLOSSmole.RData
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

(similar targets for other data sources)

<强>准备/生成文件:

IMPORT_DIR=../import

prepare: import \
         transform \
         cleanup \
         merge \
         sample

import: $IMPORT_DIR/importFLOSSmole.done # and/or other flag files, as needed

transform: transform.R import
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

cleanup: cleanup.R transform
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

merge: merge.R cleanup
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

sample: sample.R merge
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

<强>分析/生成文件:

PREP_DIR=../prepare

analysis: prepare \
          eda \
          efa \
          cfa \
          sem

prepare: $PREP_DIR/transform.done # and/or other flag files, as needed

eda: eda.R prepare
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

efa: efa.R eda
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

cfa: cfa.R efa
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

sem: sem.R cfa
    @$(RSCRIPT) $(R_OPTS) $<
    @touch $@.done

目录Makefileresultspresent个文件的内容仍为TBD。

感谢您对上述内容的想法和建议!