Rendered at 17:49:10 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
stabbles 20 hours ago [-]
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 :).
Has Apple backported anything recent to their forked gmake? Have they ever backported any features for that matter?
plorkyeran 13 hours ago [-]
Apple does not ship any version of gmake. The only included make is BSD make.
yaris 10 hours ago [-]
On my machine (Golden Gate):
[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
On Sequoia it was the same.
1kurac 9 hours ago [-]
Setting environment variable `MAKEFLAGS=-j8` transfers to subprocesses.
kazinator 13 hours ago [-]
How it works is that the top-level invocation runs the job server, and the children feed requests to it. The top-level controls the parallelism.
If you have sub-projects which cross-depend on each other (no total ordering), then recursive make will have a bad time. I agree.
Author thinks the best way is to stop doing recursive make. I disagree.
IMHO, the best way to solve this is to arrange your sub-projects properly, so the are no circular dependencies and thus there is one correct order. Not only your build should be a DAG on file level, it should also be a DAG on the sub-project/directory level. Then a single recursive "make" pass builds everything properly, no need for ugly tricks like running make twice, or intentionally omitting some dependencies.
(Even better option is to stop using make for such large projects - it's great for smaller ones, but for the huge ones, there are much better runners available. But I assume there is some reason to use make)
entrope 8 hours ago [-]
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.
adrian_b 4 hours ago [-]
Like anything else, recursive make can be used in a right way and in a 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 also never write dependencies manually, I always generate them automatically. I also never write the names of source files in makefiles, I only provide a top directory and/or a list of subdirectories, where source files can be found automatically. This means that I never need to edit a makefile when source files are added, moved, renamed or deleted.
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.
PeterWhittaker 20 hours ago [-]
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.
kazinator 12 hours ago [-]
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.
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://accu.org/journals/overload/14/71/miller_2004/
Recursive Make Considered Harmful
By Peter Miller
If you have sub-projects which cross-depend on each other (no total ordering), then recursive make will have a bad time. I agree.
Author thinks the best way is to stop doing recursive make. I disagree.
IMHO, the best way to solve this is to arrange your sub-projects properly, so the are no circular dependencies and thus there is one correct order. Not only your build should be a DAG on file level, it should also be a DAG on the sub-project/directory level. Then a single recursive "make" pass builds everything properly, no need for ugly tricks like running make twice, or intentionally omitting some dependencies.
(Even better option is to stop using make for such large projects - it's great for smaller ones, but for the huge ones, there are much better runners available. But I assume there is some reason to use make)
At the time that essay was written, Make was the best runner available, and the only portable one. There are better options now.
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 also never write dependencies manually, I always generate them automatically. I also never write the names of source files in makefiles, I only provide a top directory and/or a list of subdirectories, where source files can be found automatically. This means that I never need to edit a makefile when source files are added, moved, renamed or deleted.
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.
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.