In Makefiles generated by automake versions to date (1.18.1), submakes are
called serially.
---8<---
$(am__recursive_targets):
@fail=; \
...
for subdir in $$list; do \
..
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
--->8---
As a directory runs out of targets to make just before completion,
the parallelization factor drops for that directory, and thus also the
parent make. A project with SUBDIRS can therefore accrue a lot of idle
time. This can be fixed by running over SUBDIRS in parallel.
An updated ruleset fragment needs to looks like this:
---8<---
$(am__recursive_targets):
@fail=; \
if $(am__make_keepgoing); then \
failcom='fail=yes'; \
else \
failcom='exit 1'; \
fi; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
md="$${TMPDIR=/tmp}/am-rm-$$$$"; \
mkdir -p "$$md"; \
mf="$$md/Makefile.$@"; \
new_phony=".PHONY:"; \
new_targets="all:"; \
for subdir in $$list; do \
if test "$$subdir" = "."; then \
dot_seen=yes; \
fi; \
new_phony="$$new_phony d.$$subdir"; \
new_targets="$$new_targets d.$$subdir"; \
done; \
if test "$$dot_seen" = "no"; then \
new_phony="$$new_phony d.."; \
new_targets="$$new_targets d.."; \
fi; \
echo "$$new_phony" >"$$mf"; \
echo "$$new_targets" >>"$$mf"; \
for subdir in $$list; do \
if test "$$subdir" = "."; then \
dot_seen=yes; \
echo "d.$$subdir:" >>"$$mf"; \
echo " $$""(MAKE) $$""(AM_MAKEFLAGS) -C $$subdir $$target-am"
>>"$$mf"; \
else \
echo "d.$$subdir:" >>"$$mf"; \
echo " $$""(MAKE) $$""(AM_MAKEFLAGS) -C $$subdir $$target"
>>"$$mf"; \
fi; \
done; \
if test "$$dot_seen" = "no"; then \
echo "d..:" >>"$$mf"; \
echo " $$""(MAKE) $$""(AM_MAKEFLAGS) -C . $$target-am"
>>"$$mf"; \
fi; \
$(MAKE) $(AM_MAKEFLAGS) -f "$$mf"
---8<--
This way, if you have multiple directories each with a target
involving `sleep 60`, you can now run `make -j` at the toplevel and
complete the whole thing in 60 rather than 60*x seconds.
There are only few unsolved points:
* delete $md again
* making this conditional on an automake option e.g.
AM_INIT_AUTOMAKE([parallel-recursion]), because a lot of projects
likely depend on serial recursion