Subject: Re: Reducing bsd.pkg.mk recursion
To: Todd Vierling <tv@duh.org>
From: Christopher Vance <christopher@nu.org>
List: tech-pkg
Date: 11/15/2004 15:42:50
On Thu, Nov 11, 2004 at 10:48:13PM -0500, Todd Vierling wrote:
>There's a lot of it.  A whopping caboodle of it.  The problem is, it's
>rather expensive to call ${MAKE} recursively (in some cases, a couple levels
>deep) within a package when there's really no need to do so.

I had a similar problem at my previous job (using GNU make, but the
principles are the same).  In some cases, there are two dimensions of
possible recursion: 1) over (sub)directories, and 2) over targets
within a directory.

My solution to reducing recursion had multiple parts:

1) rules with actions have only real targets, so that they only get do
stuff when the target is actually out of date;

2) traditional targets with expected hierarchy (all, install, etc.)
have dependencies on real targets, and on each other where
appropriate, but no actions of their own;

3) explicit targets (usually the traditional ones) are coalesced so
that the earlier ones are omitted if they are dependencies of others
also mentioned (so omit "all" if "install" is also specified); this
assumes a consistent set of makefiles;

4) where possible, making a later target (say "install", "package", or
whatever) in a directory should be able to do everything necessary
from clean source, where things like external libraries are already in
place;

5) directory visit order is specified using appropriate targets to
make sure things like external libraries are available.

My environment had the advantage of being written in one place and
time.  Although the stuff built was heterogeneous (C, C++, java,
shell) x (user space, kernel modules) x (Solaris, Tru64, 2 Linuxes),
it was still not as hugely varied as the stuff in pkgsrc.

I also experimented with scons as a way of reducing the build problem
to one without recursion.  Peter Miller's "Recursive Make Considered
Harmful" is also worth reading.

With pkgsrc, the (sub)directory recursion is mostly replaced by "oh, I
need to do that other pkg before I can do this one", and the number of
useful pkg-level targets for this is accordingly reduced.  Reducing
the number of different targets used by repeated invocations of make
(or equivalent) in the same directory is highly desirable.  Repeated
invocations with different environments, variable settings, or other
tweaks is particularly objectionable.

Of course, pkgsrc also has a huge amount of configurability and
inter-package dependencies, which make the whole thing Hard To Do.

>I have some changes in work which already improve bsd.pkg.mk build time
>appreciably, especially on platforms where fork() is not cheap.  It's not
>just fork(), though; it takes nonzero time for make to go reparse and
>recalculate everything it just finished calculating in the package Makefile
>the last time through.

>  To accomplish this, I plan to add bits to bsd.pkg.mk to detect the
>  "maximum phase" of the package build requested by the user, so that
>  anything previously needing PKG_PHASE can simply check if a certain phase
>  *would* be executed in the current make instance.  This should provide
>  equivalent functionality all within a single make invocation.

This also requires that a later target can actually make earlier stuff
happen, at least for its own directory and descendants, rather than
just assuming somebody else has already done it.

Best wishes.

-- 
Christopher Vance