The build layer

| Home | Libraries | People | FAQ | More

## The build layer

The build layer has just four main parts -- abstract targets, virtual targets, generators and properties. The abstract targets, represented by the "abstract-target" class, correspond to main targets -- which, as you recall, can produce different files depending on properties. Virtual targets, represented by the 'virtual-target' class correspond to real files. The abstract-target class has a method 'generate', which is given a set of properties and produces virtual targets for those properties.

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.

Generators are Boost.Build abstractions for a tool. For example, one can register a generator which converts target of type CPP into target of type OBJ. When run with on a virtual target with CPP type, the generator will construct the virtual target of type OBJ. The "generators" module implements an algorithm, which given a list of sources, the desired type and a list of properties, find all the generators which can perform the conversion.

The virtual targets which are produces by the main targets form a graph. Targets which are produces from other ones refer to an instance of "action" class, which in turn refers to action's sources, which can further refer to actions. The sources, which are not produces from anything, don't refer to any actions.

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 "virtual-target.actualize" and "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.

When target paths are computed and the commands are set, Boost.Build just gives control to bjam, which controls the execution of commands.