6

Consider the following contrived Makefile:

.PHONY: all one two
SLEEP = 2

all: one two

one two:
    @sleep $(SLEEP)
    @echo $@

Running this with make -j 2 all gets both jobs done in the time it takes to run either of them because they are both running in parallel. This works great if you control the invocation of make and remember to do it every time, but not if all you control is the Makefile.

Setting the MAKEFLAGS environment variable can also control this:

$ export MAKEFLAGS="-j 2"
$ make all

However setting this value in the Makefile does not seem to work:

MAKEFLAGS = -j 2

Fail.

export MAKEFLAGS="-j 2"

Fail.

Setting JOBS likewise doesn't seem to have any effect. Is there any way to control the default number of jobs run from inside a Makefile?

Note I'm aware that I could use a dummy recipe and invoke a recursive make from inside it, but that would introduce a giant amount of mess because I would need to set it up for a whole bunch of possible targets, and I'm dealing with included Makefiles that don't necessarily play nice with recursion.

Caleb
  • 5,084
  • 1
  • 46
  • 65
  • There's no way unless you invoke make recursively, alas. (But wrapping the one recursive invocation is not _that_ bad, albeit tricky: just use `eval` to define phony targets for everything in `MAKECMDGOALS` and have those depend on the wrapped invocation goal. And things like `-q` will break unless you are willing to analyze `MAKEFLAGS` in depth, etc.) – Michael Livshin Feb 17 '17 at 12:33
  • Or use a wrapper script... – Michael Livshin Feb 17 '17 at 12:38
  • @MichaelLivshin Those comments would make an answer. – Caleb Feb 17 '17 at 12:42
  • The issue is that by the time make finishes parsing makefiles it's already configured its environment including setting up the job server, etc So changes to MAKEFLAGS that appear inside the makefile can't always impact everything about the current instance of make. Offhand I'm not sure why it has to be that way, but that's the way it is today. – MadScientist Feb 17 '17 at 14:12

1 Answers1

14

This was impossible until GNU Make 4.3 (released January 19th, 2020). In the news file there is this item:

  • Makefiles can now specify the '-j' option in their MAKEFLAGS variable and this will cause make to enable that parallelism mode.

This should now do the trick (of course you can hard code a value too):

MAKEFLAGS := --jobs=$(shell nproc)

You may wish to combine that with an option to buffer the output of commands and output the results together (instead of lines possibly being intermixed):

MAKEFLAGS += --output-sync=target
Caleb
  • 5,084
  • 1
  • 46
  • 65
  • Is there a way we can use the environment variables to do the same job – xiaojueguan Jun 09 '22 at 13:25
  • @xiaojueguan Sure, set `MAKEFLAGS` which is read from the host environment before being modified from anything found in the Makefiles or CLI args. – Caleb Jun 09 '22 at 20:29