Table of Contents
This chapter provides detailed information about the inner workings of parts of abuild. Understanding this material is not essential even for using abuild in an advanced way, but reading it may provide insight into some of the reasons that abuild works the way it does. Understanding this material is essential to anyone who would want to modify any of abuild's core functionality.
There has been some thought and writing about recursive make, and there are various approaches to the problem of make recursion. On one extreme, you can write makefiles that iterate through subdirectories and invoke make recursively for each subdirectory. These are hostile to parallelism and invoke make recursively bounded by the depth of the file system. This use of recursive make is expensive in terms of time and system resources. At the other end of the spectrum, you can create makefiles that include all the other makefiles and effectively create one monolithic makefile for the entire project. These makefiles are fragile and very hard to maintain because you have to make sure that no makefile defines any targets or variables that conflict with those defined by other makefiles, and you have to jump through hoops to make sure that whatever paths are in the makefiles can be resolved properly regardless of the starting directory of the build.
Abuild takes a middle ground. The only files that may be
included in multiple contexts that actually set variables and
contain end-user knowledge are rules files. To make this work,
we provide variables that contain the currently resolved path of
each build item. This is necessary anyway in order to support
backing areas. Abuild then allows users to create
Abuild.mk
files that don't have to coexist
with other Abuild.mk
files at runtime.
Since abuild knows all the dependencies between build items, it
can build items iteratively or even in parallel without using any
recursion at all. Although a monolithic makefile system that is
perfectly constructed would allow arbitrarily complex
dependencies to be declared between specific targets in specific
directories, maintaining this for a system of any size or for a
system that was dynamic would be impractical. Abuild replaces
this with precise management of inter-build item dependencies.
Even so, abuild's make code actually does generate fine-grained
dependencies at the file level, so most of the advantages of the
monolithic non-recursive makefile approach are realized with
abuild. We believe that this achieves the right balance
between granularity and ease of maintenance and makes abuild's
approach robust and efficient for both small and large build
trees.