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.