Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Chapter7.Extender Manual

Introduction

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.

metatarget

Object that is created from declarations in Jamfiles. May be called with a set of properties to produce concrete targets.

concrete target

Object that corresponds to a file or an action.

jam target

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.

[Warning] Warning

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.

Metatargets

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-targettyped-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

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 specifie 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 to different instance 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, that will 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) ] ;

Generators

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.



[4] This name is historic, and will be eventuall changed to metatarget

[5] This create-then-register pattern is caused by limitations of the Boost.Jam language. Python port is likely to never create duplicate targets.

PrevUpHomeNext