Nonrecursive make advocacy
When I set up the Mugshot
client build I noticed that the automake manual suggests a
non-recursive setup, so I thought I’d try it. I’ve used a
non-recursive setup for every project since. The
automake manual points to the classic 1997 paper, Recursive
Make Considered Harmful, if you want the detailed rationale.
My first attempt at the Mugshot client build had one big Makefile.am
with every target inline in it; that was a downside. Owen nicely
fixed it with a convention: for build subcomponent “libfoo” put
“include Makefile-libfoo.am” in the Makefile.am, then put the build
for stuff related to “libfoo” in “Makefile-libfoo.am”.
I recommend doing your project this way. I’ve spent a lot less
time messing with weird build issues; nonrecursive make “just works”
as long as you get the dependencies right, while recursive make
involves various hacks and workarounds for the fact that make can’t
see the whole dependency graph. In particular, nonrecursive make
supports “make -jN” without extra effort, a big win since
most new computers have multiple cores these days.
Nonrecursive make has the aesthetic benefit that it keeps all
your build stuff separate from your source code. On top of
that, since srcdir != builddir will work more easily, you can make a
habit of building in a separate directory. Result: your source tree
contains source and nothing else.
GNOME unfortunately makes nonrecursive automake painful. Two issues
I’ve encountered are that “gtkdocize” generates a Makefile that is
broken in a nonrecursive setup, and that jhbuild always wants to do
srcdir=builddir even though my project is nice and clean and doesn’t
I’m not sure why GNOME started with recursive make and everyone has
cut-and-pasted it ever since; it’s possible automake didn’t support
nonrecursive make in older versions, or maybe it was just dumb luck.
With “weird build bugs due to recursive make” knocked off the
list, my current top automake feature requests:
- A way to echo only the filename “foo.c” instead of a 10-line
list of compiler flags, so I can see all warnings and errors at once without
scrolling through pages of junk.
In a nonrecursive make setup, a way to set a base directory for
SOURCES, so instead of “foo_SOURCES=src/foo.c src/bar.c” I can have
“foo_SOURCE_BASEDIR=src foo_SOURCES=foo.c bar.c” or something along
Ability to include in the build a relative directory outside the
source tree, like “../common” or “../some-not-installed-dependency” –
this almost works but breaks in “make dist” because it tries
to copy “../common” to “distdir/../common” – we fix that in the
Mugshot client build with a little hack, but I can imagine an
automake-level convention for how to handle it.
These are obviously pretty minor quibbles.
(This post was originally found at http://log.ometer.com/2007-07.html#14)