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

dla*_*tte 28 parallel-processing makefile

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

像下面的"伪代码"示例,但更干净?

all:
    @make -j$(NUM_PROCESSORS) all
Run Code Online (Sandbox Code Playgroud)

要么:

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

.inparallel:
    @make -j$(NUM_PROCESSORS) $(ORIGINAL_TARGET)
Run Code Online (Sandbox Code Playgroud)

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

% make all
Run Code Online (Sandbox Code Playgroud)

希望这是有道理的.

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

dmc*_*kee 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
Run Code Online (Sandbox Code Playgroud)

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

  • NPROCS:= Windows上的$(NUMBER_OF_PROCESSORS),继承自同名的自动环境变量. (2认同)
  • 对于Mac OS X,您可以通过将信息限制为仅硬件数据来改进system_profiler的使用 - 例如`system_profiler SPHardwareDataType`.然后你可以使用类似的命令:`system_profiler SPHardwareDataType | awk'/核心总数/ {print $ 5} {next;}'`.虽然你可以使用`sysctl -n hw.ncpu`而不是使用system_profiler,但只是意识到它可以报告一些不同的,因为它还包括超线程内核.对于我的13英寸英特尔酷睿i5(2015年初),system_profiler报告2个内核,而sysctl报告4.你可以使用`sysctl -n hw.physicalcpu`. (2认同)

小智 7

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

MAKEFLAGS+="-j -l $(shell grep -c ^processor /proc/cpuinfo) "
Run Code Online (Sandbox Code Playgroud)

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

  • 更短:`MAKEFLAGS+="-j $(shell nproc)"` - 请注意,你可以很容易地用这个来射击自己 (3认同)
  • 我更喜欢`JOBS ?= $(shell nproc)`,然后是`MAKEFLAGS += -j $(JOBS) -l $(JOBS)`。 (2认同)

dla*_*tte 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"
Run Code Online (Sandbox Code Playgroud)

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

我看到的好处是人们仍然make打算建立.因此,不存在一些"驱动程序"脚本,并NPROCSmake -j$(NPROCS)人们必须知道,而不是打字使工作.

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

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


amo*_*mos 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 
Run Code Online (Sandbox Code Playgroud)

  • 而不是通过`awk`传递`sysctl`输出,只需要求值:`sysctl -n hw.ncpu` (4认同)
  • 确定操作系统(可在旧Linux和Mac上运行)的最简单方法是NUMPROC = \`getconf _NPROCESSORS_ONLN \`` (2认同)

Jac*_*lly 5

我将跳过$(NPROCS)检测的东西,但是这里你可以在一个单独的地方做这个Makefile(这可能是GNU Make特定的,但看起来像你正在运行的变体):

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

请参阅GNU Make Manual中的定义Last-Resort默认规则覆盖另一个Makefile的一部分.