【问题标题】:writing a recursive make recipe with prerequisite on parent directory在父目录上编写具有先决条件的递归制作配方
【发布时间】:2016-03-16 00:42:38
【问题描述】:

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

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系统;

【问题讨论】:

  • 你愿意使用递归 Make 吗? [邪恶音乐]
  • make 不会多次应用规则。这是一个内置的(有意的)限制。如果不通过手动递归或手动构建目标集并使用静态模式规则(我不确定这可能会或可能不会真正起作用)来解决这个问题,您对此无能为力。
  • @Beta 这将如何工作?请注意,我使用它来创建目录树,这些目录不存在,因此不能有 Makefile。
  • @EtanReisner 所以我需要首先创建所有可能的 dirstamp 文件的列表,而不是希望它们是从 N 级递归中推导出来的?嗯……我会试试的。
  • 线程安全的工具或函数调用与同时使用该工具或函数的多个进程没有任何关系。这些是完全不相关的概念。您在 OS X 上从mkdir -p 得到什么错误?这让我觉得很奇怪(但这是一个不同的问题,所以我们可以不用管它)。

标签: recursion makefile metaprogramming gnu-make


【解决方案1】:

在@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 $@

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    相关资源
    最近更新 更多