At this point we've pretty much covered everything needed to implement reference builds. Customizing the single top-level makefile to support the feature is straightforward. Simply replace the simple assignments to SOURCE_DIR and BINARY_DIR with ?= assignments. The scripts you run from cron can use this basic approach:
Redirect output and set the names of log files
Clean up old builds and clean the reference source tree
Set the source and binary directory variables
Compute tags files, and possibly update the locate database 
 The locate database is a compilation of all the filenames present on a filesystem. It is a fast way of performing a find by name . I have found this database invaluable for managing large source trees and like to have it updated nightly after the build has completed.
Post information on the success or failure of the build
It is convenient , in the reference build model, to maintain a set of old builds in case a rogue check-in corrupts the tree. I usually keep 7 or 14 nightly builds. Of course, the nightly build script logs its output to files stored near the builds themselves and the script purges old builds and logs. Scanning the logs for errors is usually done with an awk script. Finally, I usually have the script maintain a latest symbolic link. To determine if the build is valid, I include a validate target in each makefile . This target performs simple validation that the targets were built.
.PHONY: validate_build validate_build: test $(foreach f,$(RELEASE_FILES),-s $f -a) -e .
This command script simply tests if a set of expected files exists and is not empty. Of course, this doesn't take the place of testing, but is a convenient sanity check for a build. If the test returns failure, the make returns failure and the nightly build script can leave the latest symbolic link pointing to the old build.
Third-party libraries are always a bit of a hassle to manage. I subscribe to the commonly held belief that it is bad to store large binary files in CVS. This is because CVS cannot store deltas as diffs and the underlying RCS files can grow to enormous size . Very large files in the CVS repository can slow down many common CVS operations, thus affecting all development.
If third-party libraries are not stored in CVS, they must be managed some other way. My current preference is to create a library directory in the reference tree and record the library version number in the directory name, as shown in Figure 8-1.
Figure 8-1. Directory layout for third-party libraries
These directory names are referenced by the makefile :
ORACLE_9011_DIR ?= /reftree/third_party/oracle-188.8.131.52/Ora90 ORACLE_9011_JAR ?= $(ORACLE_9011_DIR)/jdbc/lib/classes12.jar
When the vendor updates its libraries, create a new directory in the reference tree and declare new variables in the makefile . This way the makefile , which is properly maintained with tags and branches, always explicitly reflects the versions being used.
Installers are also a difficult issue. I believe that separating the basic build process from creating the installer image is a good thing. Current installer tools are complex and fragile. Folding them into the (also often complex and fragile) build system yields difficult-to-maintain systems. Instead, the basic build can write its results into a "release" directory that contains all (or most of) the data required by the installer build tool. This tool may be driven from its own makefile that ultimately yields an executable setup image.