Chapter 3. Overview

3.1. Architecture

The heart of SCons is its Build Engine. The SCons Build Engine is a Python module that manages dependencies between external objects such as files or database records. The Build Engine is designed to be interface-neutral and easily embeddable in any software system that needs dependency analysis between updatable objects.

The key parts of the Build Engine architecture are captured in the following quasi-UML diagram:

Figure 3.1. SCons Architecture

SCons Architecture

The point of SCons is to manage dependencies between arbitrary external objects. Consequently, the Build Engine does not restrict or specify the nature of the external objects it manages, but instead relies on subclass of the Node class to interact with the external system or systems (file systems, database management systems) that maintain the objects being examined or updated.

The Build Engine presents to the software system in which it is embedded a Python API for specifying source (input) and target (output) objects, rules for building/updating objects, rules for scanning objects for dependencies, etc. Above its Python API, the Build Engine is completely interface-independent, and can be encapsulated by any other software that supports embedded Python.

Software that chooses to use the Build Engine for dependency management interacts with it through Construction Environments. A Construction Environment consists of a dictionary of environment variables, and one or more associated Scanner objects and Builder objects. The Python API is used to form these associations.

A Scanner object specifies how to examine a type of source object (C source file, database record) for dependency information. A Scanner object may use variables from the associated Construction Environment to modify how it scans an object: specifying a search path for included files, which field in a database record to consult, etc.

A Builder object specifies how to update a type of target object: executable program, object file, database field, etc. Like a Scanner object, a Builder object may use variables from the associated Construction Environment to modify how it builds an object: specifying flags to a compiler, using a different update function, etc.

Scanner and Builder objects will return one or more Node objects that represent external objects. Node objects are the means by which the Build Engine tracks dependencies: A Node may represent a source (input) object that should already exist, or a target (output) object which may be built, or both. The Node class is sub-classed to represent external objects of specific type: files, directories, database fields or records, etc. Because dependency information, however, is tracked by the top-level Node methods and attributes, dependencies can exist between nodes representing different external object types. For example, building a file could be made dependent on the value of a given field in a database record, or a database table could depend on the contents of an external file.

The Build Engine uses a Job class (not displayed) to manage the actual work of updating external target objects: spawning commands to build files, submitting the necessary commands to update a database record, etc. The Job class has sub-classes to handle differences between spawning jobs in parallel and serially.

The Build Engine also uses a Signature class (not displayed) to maintain information about whether an external object is up-to-date. Target objects with out-of-date signatures are updated using the appropriate Builder object.