如何使用GNU Make优化子目录的并行构建?

时间:2015-03-21 13:48:38

标签: makefile gnu-parallel

我正在一个大型项目中工作,我们有几个子目录,我们从中构建libs / archives。大多数子目录没有相互依赖,但有些子目录。

例如,这是一般形式:

TARG1=targ1/
TARG2=targ2/
TARG3=targ3/

SUBDIRS= lib1\
         lib2\
         lib3\
         ...

.PHONY: $(TARG1) $(TARG2) $(TARG3)

构建顺序必须如下:TARG1 - > TARG2-> TARG3 - > SUBDIRS

我们已经构建了这样的目标:

build_libs:
      $(MAKE) subdirs

subdirs: $(SUBDIRS)

$(SUBDIRS): $(TARG3)
      $(MAKE) -C $@

$(TARG3): $(TARG2)
      $(MAKE) -C $@

$(TARG2): $(TARG1)
      $(MAKE) -C $@

$(TARG1):
      $(MAKE) -C $@

现在我认为,这将允许最大程度的并行化,因为在构建目标(TARG1 - > TARG3)时,Make可以同时构建SUBDIRS中的所有库。但也许有更好的方法来优化这个?我看到,这种方法的缺点是我们得到了一个更大的Makefile,因为我们必须为每个与另一个目标具有依赖性的目标指定一个配方。有没有办法避免这种情况,仍然允许完全并行化?

另一种方法是建立这样的目标:

SUBDIRS = targ1 targ2 targ3 lib1 lib2 lib3

subdirs:
        for dir in $(SUBDIRS); do \
          $(MAKE) -C $$dir; \
        done

现在,这种方法的好处是只需通过以正确的顺序编写目标就可以轻松指定依赖关系。然而,Make无法完全利用并行化,因为它必须完成每个子目录才能继续下一个目录。

也许我的假设是错误的,因此我问这个问题如何最好地组织目标以实现最佳并行化?作为一个侧面问题,如何组织目标以避免代码重复?

1 个答案:

答案 0 :(得分:1)

如果食谱完全相同,则无需复制食谱。如果您不想,则不必同时定义配方和先决条件。您可以将第一个示例重写为:

build_libs:
        $(MAKE) subdirs

$(SUBDIRS) $(TARG1) $(TARG2) $(TARG3):
        $(MAKE) -C $@

subdirs: $(SUBDIRS)
$(SUBDIRS): $(TARG3)
$(TARG3): $(TARG2)
$(TARG2): $(TARG1)

我真的不知道你为什么要进行build_libs递归;为什么不只有build_libs: subdirs