【问题标题】:How to optimize parallel build of subdirectories using GNU Make?如何使用 GNU Make 优化子目录的并行构建?
【发布时间】:2015-03-21 13:48:38
【问题描述】:

我在一个大型项目中工作,我们有几个子目录可以从中构建库/存档。大多数子目录之间没有相互依赖关系,但有些子目录有。

例如,这是一般形式:

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 无法充分利用并行化,因为它必须先完成每个子目录,然后才能继续下一个。

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

【问题讨论】:

    标签: makefile gnu-parallel


    【解决方案1】:

    你不必复制食谱,如果它们都一样的话。如果您不想,不必同时定义食谱和先决条件。您可以将您的第一个示例重写为:

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

    我真的不知道你为什么要使用build_libs 递归;为什么不直接使用build_libs: subdirs

    【讨论】:

    • 确实如此,感谢您的提示。但是对于另一个关于优化的问题,您是否同意这是利用并行化的最佳方式?
    • 这里的方法会给你最好的全方位优化。第二种方法(全部在一个循环中)的问题在于,假设还有一个运行时间较长的作业正在构建 lib1:其他 lib* 目录中的其他作业在完成之前无法启动。使用这种方法,您将拥有更多的并行度。
    猜你喜欢
    • 2022-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    相关资源
    最近更新 更多