如何强制Make从源头到目标采取“最短路径”?

时间:2013-10-22 21:46:09

标签: makefile gnu-make

我有这个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执行配方到foobar.intermediate

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

换句话说,这是一种常见的情况,从源(foobar.a)制作目标(foobar.c)需要内部通过中间体,这需要花费更多的时间,而不是从单独从源到中间,或从中间到目标,但是当你明确地(不是在内部)通过中间体时,它比这两个组合花费的时间更少。

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

所以我想提示做出正确的路径:

  • 当我只想要目标时,从源头到目标
  • 采取直接配方
  • 当我想要目标和中间时,从中创建中间,然后是目标。

我的GNU Make至少为3.82,但我无法控制花纹茎的长度 - 这必须适用于任何长度的茎,包括像本例中所有茎长度相同的茎。

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

3 个答案:

答案 0 :(得分: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想要做的就是确保满足所有的依赖条件。

答案 1 :(得分: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文件,我们走吧!只有当第一轮失败时才应该扩展图形闭包以包括一步删除的先决条件,依此类推。这甚至是一个聪明的优化问题;只是图表遍历顺序的问题!

答案 2 :(得分:0)

有两种不同的方法来构建相同的目标is explicitly not allowed in Gnu Make

  

所有规则中提到的所有先决条件都合并为一个   目标的先决条件列表。如果目标比任何目标旧   任何规则的先决条件,都会执行配方。

     

只能为文件执行一个配方。如果超过   一个规则给出了同一个文件的配方,make使用最后一个   给出并打印错误信息。

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

如果你想提供&#34;提示&#34;至于两种策略中哪一种应该是首选的,你可能必须使用像ifeq ... else ... endif这样的条件来定义你提供提示时所需的行为,如果没有,则定义你想要的行为。在构建依赖图时,目标只有一个配方。