2

我有这个 Makefile(它只是一个例子,没有实际意义)

all: foobar.intermediate foobar.a

define RECIPE_THROUGH_INTERMEDIATE
    cp $< $@.intermediate
    mv $@.intermediate $@
endef 

define RECIPE_DIRECT
    cp $< $@
endef

%.a: %.c
    $(RECIPE_THROUGH_INTERMEDIATE)

%.a: %.intermediate
    $(RECIPE_DIRECT)

%.intermediate: %.c
    $(RECIPE_DIRECT)

我希望 Make 尽可能“快”并像这样更新:

>make foobar.a

通过中间执行配方,从foobar.cfoobar.a

>make

foobar.c直接从to执行配方foobar.intermediate

foobar.intermediate直接从to执行配方foobar.a

换句话说,这是一种常见的情况,foobar.a从源 ( ) 生成目标 ( foobar.c) 需要在内部通过中间体,这比单独从源到中间体或从中间体到目标需要更多时间,但是当您明确(不是在内部)通过中间时,它所花费的时间比这两者的总和要少。

当然 Make 不知道食谱需要多长时间。

所以我想提示 Make what the correct path to take:

  • 当我只想要目标时,将直接配方从源带到目标
  • 当我既想要目标又想要中间时,先做中间,然后再做目标。

我有 GNU Make 至少 3.82,但我无法控制模式词干的长度 - 这必须适用于任何长度的词干,包括,就像在这个例子中一样,所有词干的长度都相同。

有没有办法更改上述 Makefile 以实现所需的行为?

4

3 回答 3

0

我无法使用 GNU Make 3.81 重现该行为。

显然,这不是真正的 Makefile,因为它调用了一个from不存在的命令。我通过用#. 在我的目录中,我只有 makefile 和一个foobar.c.

$ make foobar.a
#from .c to .a

$ make foobar.b
#from .c to .b

只有当我注释掉%.a : %.c模式规则时,我才会得到这个:

$ make foobar.a
#from .c to .b
#from .b to .a

所以还有其他事情发生。也许这是 3.82 中的回归,或者您的实际 makefile 触发了一些错误,或者在我的情况下可能是侥幸选择了短路径。

很明显,当您请求foobar.a制作时,Make 应该搜索其模式规则以推断出foobar.a可以制作的先决条件。这应该是广度优先搜索:它应该%.a: %.c在模式规则中遇到,看看,啊哈,我们有一个foobar.c文件,走吧!只有当第一轮失败时,图闭包才应该被扩展以包括先决条件一个步骤被删除等等。这甚至是一个巧妙优化的问题;只是图遍历顺序的问题!

于 2013-10-29T05:30:30.690 回答
0

您所期望的不满足 Makefile 规则,如果您仔细查看您的代码,那么您可以观察到以下内容

all: foobar.b foobar.a

%.a: %.c                  // .a depends on .c
       from .c to .a

%.a: %.b                 // .a depends on .b
       from .b to .a

%.b: %.c                 // .b depends on .c
       from .c to .b

所以这里的 .a 取决于 .b 和 .c .. 因为 .a 和 .b 都取决于 .c 而 .a 取决于 .b 第一条规则from .c to .a由 make 优化。from .c to .b然后你就会明白from .b to .a,makefile 无法找到最短路径,因为 makefile 想要做的就是确保满足所有依赖项标准。

于 2013-10-29T04:47:21.927 回答
0

在 Gnu Make 中明确不允许有两种不同的方式来构建相同的目标:

所有规则中提到的所有先决条件都合并到目标的先决条件列表中。如果目标早于任何规则的任何先决条件,则执行配方。

一个文件只能执行一个配方。如果多个规则为同一个文件提供了一个配方,make 使用最后一个给定的规则并打印一条错误消息。

基于依赖图上的一些任意度量来选择多个配方的概念不太可能得到支持。因此,为了回答您提出的问题,首先需要更改 Make 以支持多种替代方案。

如果您想提供一个“提示”,说明应该首选两种策略中的哪一种,如果提供了提示,您可能必须使用条件 likeifeq ... else ... endif来定义您想要的行为,如果没有,您可能需要定义想要的行为。在构建依赖图时,目标只有一个配方。

于 2017-12-01T21:37:45.887 回答