nethack
nethack

Reputation: 42

Getting make to stop on first error in multi-directory build

Our project uses Makefiles with the following type of rule for each multi-directory sub-make:

DIRS = lib audio conf parser control
all: $(DIRS)
        @for DIR in $(DIRS); \
        do \
          ( cd $$DIR; $(MAKE) $(MFLAGS) all; ) \
        done

If any file fails to compile in one of the leaf makes, the build stops in that directory - but the rest of the make continues. How do I set up these Makefiles so the first error at any level will stop the entire make?

Thanks

Upvotes: 2

Views: 12646

Answers (2)

Renaud Pacalet
Renaud Pacalet

Reputation: 29222

From the for loops section of the bash manual:

The return status is the exit status of the last command that executes.

So, you do not need to capture return statuses. You need your recipe to fail if any sub-make fails:

DIRS = lib audio conf parser control
all: $(DIRS)
    @for DIR in $(DIRS); do \
        $(MAKE) -C $$DIR $(MFLAGS) all || exit 1; \
    done

But it would be much better to have individual recipes per directory, instead of a single for loop:

DIRS = lib audio conf parser control

all: $(DIRS)

.PHONY: all $(DIRS)

$(DIRS):
    $(MAKE) -C $@ $(MFLAGS) all

This way, if a sub-make fails, it is the complete rule's recipe that fails and make stops. Note the .PHONY special target, in this case it is needed because you want to run the recipe, even if the directory already exists.

There is another advantage with this structure: if you run make in parallel mode (make -j N) it will launch several sub-makes simultaneously instead of just one with the for loop. And each sub-make, in turn, will launch several recipes in parallel, up to N jobs. On a multi-processor or multi-core architecture the speed-up factor can be significant.

But this advantage can become a drawback if your project is not parallel safe, that is, if the order of processing of your directories matters and is not properly defined in the makefiles. If you are in this situation you can add a:

.NOTPARALLEL:

special target at the beginning of your main makefile to tell make. But it would be better to explicitly define the inter-directories dependencies. And if you do not know how to do this, please ask another question.

Upvotes: 5

nethack
nethack

Reputation: 42

I found the answer in this question's answer: I have to rewrite to capture the return status of each submake.

Upvotes: 0

Related Questions