| Home | Libraries | People | FAQ | More

## The build layer

The build layer has just four main parts -- metatargets (abstract targets), virtual targets, generators and properties.

- Metatargets (see the "targets.jam" module) represent all the user-defined entities which can be built. The "meta" prefix signify that they don't really corrspond to files -- depending of build request, they can produce different set of files. Metatargets are created when Jamfiles are loaded. Each metagarget has a `generate` method which is given a property set and produces virtual targets for the passed properties.

- Virtual targets (see the "virtual-targets.jam" module) correspond to the atomic things which can be updated -- most typically files.

- Properties are just (name, value) pairs, specified by the user and describing how the targets should be built. Properties are stored using the `property-set` class.

- Generators are the objects which encapsulate tools -- they can take a list of source virtual targets and produce new virtual targets from them.

The build process includes those steps:

1. Top-level code calls the `generate` method of a metatarget with some properties.

2. The metatarget combines the requested properties with requirements and passes the result, together with the list of sources, to the `generators.construct` function

3. A generator appropriate for the build properties is selected and its `run` method is called. The method returns a list of virtual targets

4. The targets are returned to the top level code. They are converted into bjam targets (via `virtual-target.actualize`) and passed to bjam for building.

### Metatargets

There are several classes derived from "abstract-target". The "main-target" class represents top-level main target, the "project-target" acts like container for all main targets, and "basic-target" class is a base class for all further target types.

Since each main target can have several alternatives, all top-level target objects are just containers, referring to "real" main target classes. The type is that container is "main-target". For example, given:

    alias a ;
    lib a : a.cpp : <toolset>gcc ;

we would have one-top level instance of "main-target-class", which will contain one instance of "alias-target-class" and one instance of "lib-target-class". The "generate" method of "main-target" decides which of the alternative should be used, and call "generate" on the corresponding instance.

Each alternative is a instance of a class derived from "basic-target". The "basic-target.generate" does several things that are always should be done:

- Determines what properties should be used for building the target. This includes looking at requested properties, requirements, and usage requirements of all sources.

- Builds all sources

- Computes the usage requirements which should be passes back.

For the real work of constructing virtual target, a new method "construct" is called.

The "construct" method can be implemented in any way by classes derived from "basic-target", but one specific derived class plays the central role -- "typed-target". That class holds the desired type of file to be produces, and calls the generators modules to do the job.

This means that a specific metatarget subclass may avoid using generators at all. However, this is deprecated and we're trying to eliminate all such subsclasses at the moment.

Note that the `build/targets.jam` file contains an UML diagram which might help.

### Virtual targets

Virtual targets correspond to the atomic things which can be updated. Each virtual target can be assigned an updating action -- instance of the `action` class. The action class, in turn, contains a list of source targets, properties, and a name of bjam action block which should be executed.

We try hard to never create equal instances of the `virtual-target` class. Each code which creates virtual targets passes them though the `virtual-target.register` function, which detects if a target with the same name, sources, and properties was created. In that case, existing target is returned.

When all virtual targets are produced, they are "actualized". This means that the real file names are computed, and the commands that should be run are generated. This is done by the `virtual-target.actualize` method and the `action.actualize` methods. The first is conceptually simple, while the second need additional explanation. The commands in bjam are generated in two-stage process. First, a rule with the appropriate name (for example "gcc.compile") is called and is given the names of targets. The rule sets some variables, like "OPTIONS". After that, the command string is taken, and variable are substitutes, so use of OPTIONS inside the command string become the real compile options.

Boost.Build added a third stage to simplify things. It's now possible to automatically convert properties to appropriate assignments to variables. For example, <debug-symbols>on would add "-g" to the OPTIONS variable, without requiring to manually add this logic to gcc.compile. This functionality is part of the "toolset" module.

Note that the `build/virtual-targets.jam` file contains an UML diagram which might help.

Above, we noted that metatargets are built with a set of properties. That set is represented with the `property-set` class. An important point is that handling of property sets can get very expensive. For that reason, we make sure that for each set of (name, value) pairs only one `property-set` instance is created. The `property-set` uses extensive caching for all operation, so most work is avoided. The `property-set.create` is the factory function which should be used to create instances of the `property-set` class.