当规则有多个带有 % 字符的目标时,为什么 make 的行为会很奇怪?

当规则有多个带有 % 字符的目标时,为什么 make 的行为会很奇怪?

根据GNU 制作手册

具有多个目标的规则相当于编写许多规则,每个规则都有一个目标,并且除此之外全部相同。相同的配方适用于所有目标,但其效果可能会有所不同,因为您可以使用“$@”将实际目标名称替换为配方。该规则也为所有目标提供了相同的先决条件。

第一个生成文件:
%.in %.out:
    echo BLANK > $@

相应的 bash 会话:

$ ls
Makefile

$ make a.in a.out
echo BLANK > a.in
make: Nothing to be done for 'a.out'.

$ ls
Makefile  a.in

$ make a.out
echo BLANK > a.out

$ ls
Makefile  a.in  a.out

$ make b.in c.out
echo BLANK > b.in
echo BLANK > c.out

$ make d.in d.out
echo BLANK > d.in
make: Nothing to be done for 'd.out'.

$ make e.out e.in
echo BLANK > e.out
make: Nothing to be done for 'e.in'.

$ ls
Makefile  a.in  a.out  b.in  c.out  d.in  e.out
第二个生成文件:
%.in:
    echo BLANK > $@

%.out:
    echo BLANK > $@

相应的 bash 会话:

$ ls
Makefile

$ make a.in a.out
echo BLANK > a.in
echo BLANK > a.out

$ ls
Makefile  a.in  a.out

$ # nice       

那么,问题是:

为什么第一个 Makefile 不<name>.in <same name>.out同时创建目标?为什么它的解释不类似于第二个 Makefile?

答案1

您的规则表明make,单次调用该配方将创建两个都和目标.in.out

https://www.gnu.org/software/make/manual/html_node/Pattern-Intro.html解释了这一点。它说(在倒数第二段):

“模式规则可以有多个目标;但是,每个目标都必须包含 % 字符。模式规则中的多个目标模式始终被视为分组目标(请参阅规则中的多个目标),无论它们是否使用 : 或 &:分隔器。 ”

如果您随后点击链接多目标它解释了分组目标(&:当您有明确的规则时通常使用分隔符)告诉make单次调用配方将创建全部其中,而不是一次只有一个。

所以你的模式规则相当于:

a.in a.out &:
        echo BLANK > $@

...而不是您想要的等价物:

a.in a.out :
        echo BLANK > $@

据我所知,没有办法制定一种像后者一样工作并且一次只创建一个的模式规则。你只需要拥有分离%.in和 的规则%.out

答案2

您不应该在单个规则中拥有多个隐式目标。我不记得是否在任何地方提到过这一点,但这样的规则肯定是不好的做法。这是发生的事情:

$ cat Makefile 
%.in %.out :
        echo BLANK > $@

$ make -d a.in a.out
[... irrelevant output skipped ...]
Updating goal targets....
Considering target file 'a.in'.
 File 'a.in' does not exist.
 Looking for an implicit rule for 'a.in'.
 Trying pattern rule with stem 'a'.
 Found an implicit rule for 'a.in'.
 Finished prerequisites of target file 'a.in'.
Must remake target 'a.in'.
echo BLANK > a.in
Successfully remade target file 'a.in'.
Considering target file 'a.out'.
File 'a.out' was considered already.
make: Nothing to be done for 'a.out'.

注意以下几行:

Considering target file 'a.out'.
File 'a.out' was considered already.

隐式目标在尝试之前并不“存在”,因此规则不会“拆分”为多个规则。当a.in尝试并成功匹配时,所有其他目标都被标记为已尝试。绝大多数时候这不是您想要的。只需写两条规则即可。

相关内容