Makefile 在不同的目录中创建相同的工作流

Makefile 在不同的目录中创建相同的工作流,makefile,Makefile,我正在使用make自动化一些数据分析。我有几个目录,每个目录都包含不同的数据实现,其中包括几个表示给定时间数据状态的文件,如下所示: ├── a │ ├── time_01.dat │ ├── time_02.dat │ ├── time_03.dat │ └── ... ├── b │ ├── time_01.dat │ └── ... ├── c │ ├── time_01.dat │ └── ... ├── ... 每个目录中的数据文件数量未知,可以随时添

我正在使用make自动化一些数据分析。我有几个目录,每个目录都包含不同的数据实现,其中包括几个表示给定时间数据状态的文件,如下所示:

├── a
│   ├── time_01.dat
│   ├── time_02.dat
│   ├── time_03.dat
│   └── ...
├── b
│   ├── time_01.dat
│   └── ...
├── c
│   ├── time_01.dat
│   └── ...
├── ...
每个目录中的数据文件数量未知,可以随时添加更多数据文件。这些文件在每个目录中都具有相同的命名约定

我想使用make在每个目录中运行完全相同的一组配方(分别统一地分析每个数据集)。特别是,有一个脚本应该在添加新数据文件时运行,并为目录中的每个数据文件创建一个输出文件(
analysis\u time\u XX.txt
)。此脚本不会更新以前创建的任何文件,但会创建所有缺少的文件。不幸的是,重构这个脚本是不可能的

因此,我有一个创建多个目标的配方,但它必须为每个目录分别运行。我发现用一个配方(例如)创建多个目标的解决方案在我的情况下不起作用,因为我需要一条规则来分别为不同目录中的多组文件执行此操作

这些中间文件本身是需要的(因为它们有助于验证收集的数据),但也用于创建数据集之间的最终比较图

我当前的设置是功能和
的丑陋组合。SECONDEXPANSION

dirs = a b c

datafiles = $(foreach dir,$(dirs),$(wildcard $(dir)/*.dat))

df_to_analysis = $(subst .dat,.txt,$(subst time_,analysis_time_,$(1)))
analysis_to_df = $(subst .txt,.dat,$(subst analysis_time_,time_,$(1)))

analysis_files = $(foreach df,$(datafiles),$(call df_to_analysis,$(df)))

all: final_analysis_plot.png

.SECONDEXPANSION:
$(analysis_files): %: $$(call analysis_to_df,%)
    python script.py $(dir $@)

final_analysis_plot.png: $(analysis_files)
    python make_plot.py $(analysis_files)
请注意,
script.py
在给定目录中创建所有
analysis\u time\u XX.txt
文件。此设置的缺陷是make不知道第一个脚本生成所有目标,因此在使用parallel make时不必要地运行。对于我的应用程序来说,并行生成是必要的,因为这些脚本有很长的运行时间,并行化可以节省很多时间,因为设置是“令人尴尬的并行”


有没有一种优雅的方法来解决这个问题?或者甚至是一种优雅的方式来清理我现在的代码?我在这里展示了一个简单的示例,它已经需要很好的设置,而对几个不同的脚本执行此操作很快就会变得笨拙。

我认为,在您的情况下,没有必要使用
.txt
文件。如果
script.py
更好,并且每个文件都可以工作,那么编写单个文件规则将是有价值的。在这种情况下,我们需要为每个目录
.done
文件引入一个中间层

DATA_DIRS := a b c
# A directory/.done.analysis file means that `script.py` was run here.
DONE_FILES := $(DATA_DIRS:%=%/*.done.analysis)

# .done.analysis depends on all the source data files.
# When a .dat file is added or changes, it will be newer than
# a .done.analysis file; and the analysis would be re-run.
$(DONE_FILES): %/.done.analysis: $(wildcard %/*.dat)
    python script.py $(@D)

final_analysis_plot.png: $(DONE_FILES)
    python make_plot.py $(wildcard $(DATA_DIRS)/analysis_time_*.txt)