GNU make将以什么顺序进行先决条件?

时间:2009-10-30 01:00:50

标签: dependencies makefile gnu

假设我们有规则:

a: b c d e

bcde相互独立。

是否定义了bcde的顺序?通常情况下,它们会按顺序bcde制作,但有时可能会发生,订单会有所不同吗?

7 个答案:

答案 0 :(得分:25)

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

答案 1 :(得分:13)

  

GNU make将以什么顺序进行先决条件?

这取决于先决条件的类型。根据{{​​3}},第4.2节:

  

实际上有两种不同类型的先决条件可供理解   GNU make:正常的先决条件,如前面所述   部分和仅限订单的先决条件。正常的先决条件是两个   陈述:首先,它强加了一个食谱的订单   invoked:目标的所有先决条件的配方将是   在运行目标的配方之前完成。其次,它强加   依赖关系:如果任何先决条件比...更新   目标,然后目标被认为是过时的,必须重建。

     

通常情况下,这正是您想要的:如果目标的先决条件是   更新后,目标也应该更新。

     

但是,有时你会想要强加一个   要调用的规则的特定顺序没有强制执行   如果执行其中一个规则,则更新目标。在这种情况下,   您想要定义仅订单先决条件。订单只   可以通过在管道中放置管道符号(|)来指定先决条件   先决条件列表:管道符号左侧的任何先决条件   是正常的;右边的任何先决条件都是仅限订单:

   targets: normal-prerequisites | order-only-prerequisites
     

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

     

考虑一个示例,将目标放在一个单独的位置   目录,并且在运行make之前该目录可能不存在。在   在这种情况下,您希望在任何之前创建目录   目标被放入其中,但因为目录上的时间戳   我们当然会在添加,删除或重命名文件时进行更改   不想在目录的时候重建所有目标   时间戳更改。管理此问题的一种方法是仅订购   先决条件:使目录成为所有目录的必备先决条件   目标:

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)
     

现在,如果需要,将运行创建'objdir'目录的规则,   在任何'.o'构建之前,但不会构建'.o'因为   'objdir'目录时间戳已更改。

答案 2 :(得分:6)

顺序中,根据您提供的规则。对于您的特定示例,这可能意味着许多不同的(4!= 24,来自内存)订单中的任何一个。

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

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

答案 3 :(得分:5)

当然,如果我使用make -j a,它们可能会同时构建(取决于bcd还是{{1}反过来有其他/相互依赖的依赖)。

答案 4 :(得分:4)

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

  • 需要做a topological sort,因为依赖关系可能有额外的和多个关系。由于图中的节点可能在不同级别多次相关,因此排序可能非常复杂
  • 一般来说排序算法不是stable,即使是基于密钥的简单排序

答案 5 :(得分:2)

如果订单很重要,您可以使用recursive 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)以反对这样做的参数。

答案 6 :(得分:1)

我将添加它以供将来参考。尽管在处理先决条件时,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一起使用的方式来重写它,但我认为我会分享有关先决条件排序的小知识。