Table of Contents
This section explains how to extend Boost.Build to accomodate your local requirements—primarily to add support for non-standard tools you have. Before we start, be sure you have read and understoon the concept of metatarget, the section called “Concepts”, which is critical to understanding the remaining material.
The current version of Boost.Build has three levels of targets, listed below.
Object that is created from declarations in Jamfiles. May be called with a set of properties to produce concrete targets.
Object that corresponds to a file or an action.
Low-level concrete target that is specific to Boost.Jam build engine. Essentially a string—most often a name of file.
In most cases, you will only have to deal with concrete targets and the process that creates concrete targets from metatargets. Extending metatarget level is rarely required. The jam targets are typically only used inside the command line patterns.
All of the Boost.Jam target-related builtin functions, like
DEPENDS
or ALWAYS
operate on jam
targets. Applying them to metatargets or concrete targets has no
effect.
Metatarget is an object that records information specified in Jamfile, such as metatarget kind, name, sources and properties, and can be called with specific properties to generate concrete targets. At the code level it is represented by an instance of class derived from abstract-target. [4]
The generate method takes the build properties (as an instance of the property-set class) and returns a list containing:
As front element—Usage-requirements from this invocation (an instance of property-set)
As subsequent elements—created concrete targets (
instances of the virtual-target
class.)
It's possible to lookup a metataget by target-id using the
targets.resolve-reference
function, and the
targets.generate-from-reference
function can both
lookup and generate a metatarget.
The abstract-target class has three immediate derived classes:
project-target that corresponds to a project and is not intended for further subclassing. The generate method of this class builds all targets in the project that are not marked as explicit.
main-target corresponds to a target in a project and contains one or more target alternatives. This class also should not be subclassed. The generate method of this class selects an alternative to build, and calls the generate method of that alternative.
basic-target corresponds to a specific target alternative. This is base class, with a number of derived classes. The generate method processes the target requirements and requested build properties to determine final properties for the target, builds all sources, and finally calls the abstract construct method with the list of source virtual targets, and the final properties.
The instances of the project-target and
main-target classes are created
implicitly—when loading a new Jamfiles, or when a new target
alternative with as-yet unknown name is created. The instances of the
classes derived from basic-target
are typically created when Jamfile calls a metatarget rule,
such as such as exe
.
It it permissible to create a custom class derived from basic-target and create new metatarget rule that creates instance of such target. However, in the majority of cases, a specific subclass of basic-target— typed-target is used. That class is associated with a type and relays to generators to construct concrete targets of that type. This process will be explained below. When a new type is declared, a new metatarget rule is automatically defined. That rule creates new instance of type-target, associated with that type.
Concrete targets are represented by instance of classes derived
from virtual-target
. The most commonly used
subclass is file-target
. A file target is associated
with an action that creates it— an instance of the action
class. The action, in turn, hold a list of source targets. It also holds the
property-set
instance with the build properties that should be used for the action.
Here's an example of creating a target from another target, source
local a = [ new action $(source) : common.copy : $(property-set) ] ; local t = [ new file-target $(name) : CPP : $(project) : $(a) ] ;
The first line creates an instance of the action
class.
The first parameter is the list of sources. The second parameter is the name
a jam-level action.
The third parameter is the property-set applying to this action. The second line
creates a target. We specify a name, a type and a project. We also pass the
action object created earlier. If the action creates several targets, we can repeat
the second line several times.
In some cases, code that creates concrete targets may be invoked more than
once with the same properties. Returning two different instances of file-target
that correspond to the same file clearly will result in problems. Therefore, whenever
returning targets you should pass them via the virtual-target.register
function, besides allowing Boost.Build to track which virtual targets
got created for each metatarget, this will also replace targets with previously created identical
ones, as necessary.[5]
Here are a couple of examples:
return [ virtual-target.register $(t) ] ; return [ sequence.transform virtual-target.register : $(targets) ] ;
In theory, every kind of metatarget in Boost.Build (like exe
,
lib
or obj
) could be implemented
by writing a new metatarget class that, independently of the other code, figures
what files to produce and what commands to use. However, that would be rather inflexible.
For example, adding support for a new compiler would require editing several metatargets.
In practice, most files have specific types, and most tools consume and produce files of specific type. To take advantage of this fact, Boost.Build defines concept of target type and generators, and has special metatarget class typed-target. Target type is merely an identifier. It is associated with a set of file extensions that correspond to that type. Generator is an abstraction of a tool. It advertises the types it produces and, if called with a set of input target, tries to construct output targets of the advertised types. Finally, typed-target is associated with specific target type, and relays the generator (or generators) for that type.
A generator is an instance of a class derived from generator
.
The generator
class itself is suitable for common cases.
You can define derived classes for custom scenarios.