kkm mistrusts SE
kkm mistrusts SE

Reputation: 5530

Is there a reason to use `$(MAKE) target` as a recipe?

I am working on a quite complex and somewhat old makefile (so it could have bogotified over time), and notice rules that have this recipe pattern:

SUBDIRS = lib1 lib2 lib3

all:    prerequisites
        $(MAKE) subdirs

subdirs: $(SUBDIRS)
# (empty recipe body)

Is (or was) there any reason to write the all rule in this way, instead of simply

all:    prerequisites subdirs
# (empty recipe body)

Is there a subtle difference between the two? I am running both with GNU make 4.1, and not seeing any differences.

The makefile is intended for Linux and OS/X, and supposed to support somewhat outdated setups, but not very (for one, we require gcc 4.7, which is 3 years old).

Upvotes: 1

Views: 729

Answers (2)

bobbogo
bobbogo

Reputation: 15483

There is one massive and important difference: Writing it as three separate targets allows the -j flag to work properly. make -j9 tells make to keep 9 jobs running simultaneously, very nice if you have 8 CPUs.

This is a good test of any makefile, and the whole point of make IMHO.

The pattern you present is trying to ensure prerequisites are complete before the subdirs start building. There is a more straight-forward way of writing that of course:

all: ${SUBDIRS}
    echo $@ Success

${SUBDIRS}: prerequisites
    echo Building $@...

subdirs: ${SUBDIRS} ; # Empty symbolic target

The subdirs target is only there as a convenience to anyone who wishes to type make subdirs.

PHONY: should be added as appropriate of course

Upvotes: 3

Alexandre Fenyo
Alexandre Fenyo

Reputation: 4809

There are subtle differences, but this is certainly not important, nor intentional, with your specific situation.

Included, but not limited to, here are some minor differences.

First difference: gmake has a special feature that defines (if not already done) and increments the variable MAKELEVEL at start. So the following two Makefiles have different results:

SUBDIRS = lib1 lib2 lib3
all: prerequisites
     $(MAKE) subdirs
subdirs: $(SUBDIRS)
lib3:
     echo $(MAKELEVEL)

Running this Makefile displays:

 1

But with the following:

SUBDIRS = lib1 lib2 lib3
all: prerequisites subdirs
subdirs: $(SUBDIRS)
lib3:
     echo $(MAKELEVEL)

Running this Makefile displays:

 0

So, in case MAKELEVEL would be used in your Makefile, things may not be built the same way. For instance, defining a variable this way would have some impacts:

 ifeq (1,${MAKELEVEL})
 CFLAGS=-g
 endif

2nd difference: as stated in the gmake manual, By default, only variables that came from the environment or the command line are passed to recursive invocations. But it would be very rare to have an impact, because if the definition of the variable were not context-dependent, the variable would then be defined with the same value in the inner invocation (to get an impact, you should set a context-dependent variable and encounter different contexts while first running the Makefile and while running the recursive invocation).

Anyway, people often use recursive invocations when there are other Makefiles in subdirectories (but this is obviously not your situation). So, we often encounter this:

SUBDIRS = lib1 lib2 lib3
all:    prerequisites
     $(MAKE) -C subdirs

Of course, this can not be replaced by all: prerequisites $SUBDIRS, this would have no sense. But this is perhaps the reason why somebody wrote what you encountered and not the other way without inner invocation, thinking wrongly that it is a more common way to write things.

Upvotes: 2

Related Questions