Having a clean DAG still breaks down with recursive Make: if binary X depends on library A, then X's Makefile either has a rule to recurse to A (and then parallel builds of A might happen, even when building from the top level, unless you use -j1) or it doesn't (and then you can only build from the top level Makefile and you might give up parallelism due to granularity of the top-level DAG).
At the time that essay was written, Make was the best runner available, and the only portable one. There are better options now.
Yeah, no: We use recursive make extensively with a mix of "just normal makefiles" and autoconf schtuff, and it all works fine and reliably.
It's like any programming: Understand your tools, understand your requirements, understand your design and implementation (code carefully), test, review the design and implementation, test, repeat as necessary.
Still a big fan of make all these decades later. One day I may reach BJJ blue belt level.
The proliferation of recursive make has been harmful for make itself!
Most of the make replacement tools are promoted by propaganda which attacks a strawman version of make, whereby it is assumed to be at the center of a shitty recursive situation.
Like anything else, recursive make can be used in a right way and in the wrong way.
It can be used in a wrong way, like described in the article linked by you, when it results in slow project building.
How I use recursive make, it does not introduce any slowdown whatsoever.
I organize my projects so that there is a one-to-one correspondence between leaf Makefiles and the final files that are generated as a result of the building process, regardless of the file types, e.g. executable files, static libraries, dynamic libraries, executable files including GUI resources, documentation files etc.
A generated file may depend on source files located in many directories. Those files are searched and used by the single "make" command that generates one result file (by using the GNU make directory search functions, e.g. "wildcard", "notdir", "addsuffix", "addprefix"), not by recursive make invocations.
I use recursive "make" invocations only for generating multiple result files with a single make command in the top of a directory tree that contains subdirectories where each result file will be built (which also store the corresponding intermediate files, e.g. object files).
The directory tree used for project building is located elsewhere than the source files and its tree structure is not related to the tree structure of the source files, but it is determined only by the number of final files that are produced when building the project, which will be included in a release.
The `-j` is meant for the top-level invocation only, and the $(MAKE) pattern is standard.
The `+` or $(MAKE) "tricks" to ensure the jobserver is inherited in submake and any other subprocess are no longer needed in gmake 4.4 (from 2022) because it defaults to a FIFO instead of pipes. The author should just upgrade gmake :).
[2026-10-01 9:35:10] % which make
/usr/bin/make
[2026-10-01 9:35:39] % /usr/bin/make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
14 comments
[ 0.24 ms ] story [ 16.7 ms ] threadhttps://accu.org/journals/overload/14/71/miller_2004/
Recursive Make Considered Harmful
By Peter Miller
At the time that essay was written, Make was the best runner available, and the only portable one. There are better options now.
It's like any programming: Understand your tools, understand your requirements, understand your design and implementation (code carefully), test, review the design and implementation, test, repeat as necessary.
Still a big fan of make all these decades later. One day I may reach BJJ blue belt level.
Most of the make replacement tools are promoted by propaganda which attacks a strawman version of make, whereby it is assumed to be at the center of a shitty recursive situation.
It can be used in a wrong way, like described in the article linked by you, when it results in slow project building.
How I use recursive make, it does not introduce any slowdown whatsoever.
I organize my projects so that there is a one-to-one correspondence between leaf Makefiles and the final files that are generated as a result of the building process, regardless of the file types, e.g. executable files, static libraries, dynamic libraries, executable files including GUI resources, documentation files etc.
A generated file may depend on source files located in many directories. Those files are searched and used by the single "make" command that generates one result file (by using the GNU make directory search functions, e.g. "wildcard", "notdir", "addsuffix", "addprefix"), not by recursive make invocations.
I use recursive "make" invocations only for generating multiple result files with a single make command in the top of a directory tree that contains subdirectories where each result file will be built (which also store the corresponding intermediate files, e.g. object files).
The directory tree used for project building is located elsewhere than the source files and its tree structure is not related to the tree structure of the source files, but it is determined only by the number of final files that are produced when building the project, which will be included in a release.
The `+` or $(MAKE) "tricks" to ensure the jobserver is inherited in submake and any other subprocess are no longer needed in gmake 4.4 (from 2022) because it defaults to a FIFO instead of pipes. The author should just upgrade gmake :).
https://formulae.brew.sh/formula/make