55

自从我了解 -j 后,我就愉快地使用了 -j8。前几天我正在编译一个 atlas 安装,但 make 失败了。最终,我将其归结为乱序制作的东西——一旦我回到单线程制作,它就可以正常工作。这让我很紧张。在编写自己的 make 文件时需要注意哪些条件以避免使用 make -j 做一些意想不到的事情?

4

6 回答 6

47

我认为 make -j 会尊重您在 Makefile 中指定的依赖项;即,如果您指定 objA 依赖于 objB 和 objC,那么在 objB 和 objC 完成之前,make 不会开始处理 objA。

很可能您的 Makefile 没有足够严格地指定必要的操作顺序,幸运的是它恰好在单线程情况下为您工作。

于 2009-10-14T04:38:11.103 回答
26

简而言之 - 确保您的依赖项正确且完整。

如果您使用的是单线程 make,那么您可能会盲目地忽略目标之间的隐式依赖关系。使用并行 make 时,您不能依赖隐式依赖项。它们都应该明确。这可能是最常见的陷阱。特别是如果使用 .phony 目标作为依赖项。

这个链接是关于并行制作的一些问题的一个很好的入门。

于 2009-10-14T04:45:49.497 回答
11

这是我开始使用并行构建时遇到的一个问题的示例。我有一个名为“新鲜”的目标,我用它从头开始重建目标(“新鲜”构建)。过去,我通过简单地指示“干净”然后“构建”作为依赖项来编码“新鲜”目标。

build: ## builds the default target
clean: ## removes generated files
fresh: clean build ## works for -j1 but fails for -j2

在我开始使用并行构建之前效果很好,但是对于并行构建,它会尝试同时进行“清理”和“构建”。所以为了保证正确的操作顺序,我将“新鲜”的定义修改如下。

fresh:
    $(MAKE) clean
    $(MAKE) build

这基本上只是正确指定依赖关系的问题。诀窍是并行构建比单线程构建更严格。我的示例演示了给定目标的依赖项列表不一定指示执行顺序。

于 2010-04-10T17:42:25.133 回答
7

如果你有一个递归的make,事情就很容易坏掉。如果您不进行递归 make,那么只要您的依赖项正确且完整,您就不会遇到任何问题(除了 make 中的错误)。请参阅Recursive Make Considered Harmful以更全面地描述递归 make 的问题。

于 2009-10-14T05:01:15.627 回答
3

最好有一个自动化测试来测试所有 make 文件的 -j 选项。即使是最优秀的开发人员也会在 make 的 -j 选项上遇到问题。最常见的问题是最简单的。

myrule: subrule1 subrule2
     echo done

subrule1:
     echo hello

subrule2:
     echo world

在正常的 make 中,你会看到 hello -> world -> done。使用 make -j 4,你可能会看到 world -> hello -> done

我看到这种情况发生最多的地方是创建输出目录。例如:

build: $(DIRS) $(OBJECTS)
     echo done

$(DIRS):
     -@mkdir -p $@

$(OBJECTS):
     $(CC) ...
于 2013-08-24T22:20:47.040 回答
1

只是想我会添加到子集的答案,因为它没有清楚地显示效果。但是添加一些睡眠命令可以。好吧,它适用于Linux。

然后运行 ​​make 显示差异:

  • 制作
  • 使-j4

all: toprule1

toprule1: botrule2 subrule1 subrule2
    @echo toprule 1 start
    @sleep 0.01
    @echo toprule 1 done

subrule1: botrule1
    @echo subrule 1 start
    @sleep 0.08
    @echo subrule 1 done

subrule2: botrule1
    @echo subrule 2 start
    @sleep 0.05
    @echo subrule 2 done

botrule1:
    @echo botrule 1 start
    @sleep 0.20
    @echo "botrule 1 done (good prerequiste in sub)"

botrule2:
    @echo "botrule 2 start"
    @sleep 0.30
    @echo "botrule 2 done (bad prerequiste in top)"
于 2015-11-06T08:26:57.437 回答