在父目录上编写具有先决条件的递归make recipe

时间:2016-03-14 18:51:55

标签: recursion makefile metaprogramming gnu-make

我正在尝试编写递归制作配方。在此配方中,每个目标都依赖于父目录中具有相同名称的文件。最小(非工作)示例:

foo/.dirstamp:
  mkdir $(dir $@)
  touch $@

.SECONDEXPANSION:
%/.dirstamp: $$(dir $$*).dirstamp
  mkdir $(dir $@)
  touch $@

通过这个例子,我希望make foo/bar/qux/lol/.dirstamp生成整个目录树(如果它不存在),触摸所有.dirstamp文件。但是,它不起作用:

$ ls # note that there is nothing, make is meant to create the dir tree
Makefile
$ make --debug=v foo/bar/qux/lol/.dirstamp
GNU Make 4.0
[...]
Reading makefiles...
Reading makefile 'Makefile'...
Updating goal targets....
Considering target file 'foo/bar/qux/lol/.dirstamp'.
 File 'foo/bar/qux/lol/.dirstamp' does not exist.
 Finished prerequisites of target file 'foo/bar/qux/lol/.dirstamp'.
Must remake target 'foo/bar/qux/lol/.dirstamp'.
make: *** No rule to make target 'foo/bar/qux/lol/.dirstamp'.  Stop.

只要递归配方只需要扩展两次就可以正常工作,例如,make foo/bar/.dirstamp工作正常。

这对于任意数量的级别如何工作?如何处理目标和先决条件名称的递归扩展?

注意:我的真正问题是我的食谱的先决条件是在根目录中 目录与目标不同,所以我使用上面的配方来复制目录树。我知道mkdir -p 似乎在GNU系统中运行良好。我仍然有兴趣了解如何解决任意级别的递归问题。不再有效,因为部分团队正在使用Mac并将此目录安装在smb上。

有关实际问题的更多详细信息:先决条件位于data/x/y/z,目标进入results/x/y/z。但是,results目录树不存在,需要根据需要创建。为了解决这个问题,我将父目录的创建设置为仅限订单的先决条件(通过上面最小例子中的.dirstamp文件)。

  • 无法将data复制到results,即数TB的数据;
  • 无法在data中创建只读的目标;
  • 不能使用mkdir -p因为results目录不是本地的,挂载在smb上,而其他目录可能使用非GNU系统;

1 个答案:

答案 0 :(得分:2)

在@EtanReisner提出问题后提示:

  

make不会多次应用规则。这是内置(故意)限制。如果不通过手动递归或手动构建目标集并使用静态模式规则(可能实际可能或可能不实际工作,我不确定),那么您无法做到这一点。

我编写了这个解决方案:

RESULT_DIRS := $(patsubst data/%, results/%, $(shell find data/* -type d -print))
DIRSTAMPS := $(addsuffix /.dirstamp, $(RESULT_DIRS))

results/.dirstamp:
    mkdir $(dir $@)
    touch $@

.SECONDEXPANSION:
$(DIRSTAMPS): $$(dir $$(patsubst %/.dirstamp, %, $$@)).dirstamp
    mkdir $(dir $@)
    touch $@

它将复制data中的results目录树,因为需要dirstamp文件。通过将它们作为其他配方的先决条件来要求它们(注意|使它们成为仅限订单的先决条件):

results/%/foo.analysis: data/%/foo.data | results/%/.dirstamp
    $(SOME_ANALYSIS_PROGRAM) $^ > $@