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