如何编写makefile以使用GNU Make自动检测和并行化构建?

时间:2010-03-26 23:42:39

标签: makefile parallel-processing

不确定单独在一个Makefile中是否可以这样做,但我希望以一种方式编写Makefile,以便尝试在文件中构建任何目标,自动地检测当前系统上的处理器数量并构建并行处理目标数量。

类似下面的“伪代码”示例,但更清洁?

all:
    @make -j$(NUM_PROCESSORS) all

或者:

all: .inparallel
    ... build all here ...

.inparallel:
    @make -j$(NUM_PROCESSORS) $(ORIGINAL_TARGET)

在这两种情况下,您只需输入以下内容:

% make all

希望这是有道理的。

更新:仍然希望上面的示例Makefile。对找到进程数并不感兴趣,但对如何在没有-j命令行选项的情况下编写并行构建的makefile感兴趣。

7 个答案:

答案 0 :(得分:23)

检测部分将取决于操作系统。这是一个适用于Linux和Mac OS X的片段:

NPROCS:=1
OS:=$(shell uname -s)

ifeq($(OS),Linux)
  NPROCS:=$(shell grep -c ^processor /proc/cpuinfo)
endif
ifeq($(OS),Darwin) # Assume Mac OS X
  NPROCS:=$(shell system_profiler | awk '/Number Of CPUs/{print $4}{next;}')
endif

要使其正常工作,您可能需要重新调用make。那你的问题是阻止无限递归。您可以通过使用两个makefile(第一个仅重置-j值)来管理它,但可能会对它进行精细化。

答案 1 :(得分:7)

我刚把它添加到我的Makefile的顶部。它允许创建任意数量的作业,但尝试将负载平均值保持在cpu核心数之下。

MAKEFLAGS+="-j -l $(shell grep -c ^processor /proc/cpuinfo) "

请注意,这是特定于Linux的。

答案 2 :(得分:6)

在读了LDD3第2章并阅读dmckee的回答之后,我想出了使用两个makefile的不太好的答案(我更喜欢只有一个)。

$ cat Makefile
MAKEFLAGS += -rR --no-print-directory

NPROCS := 1
OS := $(shell uname)
export NPROCS

ifeq ($J,)

ifeq ($(OS),Linux)
  NPROCS := $(shell grep -c ^processor /proc/cpuinfo)
else ifeq ($(OS),Darwin)
  NPROCS := $(shell system_profiler | awk '/Number of CPUs/ {print $$4}{next;}')
endif # $(OS)

else
  NPROCS := $J
endif # $J

all:
    @echo "running $(NPROCS) jobs..."
    @$(MAKE) -j$(NPROCS) -f Makefile.goals $@

%:
    @echo "building in $(NPROCS) jobs..."
    @$(MAKE) -j$(NPROCS) -f Makefile.goals $@
$ cat Makefile.goals
MAKEFLAGS += -rR --no-print-directory
NPROCS ?= 1

all: subgoal
    @echo "$(MAKELEVEL) nprocs = $(NPROCS)"

subgoal:
    @echo "$(MAKELEVEL) subgoal"

您对此解决方案有何看法?

我看到的好处是人们仍然要键入make来构建。因此,没有一些“驱动程序”脚本执行NPROCSmake -j$(NPROCS)工作,人们将不得不知道而不是输入make。

缺点是您必须明确使用make -f Makefile.goals才能进行串行构建。而且我不确定如何解决这个问题...

更新:在上面的代码段中添加了$ J.似乎工作很顺利。即使它的两个makefile而不是一个,它仍然非常无缝和有用。

答案 3 :(得分:6)

这就是我的目标:

ifeq ($(OS),Linux)
        NUMPROC := $(shell grep -c ^processor /proc/cpuinfo)
else ifeq ($(OS),Darwin)
        NUMPROC := $(shell sysctl hw.ncpu | awk '{print $$2}')
endif

# Only take half as many processors as available
NUMPROC := $(shell echo "$(NUMPROC)/2"|bc)

ifeq ($(NUMPROC),0)
        NUMPROC = 1
endif 

答案 4 :(得分:5)

我会跳过$(NPROCS)检测内容,但是这里是你如何在一个Makefile中执行此操作(这可能是GNU Make特定的,但这看起来像你正在运行的变种):

ifeq ($(NPROCS),)
# Code to set NPROCS...
%:
    $(MAKE) -j$(NPROCS) NPROCS=$(NPROCS)
else
# All of your targets...
endif

请参阅Defining Last-Resort Default Rules中的Overriding Part of Another MakefileGNU Make Manual

答案 5 :(得分:2)

如果您希望它是自动的,那么您可以在主目录的.bashrc中覆盖典型的make命令,使其成为自身的别名。

示例:

alias make="make -j"

或者你可以这样做:

alias jmake="make -j"

如果你不想覆盖它,但想要一种快速,简单(和令人难忘)的方式来并行运行make。

答案 6 :(得分:1)

如果我正确阅读了问题,目标是尽可能并行化构建过程。 make手册页说明了以下内容

  

如果在没有参数的情况下给出-j选项,make将不会限制可以同时运行的作业数。

这基本上不是你想要的解决方案吗?如果您的Makefile有足够的并行目标,那么您将使用所有CPU,如果目标不是并行的,那么-j选项将无济于事。