34

假设我们有规则:

a: b c d e

b, c,de相互独立。

b, c, d,的制作顺序是否已e定义?似乎它们通常会按顺序制作bc, d, e,但有时可能会发生顺序不同的情况吗?

4

7 回答 7

31

不,订单未定义。这就是使用声明性面向依赖编程的重点:计算机可以选择最佳评估顺序,或者实际上,甚至可以同时评估它们。

于 2009-10-30T02:00:05.253 回答
14

GNU make 将按什么顺序创建先决条件?

这取决于先决条件的类型。根据GNU Make Manual第 4.2 节:

GNU make 实际上有两种不同类型的先决条件:正常的先决条件,如上一节中描述的,以及仅订购的先决条件。一个正常的先决条件有两个陈述:首先,它规定了调用配方的顺序:目标的所有先决条件的配方将在目标的配方运行之前完成。其次,它强加了一种依赖关系:如果任何先决条件比目标更新,那么目标被认为是过时的,必须重新构建。

通常,这正是您想要的:如果更新了目标的先决条件,那么也应该更新目标。

但是,有时您会遇到这样的情况,即您希望对要调用的规则施加特定的顺序,而不是在执行这些规则之一时强制更新目标。在这种情况下,您想要定义仅订单的先决条件。可以通过在先决条件列表中放置管道符号 (|) 来指定仅订单先决条件:管道符号左侧的任何先决条件都是正常的;右侧的任何先决条件都是仅订购的:

   targets: normal-prerequisites | order-only-prerequisites

正常的先决条件部分当然可能是空的。此外,您仍然可以为同一目标声明多行先决条件:它们被适当地附加(正常先决条件附加到正常先决条件列表中;仅订单先决条件附加到仅订单先决条件列表中)。请注意,如果您将同一文件声明为普通和仅订单前提条件,则普通前提条件优先(因为它们具有仅订单前提条件的行为的严格超集)。

Consider an example where your targets are to be placed in a separate directory, and that directory might not exist before make is run. In this situation, you want the directory to be created before any targets are placed into it but, because the timestamps on directories change whenever a file is added, removed, or renamed, we certainly don’t want to rebuild all the targets whenever the directory’s timestamp changes. One way to manage this is with order-only prerequisites: make the directory an order-only prerequisite on all the targets:

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir $(OBJDIR)

Now the rule to create the ‘objdir’ directory will be run, if needed, before any ‘.o’ is built, but no ‘.o’ will be built because the ‘objdir’ directory timestamp changed.

于 2014-07-27T13:36:38.487 回答
7

根据您提供的规则,以正确的顺序排列对于您的特定示例,这可能意味着许多不同(4!= 24,根据记忆)订单中的任何一个。

make只要尊重依赖关系,所有程序都可以自由选择他们喜欢的顺序。如果您的示例中有其他规则,例如c: b, thenc将在之前制定b(但事实并非如此,正如您所指出的那样)。

如果您需要依赖特定订单,则需要更多规则来执行它。否则make可以为所欲为。GNU Make的文档仅说明如何处理规则,而不是处理规则中的依赖项的顺序。最合乎逻辑的顺序(无论如何对我来说)是它们的列出顺序,但这并不能保证。

于 2009-10-30T01:40:19.613 回答
4

当然,如果我使用make -j a,它们可能会同时构建(取决于bcd或是否e有其他/相互关联的依赖项)。

于 2009-10-30T01:03:04.683 回答
4

不,当没有依赖关系时,您不能指望排序。

  • make 需要做一个拓扑排序,因为依赖关系可能有额外的和多重的关系。make 所做的排序可能非常复杂,因为图中的节点可能在不同级别多次相关
  • 一般来说,排序算法不是自然稳定的,即使是简单的基于键的排序
于 2009-10-30T02:16:01.657 回答
3

我将添加此内容以供将来参考。虽然 GNU Make 在处理先决条件时可能没有定义特定的顺序,但 POSIX make 要求按照指定的顺序处理它们,即从左到右。大多数实现都遵循此规则。POSIX 甚至给出了一个示例,其中不遵循此规则的 make 实现可能会破坏程序的构建过程:

foo: y.tab.o lex.o main.o
    $(CC) $(CFLAGS) -o $@ t.tab.o lex.o main.o

lex.o 最终使用了不正确的 y.tab.h。虽然这可以用 GNU Make 的方式重写,但我想我会分享这个关于先决条件排序的花絮。

于 2020-02-02T10:09:43.727 回答
2

如果顺序很重要,您可以使用递归 make有选择地强制执行它。例如,假设您不关心 b 和 c 的生成顺序,只要它们都在 d 之前生成并且 d 在 e 之前生成。然后你可以把你的规则写成:

a: b c
    $(MAKE) d
    $(MAKE) e
    # Additional steps to make a

请注意,根据 d 和 e 的复杂性,这种方法可能会对您的构建时间造成不利影响:请参阅Recursive Make Considered Harmful (PDF) 了解反对这样做的论据。

于 2017-10-02T00:54:56.087 回答