代码之家  ›  专栏  ›  技术社区  ›  landau

使用“-j”选项生成:Make如何知道何时在依存关系图中前进?

  •  0
  • landau  · 技术社区  · 7 年前

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

    在正常的非并行操作下,make只需选取一个 针对每个迭代并构建它。当它平行时,它会抓取 尽可能多地减少依赖性目标,并并行构建它们, 最多允许同时作业的数量。

    我的图片:

    1. 查找所有不缺少依赖项的目标。
    2. 建立所有这些目标。
    3. 等待所有并行工作进程完成(同步)。
    4. 返回步骤(1)。

    但这是错误的: make -j

    例如,考虑图形:

    A -> C
    B -> D
    

    在我的第一次猜测中, make -j2 将等待 二者都 A B 在之前完成 任何一个 C D 开始。然而,它似乎知道它可以继续 C 如果 A. 完成,但 B 仍在进行中。

    1 回复  |  直到 7 年前
        1
  •  3
  •   MadScientist    7 年前

    内部make创建一个有向无环图(DAG),其中每个节点都是目标,每个边都是先决条件关系。

    Make选择一个起始节点作为(a)命令行上请求的目标,或(b)makefile中定义的第一个目标。

    从那里make将首先遍历图形深度,从左到右。因此,给定这个生成文件:

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