Generators

| Home | Libraries | People | FAQ | More

## Generators

### Warning

The information is this section is likely to be outdated and misleading.

To construct a main target with given properties from sources, it is required to create a dependency graph for that main target, which will also include actions to be run. The algorithm for creating the dependency graph is described here.

The fundamental concept is generator. If encapsulates the notion of build tool and is capable to converting a set of input targets into a set of output targets, with some properties. Generator matches a build tool as closely as possible: it works only when the tool can work with requested properties (for example, msvc compiler can't work when requested toolset is gcc), and should produce exactly the same targets as the tool (for example, if Borland's linker produces additional files with debug information, generator should also).

Given a set of generators, the fundamental operation is to construct a target of a given type, with given properties, from a set of targets. That operation is performed by rule `generators.construct` and the used algorithm is described below.

### Selecting and ranking viable generators

Each generator, in addition to target types that it can produce, have attribute that affects its applicability in particular sitiation. Those attributes are:

1. Required properties, which are properties absolutely necessary for the generator to work. For example, generator encapsulating the gcc compiler would have <toolset>gcc as required property.
2. Optional properties, which increase the generators suitability for a particual build.

Generator's required and optional properties may not include either free or incidental properties. (Allowing this would greatly complicate caching targets).

When trying to construct a target, the first step is to select all possible generators for the requested target type, which required properties are a subset of requested properties. Generators which were already selected up the call stack are excluded. In addition, if any composing generators were selected up the call stack, all other composing generators are ignored (TODO: define composing generators). The found generators are assigned a rank, which is the number of optional properties present in requested properties. Finally, generators with highest rank are selected for futher processing.

### Running generators

When generators are selected, each is run to produce a list of created targets. This list might include targets which are not of requested types, because generators create the same targets as some tool, and tool's behaviour is fixed. (Note: should specify that in some cases we actually want extra targets). If generator fails, it returns an empty list. Generator is free to call 'construct' again, to convert sources to the types it can handle. It also can pass modified properties to 'construct'. However, a generator is not allowed to modify any propagated properties, otherwise when actually consuming properties we might discover that the set of propagated properties is different from what was used for building sources.

For all targets which are not of requested types, we try to convert them to requested type, using a second call to `construct`. This is done in order to support transformation sequences where single source file expands to several later. See this message for details.

### Selecting dependency graph

After all generators are run, it is necessary to decide which of successfull invocation will be taken as final result. At the moment, this is not done. Instead, it is checked whether all successfull generator invocation returned the same target list. Error is issued otherwise.

### Property adjustment

Because target location is determined by the build system, it is sometimes necessary to adjust properties, in order to not break actions. For example, if there's an action which generates a header, say "a_parser.h", and a source file "a.cpp" which includes that file, we must make everything work as if a_parser.h is generated in the same directory where it would be generated without any subvariants.

Correct property adjustment can be done only after all targets are created, so the approach taken is:

1. When dependency graph is constructed, each action can be assigned a rule for property adjustment.

2. When virtual target is actualized, that rule is run and return the final set of properties. At this stage it can use information of all created virtual targets.

In case of quoted includes, no adjustment can give 100% correct results. If target dirs are not changed by build system, quoted includes are searched in "." and then in include path, while angle includes are searched only in include path. When target dirs are changed, we'd want to make quoted includes to be search in "." then in additional dirs and then in the include path and make angle includes be searched in include path, probably with additional paths added at some position. Unless, include path already has "." as the first element, this is not possible. So, either generated headers should not be included with quotes, or first element of include path should be ".", which essentially erases the difference between quoted and angle includes. Note: the only way to get "." as include path into compiler command line is via verbatim compiler option. In all other case, Boost.Build will convert "." into directory where it occurs.

### Transformations cache

Under certain conditions, an attempt is made to cache results of transformation search. First, the sources are replaced with targets with special name and the found target list is stored. Later, when properties, requested type, and source type are the same, the store target list is retrieved and cloned, with appropriate change in names.