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

发布于 2024-08-26 22:50:43 字数 508 浏览 7 评论 0原文

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

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

all:
    @make -j$(NUM_PROCESSORS) all

或者:

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

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

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

% make all

希望这是有道理的。

更新:仍然希望有一个用于上述内容的示例 Makefile。对查找进程数并不是很感兴趣,而是对如何编写 makefile 来并行构建而不使用 -j 命令行选项感兴趣。

Not sure if this is possible in one Makefile alone, but I was hoping to write a Makefile in a way such that trying to build any target in the file auto-magically detects the number of processors on the current system and builds the target in parallel for the number of processors.

Something like the below "pseudo-code" examples, but much cleaner?

all:
    @make -j$(NUM_PROCESSORS) all

Or:

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

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

In both cases, all you would have to type is:

% make all

Hopefully that makes sense.

UPDATE: Still hoping for an example Makefile for the above. Not really interested in finding the number of processes, but interested in how to write a makefile to build in parallel without the -j command line option.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

枯寂 2024-09-02 22:50:43

检测部分将取决于操作系统。下面是一个可以在 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 值),但可能可以巧妙地处理它。

The detection part is going to be OS dependent. Here's a fragment that will work on Linux and 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

To get it working you are probably going to have to re-invoke make. Then your problem is preventing infinite recursion. You could manage that by having two makefiles (the first only resetting the -j value), but it is probably possible to finesse it.

总攻大人 2024-09-02 22:50:43

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

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

请注意,这是 Linux 特定的。

I just added this to the top of my Makefile. It lets make create any number of jobs, but tries to keep the load average below the number of cpu cores.

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

Note this is Linux specific.

拍不死你 2024-09-02 22:50:43

这是我的做法:

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 

Here's what I went with:

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 
喜你已久 2024-09-02 22:50:43

在稍微浏览了一下 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,但它仍然非常无缝且有用。

After poking around the LDD3 chapter 2 a bit and reading dmckee's answer, I came up with this not so great answer of using two makefiles (I would prefer just one).

$ 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"

What do you think about this solution?

Benefits I see is that people still type make to build. So there isn't some "driver" script that does the NPROCS and make -j$(NPROCS) work which people will have to know instead of typing make.

Downside is that you'll have to explicitly use make -f Makefile.goals in order to do a serial build. And I'm not sure how to solve this problem...

UPDATED: added $J to above code segment. Seems work work quite well. Even though its two makefiles instead of one, its still quite seamless and useful.

内心旳酸楚 2024-09-02 22:50:43

我将跳过 $(NPROCS) 检测内容,但以下是如何在单个 Makefile 中执行此操作(这可能是 GNU Make 特定的,但看起来像您正在运行的变体):

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

请参阅定义最后手段默认规则覆盖另一个 Makefile 的部分 GNU Make 手册

I'll skip over the $(NPROCS) detection stuff, but here's how you could do this in a single Makefile (this is probably GNU Make specific, but that looks like the variant you're running):

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

See Defining Last-Resort Default Rules and Overriding Part of Another Makefile in the GNU Make Manual.

桃酥萝莉 2024-09-02 22:50:43

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

如果给出 -j 选项而不带参数,make 将不会限制可以同时运行的作业数量。

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

If I read the question correctly, the goal is to parallelize the build process as much as possible. The make man page states the following

If the -j option is given without an argument, make will not limit the number of jobs that can run simultaneously.

Isn't this basically the solution that you want? If your Makefile has enough parallel targets you will use all your CPUs and if the targets are not parallel, that -j option won't help anywas.

此生挚爱伱 2024-09-02 22:50:43

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

示例:

alias make="make -j"

或者您可以这样做:

alias jmake="make -j"

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

If you want it to be automatic, then you can override your typical make command to be an alias to itself in your .bashrc in your home directory.

Example:

alias make="make -j"

Or you could do something like:

alias jmake="make -j"

in the case that you don't want to override it, but want a quick and easy (and memorable) way to run make in parallel.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文