This post描述了make
如何以正确的顺序构建目标。我想特别了解有关并行性的更多信息。从帖子:
在正常的非并行操作下,make将只选择一个 定位每次迭代并构建它。当它是平行的时候它会抓住 尽可能多的无依赖目标并且并行构建它们, 最多允许同时工作的数量。
我的照片:
但这是错误的:make -j
以某种方式知道何时在没有步骤(3)的情况下继续前进。当且仅当所有依赖项完成且并行工作程序可用时,新目标才会开始。怎么样?
例如,请考虑图表:
A -> C
B -> D
在我的第一次猜测中,make -j2
会等待 A
和B
在之前完成 {{1} }或C
开始。但是,如果D
完成但C
仍在进行中,它似乎知道可以继续A
。
答案 0 :(得分:3)
内部make创建一个有向无环图(DAG),其中每个节点都是目标,每个边都是先决条件关系。
选择起始节点作为(a)命令行上请求的目标,或(b)makefile中定义的第一个目标。
从那里开始,图形将以深度为先,从左到右。所以给出这个makefile:
A: B C
B: D E
C: F
E: G
make会像这样走DAG:
A -> B -> D -> E -> G -> C -> F
因为make首先构建叶节点,所以配方的实际调用(假设所有节点都已过期)将按以下顺序排列:
D, G, E, B, F, C, A
您可以使用这个简单的makefile轻松证明这一点:
A: B C
B: D E
C: F
E: G
A B C D E F G: ; @echo $@
那么,现在并行性如何进入呢?
在并行构建中,make会创建相同的DAG并遵循相同的算法来遍历它。最大的区别是当make决定构建目标时会发生什么。在非并行构建中,make将调用该配方并等待它结束,然后转到下一个。
在并行构建中(假设不是无限的作业)make将首先获得一个jobserver令牌。如果它不能它会等待一个人睡觉。如果可以,它会调用该目标的配方,但不是等待,而是返回其算法并转到DAG中的下一个节点,该节点将是兄弟节点。如果没有兄弟,我们将返回到父级,看看 是否有兄弟(make无法构建父级,因为孩子还没有完成)来构建。等等通过DAG。如果它到达DAG的末尾而不是一切都已完成,那么make从头开始。