Recursive Make passes incorrect -j argument

562 views Asked by At

I'm running make (GNU Make 3.82) with a recursive Makefile.
I'm running make -j2 in order to spawn only 2 processes in parallel.
The internal Makefile is called with $(MAKE).

However, it looks like the internal Makefile (which was started by the main Makefile) spawns processes infinitely as if it was given -j and not -j2.

Trying to verify this, I dumped the environment variables of the child "make":

# pgrep -a make
17218 make -j2
17227 make -C obj_dir/ -f Vf1_package.mk ...

# strings /proc/17227/environ
...
MAKEFLAGS= --jobserver-fds=3,4 -j
...

MAKEFLAGS is not set explicitly anywhere, and -j is only provided in the command line and doesn't appear anywhere in the makefiles. So it seems like "make" itself decided to strip the "2" from the -j argument when composing the MAKEFLAGS for the child "make".

Any idea what could cause "make" to set MAKEFLAGS to -j instead of -j2?


Update 1

I've identified the problem, but I still don't understand why it happens and how to fix that.

The problem is that the job server doesn't work well when the sub-make is running under SCL context.
This is required because I need the sub-make to use specific gcc toolchain.

SCL      = scl enable devtoolset-8
...
sub_make:
    $(SCL) "$(MAKE) -C $(SUB_MAKE_DIR) ... "

When running like this, the sub-make spawns infinite number of jobs. When SCL is removed, it works as expected.

  • Why does SCL interfere with make's job server?
  • How can I solve this? I know I can enable SCL before running the external Makefile, but I would like to control the toolset from within the Makefile.

Update 2

It seems to be related to the fact that SCL changes PATH environment variable. On the new PATH, "make" is newer ("GNU Make 4.2.1").

So it seems that make job server fails if the top level make is running old GNU Make 3.82 and the sub make is running newer 4.2.1 make, maybe something changed between these versions in the way make communicates with the sub-make.

2

There are 2 answers

4
MadScientist On

There's nothing wrong here. The top-level make knows how many total jobs there are and it arranges for all the sub-makes to share those jobs through the jobserver (that's what the --jobserver-fds entry in MAKEFLAGS is for). The sub-makes don't need to know how many total jobs there are, they just need to know how to ask if they can start a new job.

In the very old version of GNU make you are using there is no way, from a sub-make, to know what the specific -j number for this build.

Starting with GNU make 4.2, make will add the specific -j value to MAKEFLAGS for informational purposes even though it's still not used.

EDIT

I don't know anything about scl or how it works. But, the GNU make jobserver works by sharing file descriptors across all the sub-makes. If this scl tool is interfering with that, say by forcing all file descriptors to be closed, or running the sub-make inside a docker image where obviously it can't access these shared file descriptors, or some similar thing, then it clearly cannot work with the jobserver feature and you'll have to run the entire make inside the scl.

An option is to not put the -j on the outer make but instead run a single inner make using -j, inside scl.

1
Altaf On

Can you run make --print-data-base and check if you get proper value of -j.

May be execute a simple test example as shown below where you can test to check if gnu make is able to compile multiple files in parallel to generate object files and is giving correct values of -j:

# .SILENT:
.PHONY:compile objs
TARGET = program.exe
CC=gcc

SOURCES = file_1.c file_2.c file_3.c
OBJ_FILES:= $(SOURCES:.c=.o)


objs: $(OBJ_FILES)

%.o: %.c
    $(CC) $(FLAGS) -c $< -o $@

all: test 

# Enable parallel compilation
compile:
    make -j ${NUMBER_OF_PROCESSORS} objs

link : compile $(TARGET)

$(TARGET): $(OBJ_FILES)
    $(CC) $(FLAGS) $(OBJ_FILES) -o $@

test: link 
    # Execute test script
    echo "Executing test script"

Command to execute : make test
This will help you debug and also check if there is issue of gnu-make or some internal bug or make is unable to run in parallel as it did not find anything. I have use ${NUMBER_OF_PROCESSORS} to use all the available processors, you can change it's value and test different runs as per your need.

EDIT
Unfortunately I am not aware about sc1.If scl is the root cause identified, then option would be run the entire make inside sc1. or maye be would be good to test once by explicitly passing -j2 inside the sc1 as maybe global flags are not getting passed to SC1.