首页 > 解决方案 > Make:是否可以从模式匹配中构建依赖关系?

问题描述

这里的目标是动态地适应和处理results-0, results-1, ...,results-n出现results-*在 makefile 的目录中,我用一个 cron 作业调用 make 。

make我正在使用的是通过gnu-make vers. 4.3brew 安装在 mac 上的。


我编写了以下代表我的实际问题的 MVP,并且它有效。请注意,在我的实际问题中,没有完整的通配符链,基本问题由被注释掉和未注释的区域表示:

sources:=result-0/foo.txt result-0/bar.txt result-1/foo.txt result-1/bar.txt
results:=result-0.txt result-1.txt

result-%/:
  @-mkdir $@

result-0/%.txt: result-0
  @touch $@

result-1/%.txt: result-1
  @touch $@


#.SECONDEXPANSION:
#result-%.txt: $$(filter $$(basename $$@)/%,$$(sources))
# @echo $^ args of: $@
# @touch $@

.SECONDEXPANSION:
result-0.txt: $$(filter $$(basename $$@)/%,$$(sources))
  @echo $^ args of: $@
  @touch $@

.SECONDEXPANSION:
result-1.txt: $$(filter $$(basename $$@)/%,$$(sources))
  @echo $^ args of: $@
  @touch $@

all: $(results)

我使用以下命令构建它:

mkdir result-0
touch result-0/foo.txt
touch result-0/bar.txt
echo result-0/foo.txt result-0/bar.txt args of: result-0.txt
touch result-0.txt
mkdir result-1
touch result-1/foo.txt
touch result-1/bar.txt
echo result-1/foo.txt result-1/bar.txt args of: result-1.txt
touch result-1.txt
rm result-1

这代表了成功的第一次构建。


但是,当我对 abstract cross 进行以下更改时result-[0...n],系统会中断:

sources:=result-0/foo.txt result-0/bar.txt result-1/foo.txt result-1/bar.txt
results:=result-0.txt result-1.txt

result-%/:
  @-mkdir $@

result-0/%.txt: result-0
  @touch $@

result-1/%.txt: result-1
  @touch $@

.SECONDEXPANSION:
result-%.txt: $$(filter $$(basename $$@)/%,$$(sources))
  @echo $^ args of: $@
  @touch $@

all: $(results)

系统崩溃:

$ make all -Bn
mkdir result-0.txt
mkdir result-1.txt

已经注意到我可以简单地进行以下更改:

# instead of 
result-%.txt: $$(filter $$(basename $$@)/%,$$(sources))

# I could write
$(results): $$(filter $$(basename $$@)/%,$$(sources))

这是我所知道的,而且我在我身边进行这项工作是零麻烦(我有工作代码)。这不是我要问的问题。我不是在问“我该如何调试”。

问:“为什么下面的规则表达式没有填充第二个扩展中的先决条件?”

.SECONDEXPANSION:
results-%:  $$(filter $$(basename $$@)/%,$$(sources))

围绕这个问题的一切都不是为了激发这个问题,而是为了证明这个问题。如果有另一种方法可以“使这个例子工作”,那就超出了范围。


可以用make做到这一点吗?这是您会在 Mac 上看到的奇怪问题之一吗?

而且,如果现在的问题似乎是result-0/%.txt在链上进一步抓住模式匹配,那实际上并不是我要处理的。我开发了一个没有文件的复制粘贴演示,如果我无意中添加了此模式扩展可能失败的另一个原因,那么我在我的问题演示中搞砸了。因此,如果这是问题所在,我可以重新处理这个问题。

标签: makefilegnu-make

解决方案


问:“为什么下面的规则表达式没有填充第二个扩展中的先决条件?”

.SECONDEXPANSION:
results-%:  $$(filter $$(basename $$@)/%,$$(sources))

奇怪的是,你的麻烦 makefile 像我认为你在 GNUmake版本 4.0 上所期望的那样工作:

> make --version
GNU Make 4.0
Built for x86_64-unknown-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
>
> make -Bn
echo  args of: result-0.txt
touch result-0.txt
echo  args of: result-1.txt
touch result-1.txt

我查看了版本 4.1、4.2 和 4.3 的发行说明,并没有看到任何我认为描述此更改的内容。不过,我想我可以解释 4.3 版中发生了什么。

第一次展开产生这条规则:

results-%:  $(filter $(basename $@)/%,$(sources))

您期望make将其与诸如 的目标相匹配results-0,扩大$@该分配的范围,然后评估该filter功能。但是%函数参数中的那个呢?

您依赖%先决条件列表中的 逐字传递到filter,但是在make评估模式规则时,它会用目标的匹配词干代替%先决条件列表中的出现。在这种情况下,它看起来像是make在评估函数调用之前执行此操作,因此生成的先决条件列表与现有或可构建目标不匹配。结果,该规则被拒绝。

这基本上是执行顺序的差异。如果在执行词干替换之前扩展函数调用,则会获得您想要的结果,但如果先执行词干替换,则您的规则无法按预期工作。我没有找到明确记录这个具体细节,但是我对模式规则的一般行为的阅读使我期望首先执行词干替换(因此我判断 GNU make4.0 在这方面存在缺陷)。

无论如何,这似乎与第二次扩展没有直接关系。我希望类似的执行顺序效果适用于任何试图%在先决条件列表中使用 a 作为文字字符的模式规则。


推荐阅读