仅限订单的先决条件在GNU make中无法正常工作?

时间:2014-07-18 09:28:10

标签: makefile gnu-make

我遇到了仅限订单的先决条件问题。这些根本不会首先执行。我是否误解了仅限订单的先决条件的工作方式?

以下制作剧本:

.PHONY: mefirst mefirst2

mefirst:
    @echo "I'm first!"

mefirst2:
    @echo "I'm first too!"

normaltarget: normaltarget2 | mefirst2
    @echo "normaltarget done"

normaltarget2: a b c 
    @echo "normaltarget2 done"

helloworld: normaltarget | mefirst
    @echo "helloworld done"

.DEFAULT_GOAL := go
go: helloworld
    @echo "go done"

a:
    @echo a
b:
    @echo b
c:
    @echo c

...打印出以下内容:

a
b
c
normaltarget2 done
I'm first too!
normaltarget done
I'm first!
helloworld done
go done

...而不是我期望的那样:

I'm first!
I'm first too!
a
b
c
normaltarget2 done
normaltarget done
helloworld done
go done

我做错了什么?

1 个答案:

答案 0 :(得分:39)

  

我是否误解了仅限订单的先决条件的工作方式?

是的,这就是它的样子。

名称“仅限订单”有些令人困惑。 |背后的先决条件被称为“仅订单先决条件”,不是因为它们更改了单个目标的先决条件列表中的配方执行顺序,而是因为它们的唯一目的是在其他目标之前创建某些目标,像一个引导程序。正如下面的用户bobbogo准确解释的那样( - 感谢纠正):如果make决定重建目标的先决条件,它将运行该先决条件的配方。现在,对于普通的先决条件,此更新意味着目标现在已过时,make将必须运行目标的配方。另一方面,对于仅订购的先决条件,make不会将目标标记为需要更新。

例如,请参阅Types of Prerequisites部分,了解在创建该目录中的对象之前应创建目录的用例。

举个例子makefile

a: b
    touch a

b: c
    touch b

c:
    touch c

x: | y 
    touch x

y: | z 
    touch y

z:
    touch z

如您所见,bcab的正常先决条件,而yz是有序的 - 只有xy的先决条件。从干净的石板开始,它们看起来一样:

:~$ make a
touch c
touch b
touch a
:~$ make x
touch z
touch y
touch x
:~$ make a
make: `a' is up to date.
:~$ make x
make: `x' is up to date.

但是,如果我们现在手动“更新”链末尾的先决条件(cz),我们会看到差异:

:~$ touch c
:~$ make a
touch b
touch a
:~$ touch z
:~$ make x
make: `x' is up to date.

这显示了存在的仅限订单的先决条件如何不会使任何目标无效,而与其时间戳无关。删除仅订单目标确实会导致重建(但只重建该丢失的文件):

:~$ rm c
:~$ make a
touch c
touch b
touch a
:~$ rm z
:~$ make x
touch z

说到这里,更改配方运行顺序的正确方法是纠正目标之间的依赖关系。例如,如果您希望在mefirst之前构建a,那么您需要将mefirst作为a的先决条件,例如

a: mefirst
    @echo a

由于您没有详细描述您希望食谱运行的顺序,因此无法为您的问题提供整个解决方案。


你的答案有一个捷径,不是解决方案,但仍然很有趣。虽然没有记录,但似乎单个目标的先决条件按它们出现的顺序进行处理。 |符号不会改变这一点。在您的简单情况下,您可以利用它来实现您正在寻找的输出:

normaltarget: mefirst2 normaltarget2
    @echo "normaltarget done"

helloworld: mefirst normaltarget
    @echo "helloworld done"

但是,正如您自己所指出的,只要-j标志用于并行运行配方,这个“解决方案”就会中断。另外,正如用户bobbogo指出的那样,依赖这种排序机制是不好的做法。引入新的依赖项可能会干扰排序。所以不要这样做: - )