假设我们有规则:
a: b c d e
和b
,c
,d
和e
相互独立。
是否定义了b
,c
,d
,e
的顺序?通常情况下,它们会按顺序b
,c
,d
,e
制作,但有时可能会发生,订单会有所不同吗?
答案 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
,它们可能会同时构建(取决于b
,c
,d
还是{{1}反过来有其他/相互依赖的依赖)。
答案 4 :(得分:4)
不,当没有依赖关系时,你不能指望排序。
答案 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一起使用的方式来重写它,但我认为我会分享有关先决条件排序的小知识。