Makefile 从顶层目录调用GNU Make

Makefile 从顶层目录调用GNU Make,makefile,gnu-make,Makefile,Gnu Make,我有一个名为experiments的目录和带有单独实验的子目录,例如2018-08-20,2018-08-21。每个子目录都包含一个Python脚本,我在screen中使用以下命令运行该脚本: screen -L -dm -S experiment python script.py 我想知道我是否可以在experiments目录中有一个Makefile来自动执行这个命令。 我知道我可以在每个子目录中都有一个Makefile,但这会给git带来太多重复的东西。当然可以。由于您没有提供太多细节,我

我有一个名为
experiments
的目录和带有单独实验的子目录,例如
2018-08-20
2018-08-21
。每个子目录都包含一个Python脚本,我在screen中使用以下命令运行该脚本:

screen -L -dm -S experiment python script.py
我想知道我是否可以在
experiments
目录中有一个
Makefile
来自动执行这个命令。
我知道我可以在每个子目录中都有一个
Makefile
,但这会给git带来太多重复的东西。

当然可以。由于您没有提供太多细节,我将假设:

  • 包含
    script.py
    python脚本的
    experiments
    子目录的任何
    都是一个实验
  • 每次调用
    make
    时,都要重新运行所有实验
  • 以下是一个良好的起点:

    EXPDIRS := $(dir $(shell find . -maxdepth 2 -mindepth 2 -type f -name script.py))
    EXPS    := $(addsuffix .done,$(EXPDIRS))
    
    .PHONY: all $(EXPS)
    
    all: $(EXPS)
    
    $(EXPS): %.done:
        cd $* && screen -L -dm -S experiment python script.py
    
    说明:

    • 使用
      find
      实用程序和
      dir
      make函数设置
      EXPDIRS
      make变量(删除返回路径的文件名部分)。示例:
      /experimentC//experimentA/
    • EXPS
      make变量是通过向
      EXPDIRS
      中的每个单词添加
      .done
      来设置的。示例:
      /experimentC/.done./experimentA/.done
    • EXPS
      中列出的目标加上
      all
      目标被声明为虚假,这意味着即使具有该名称的文件已经存在并且是最新的,make也将重新运行其构建规则
    • all
      取决于
      EXPS
      中列出的所有目标。如果您只运行
      make
      make all
      ,make将运行所有实验的规则,如果您使用
      -j4
      选项调用make,并且您的计算机上有4个内核,则make可能并行运行
    • 最后,静态模式规则
      $(EXPS):…
      告诉make如何构建
      EXPS
      中列出的目标:
      • 转到实验目录(使自动变量扩展为
        %.done
        模式的词干)
      • 运行python脚本
    可能的改进:

  • 如果并且仅当实验尚未运行,或者自上次运行以来,其输入数据发生了更改时,才运行实验。让我们假设输入数据只是python脚本(如果需要,很容易修改)。我们将使用一个名为
    experimentA/.done
    的空文件将一个实验标记为已完成,并记住何时完成。然后,应避免以下无用的实验运行:

    EXPDIRS := $(dir $(shell find . -maxdepth 2 -mindepth 2 -type f -name script.py))
    EXPS    := $(addsuffix .done,$(EXPDIRS))
    
    .PHONY: all
    
    all: $(EXPS)
    
    $(EXPS): %.done: %script.py
        cd $* && screen -L -dm -S experiment python script.py
        touch $@
    
    clean:
        rm -f $(EXPS)
    

  • 当然可以。由于您没有提供太多细节,我将假设:

  • 包含
    script.py
    python脚本的
    experiments
    子目录的任何
    都是一个实验
  • 每次调用
    make
    时,都要重新运行所有实验
  • 以下是一个良好的起点:

    EXPDIRS := $(dir $(shell find . -maxdepth 2 -mindepth 2 -type f -name script.py))
    EXPS    := $(addsuffix .done,$(EXPDIRS))
    
    .PHONY: all $(EXPS)
    
    all: $(EXPS)
    
    $(EXPS): %.done:
        cd $* && screen -L -dm -S experiment python script.py
    
    说明:

    • 使用
      find
      实用程序和
      dir
      make函数设置
      EXPDIRS
      make变量(删除返回路径的文件名部分)。示例:
      /experimentC//experimentA/
    • EXPS
      make变量是通过向
      EXPDIRS
      中的每个单词添加
      .done
      来设置的。示例:
      /experimentC/.done./experimentA/.done
    • EXPS
      中列出的目标加上
      all
      目标被声明为虚假,这意味着即使具有该名称的文件已经存在并且是最新的,make也将重新运行其构建规则
    • all
      取决于
      EXPS
      中列出的所有目标。如果您只运行
      make
      make all
      ,make将运行所有实验的规则,如果您使用
      -j4
      选项调用make,并且您的计算机上有4个内核,则make可能并行运行
    • 最后,静态模式规则
      $(EXPS):…
      告诉make如何构建
      EXPS
      中列出的目标:
      • 转到实验目录(使自动变量扩展为
        %.done
        模式的词干)
      • 运行python脚本
    可能的改进:

  • 如果并且仅当实验尚未运行,或者自上次运行以来,其输入数据发生了更改时,才运行实验。让我们假设输入数据只是python脚本(如果需要,很容易修改)。我们将使用一个名为
    experimentA/.done
    的空文件将一个实验标记为已完成,并记住何时完成。然后,应避免以下无用的实验运行:

    EXPDIRS := $(dir $(shell find . -maxdepth 2 -mindepth 2 -type f -name script.py))
    EXPS    := $(addsuffix .done,$(EXPDIRS))
    
    .PHONY: all
    
    all: $(EXPS)
    
    $(EXPS): %.done: %script.py
        cd $* && screen -L -dm -S experiment python script.py
        touch $@
    
    clean:
        rm -f $(EXPS)
    

  • 屏幕中运行构建有点奇怪。传统上,您只需在后台运行构建,并将输出输出到日志<代码>屏幕
    允许您与作业等交互,如果您想要完全可预测和可复制的构建,这是不可取的。@triplee:我完全同意。在
    屏幕
    中运行构建有点奇怪。传统上,您只需在后台运行构建,并将输出输出到日志<代码>屏幕允许您与作业等交互,如果您想要完全可预测和可复制的构建,这是不可取的。@triplee:我完全同意。