使用“-j”选项进行制作:Make如何知道何时在依赖图中前进?

时间:2017-11-23 14:32:23

标签: makefile parallel-processing gnu-make

This post描述了make如何以正确的顺序构建目标。我想特别了解有关并行性的更多信息。从帖子:

  

在正常的非并行操作下,make将只选择一个   定位每次迭代并构建它。当它是平行的时候它会抓住   尽可能多的无依赖目标并且并行构建它们,   最多允许同时工作的数量。

我的照片:

  1. 查找所有没有遗漏依赖关系的目标。
  2. 构建所有这些目标。
  3. 等待所有并行工作者完成(同步)。
  4. 返回步骤(1)。
  5. 但这是错误的:make -j以某种方式知道何时在没有步骤(3)的情况下继续前进。当且仅当所有依赖项完成且并行工作程序可用时,新目标才会开始。怎么样?

    例如,请考虑图表:

    A -> C
    B -> D
    

    在我的第一次猜测中,make -j2会等待 AB之前完成 {{1} }或C开始。但是,如果D完成但C仍在进行中,它似乎知道可以继续A

1 个答案:

答案 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从头开始。