GNU make's -j option

Gnu Make

Gnu Make Problem Overview


Ever since I learned about -j I've used -j8 blithely. The other day I was compiling an atlas installation and the make failed. Eventually I tracked it down to things being made out of order - and it worked fine once I went back to singlethreaded make. This makes me nervous. What sort of conditions do I need to watch for when writing my own make files to avoid doing something unexpected with make -j?

Gnu Make Solutions


Solution 1 - Gnu Make

I think make -j will respect the dependencies you specify in your Makefile; i.e. if you specify that objA depends on objB and objC, then make won't start working on objA until objB and objC are complete.

Most likely your Makefile isn't specifying the necessary order of operations strictly enough, and it's just luck that it happens to work for you in the single-threaded case.

Solution 2 - Gnu Make

In short - make sure that your dependencies are correct and complete.

If you are using a single threaded make then you can be blindly ignoring implicit dependencies between targets. When using parallel make you can't rely on the implicit dependencies. They should all be made explicit. This is probably the most common trap. Particularly if using .phony targets as dependencies.

This link is a good primer on some of the issues with parallel make.

Solution 3 - Gnu Make

Here's an example of a problem that I ran into when I started using parallel builds. I have a target called "fresh" that I use to rebuild the target from scratch (a "fresh" build). In the past, I coded the "fresh" target by simply indicating "clean" and then "build" as dependencies.

build: ## builds the default target
clean: ## removes generated files
fresh: clean build ## works for -j1 but fails for -j2

That worked fine until I started using parallel builds, but with parallel builds, it attempts to do both "clean" and "build" simultaneously. So I changed the definition of "fresh" as follows in order to guarantee the correct order of operations.

fresh:
    $(MAKE) clean
    $(MAKE) build

This is fundamentally just a matter of specifying dependencies correctly. The trick is that parallel builds are more strict about this than are single-threaded builds. My example demonstrates that a list of dependencies for given target does not necessarily indicate the order of execution.

Solution 4 - Gnu Make

If you have a recursive make, things can break pretty easily. If you're not doing a recursive make, then as long as your dependencies are correct and complete, you shouldn't run into any problems (save for a bug in make). See Recursive Make Considered Harmful for a much more thorough description of the problems with recursive make.

Solution 5 - Gnu Make

It is a good idea to have an automated test to test the -j option of ALL the make files. Even the best developers have problems with the -j option of make. The most common issues is the simplest.

myrule: subrule1 subrule2
     echo done

subrule1:
     echo hello

subrule2:
     echo world

In normal make, you will see hello -> world -> done. With make -j 4, you will might see world -> hello -> done

Where I have see this happen most is with the creation of output directories. For example:

build: $(DIRS) $(OBJECTS)
     echo done

$(DIRS):
     -@mkdir -p $@

$(OBJECTS):
     $(CC) ...

Solution 6 - Gnu Make

Just thought I would add to subsetbrew's answer as it does not show the effect clearly. However adding some sleep commands does. Well it works on linux.

Then running make shows differences with:

  • make
  • make -j4

all: toprule1

toprule1: botrule2 subrule1 subrule2
	@echo toprule 1 start
	@sleep 0.01
	@echo toprule 1 done

subrule1: botrule1
	@echo subrule 1 start
	@sleep 0.08
	@echo subrule 1 done

subrule2: botrule1
	@echo subrule 2 start
	@sleep 0.05
	@echo subrule 2 done

botrule1:
	@echo botrule 1 start
	@sleep 0.20
	@echo "botrule 1 done (good prerequiste in sub)"

botrule2:
	@echo "botrule 2 start"
	@sleep 0.30
	@echo "botrule 2 done (bad prerequiste in top)"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpythonic metaphorView Question on Stackoverflow
Solution 1 - Gnu MakeJeremy FriesnerView Answer on Stackoverflow
Solution 2 - Gnu MakeAndrew EdgecombeView Answer on Stackoverflow
Solution 3 - Gnu MakeBrent BradburnView Answer on Stackoverflow
Solution 4 - Gnu MakeAdam RosenfieldView Answer on Stackoverflow
Solution 5 - Gnu Makeuser2714439View Answer on Stackoverflow
Solution 6 - Gnu MakeM HutsonView Answer on Stackoverflow