A feature is a normalized (toolset-independent) aspect of a build configuration, such as whether inlining is enabled. Feature names may not contain the '>' character.
Each feature in a build configuration has one or more associated values. Feature values may not contain the '<', ':', or '=' characters.
A property is a (feature,value) pair, expressed as <feature>value.
A subfeature is a feature which only exists in the presence of its parent feature, and whose identity can be derived (in the context of its parent) from its value.
A value-string is a string of the form value-subvalue1-subvalue2...-subvalueN, where value is a feature value and subvalue1...subvalueN are values of related subfeatures. For example, the properties <toolset>gcc <toolset-version>3.0.1 can be expressed more conscisely using a value-string, as <toolset>gcc-3.0.1.
A property set is a set of properties where no property appears twice, for instance: <toolset>gcc <runtime-link>static.
A property path is a property set whose elements have been joined into a single string separated by slashes. A property path representation of the previous example would be <toolset>gcc/<runtime-link>static.
A build specification is a property set which fully describes the set of features used to build a target.
Each feature has a collection of zero or more of the following attributes. Feature attributes are low-level descriptions of how the build system should interpret a feature's values when they appear in a build request. We also refer to the attributes of properties, so that a incidental property, for example, is one whose feature is has the incidental attribute.
Incidental features are assumed not to affect build products at all. As a consequence, the build system may use the same file for targets whose build specification differs only in incidental features. A feature which controls a compiler's warning level is one example of a likely incidental feature.
Non-incidental features are assumed to affect build products, so the files for targets whose build specification differs in non-incidental features are placed in different directories as described in target paths below.
Features of this kind are propagated to dependencies. That is, if a main target is built using a propagated property, the build systems attempts to use the same property when building any of its dependencies as part of that main target. For instance, when an optimized exectuable is requested, one usually wants it to be linked with optimized libraries. Thus, the <optimization> feature is propagated.
Most features have a finite set of allowed values, and can only take on a single value from that set in a given build specification. Free features, on the other hand, can have several values at a time and each value can be an arbitrary string. For example, it is possible to have several preprocessor symbols defined simultaneously:
<define>NDEBUG=1 <define>HAS_CONFIG_H=1
An optional feature is a feature which is not required to appear in a build specification. Every non-optional non-free feature has a default value which is used when a value for the feature is not otherwise specified, either in a target's requirements or in the user's build request. [A feature's default value is given by the first value listed in the feature's declaration. -- move this elsewhere - dwa]
A symmetric feature's default value is not automatically included in build variants. Normally a feature only generates a subvariant directory when its value differs from the value specified by the build variant, leading to an assymmetric subvariant directory structure for certain values of the feature. A symmetric feature, when relevant to the toolset, always generates a corresponding subvariant directory.
The value of a path feature specifies a path. The path is treated as relative to the directory of Jamfile where path feature is used and is translated appropriately by the build system when the build is invoked from a different directory
Values of implicit features alone identify the feature. For example, a user is not required to write "<toolset>", but can simply write "gcc". Implicit feature names also don't appear in variant paths, although the values do. Thus: bin/gcc/... as opposed to bin/toolset-gcc/.... There should typically be only a few such features, to avoid possible name clashes.
Composite features actually correspond to groups of properties. For example, a build variant is a composite feature. When generating targets from a set of build properties, composite features are recursively expanded and added to the build property set, so rules can find them if neccessary. Non-composite non-free features override components of composite features in a build property set.
See below.
TODO: document active features..
rule feature ( name : allowed-values * : attributes * )A feature's allowed-values may be extended wit The build system will provide high-level rules which define features in terms of valid and useful combinations of attributes.
When the build system tries to generate a target (such as library dependency) matching a given build request, it may find that an exact match isn't possible — for example, the target may impose additonal build requirements. We need to determine whether a buildable version of that target can actually be used.
The build request can originate in many ways: It may come directly from the user's command-line, from a dependency of a main target upon a library, or from a dependency of a target upon an executable used to build that target, for example. For each way, there are different rules whether we can use a given subvariant or not. However we currently only assume linking and therefore use a simple approach described in the following paragraph.
In general, there are many possible situations: a libary which is dependency of a main target and should be linked into it, target which is directly requested on the command line, or build executable which is used in the build process itself. At this moment we use a simple approach.
Two property sets are called link-compatible when targets with those property sets can be used interchangably. In turn, two property sets are link compatible when there's no link-incompatible feature which has different values in those property sets. Whenever requested and actual properties are link-compatible, it's OK. Otherwise, it's an error.
When a target with certain properties is requested, and that target requires some set of properties, it is needed to find the set of properties to use for building. This process is called property refinement and is performed by these rules
bjam's first job upon startup is to load the Jam code which implements the build system. To do this, it searches for a file called "boost-build.jam", first in the invocation directory, then in its parent and so forth up to the filesystem root, and finally in the directories specified by the environment variable BOOST_BUILD_PATH. When found, the file is interpreted, and should specify the build system location by calling the boost-build rule:
rule boost-build ( location ? )If location is a relative path, it is treated as relative to the directory of boost-build.jam. The directory specified by location and directories in BOOST_BUILD_PATH are then searched for a file called bootstrap.jam which is interpreted and is expected to bootstrap the build system. This arrangement allows the build system to work without any command-line or environment variable settings. For example, if the build system files were located in a directory "build-system/" at your project root, you might place a boost-build.jam at the project root containing:
boost-build build-system ;In this case, running bjam anywhere in the project tree will automatically find the build system.
The comamnd line may contain:
borland/<runtime-link>staticMore complex form is used to save typing. For example, instead of
borland/runtime-link=static borland/runtime-link=dynamicone can use
borland/runtime-link=static,dynamicExactly, the convertion from argument to build request elements is performed by (1) splitting the argument at each slash, (2) converting each split part into a set of properties and (3) taking all possible combination of the property sets. Each split part should have the either the form
feature-name=feature-value1[","feature-valueN]*or, in case of implict feature
feature-value1[","feature-valueN;]*and will be converted into property set
<feature-name>feature-value1 .... <feature-name>feature-valueN
target1 debug gcc/runtime-link=dynamic,staticwould cause target called target1 to be rebuild in debug mode, except that for gcc, both dynamically and statically linked binaries would be created.
All of the Boost.Build options start with the "--" prefix. They are described in the following table.
Option | Description |
---|---|
--debug | Enables internal checks. |
--dump-projects | Cause the project structure to be output. |
--help | Access to the online help system. This prints general information on how to use the help system with additional --help* options. |
Boost.Build considers every software it build as organized into projects, each of which corresponds to a single Jamfile. Projects are organized in a hierarchical structure, so each project may have a single parent project and a number of subprojects. (TODO: project root).
For each project, there are several attributes.
Project id is a short way to denote a project, as opposed to the Jamfile's pathname. It is a hierarchical path, unrelated to filesystem, such as "boost/thread". There are two ways to refer to a project using project-id:
Source location specifies the directory where sources for the project are located.
Project requirements are requirements that apply to all the targets in the projects as well as all subprojects.
Default build is the build request that should be used when no build request is specified explicitly.
The default values for those attributes are given in the table below. In order to affect them, Jamfile may call the project rule. The rule has this syntax:
project id : <attributes> ;Here, attributes is a sequence of (attribute-name, attribute-value) pairs. The list of attribute names along with its handling is shown in the table below. For example, it it possible to write:
project tennis : requirements <threading>multi : default-build release ;
Attribute | Name for the 'project' rule | Default value | Handling by the 'project' rule |
---|---|---|---|
Project id | none | none | Assigned from the first parameter of the 'project' rule. It is assumed to denote absolute project id. |
Source location | source-location | The location of jamfile for the project | Sets to the passed value |
Requirements | requirements | The parent's requirements | The parent's requirements are refined with the passed requirement and the result is used as the project requirements. |
Default build | default-build | TODO | Sets to the passed value |
There are three kinds of project relationships.
First is parent-child. This relationship is established implicitly: parent directories of a project are searched, and the first found Jamfile is assumed to define the parent project. The parent-child relationship affects only attribute values for the child project.
Second is build relationship. Some project may request to recursively build other projects. Those project need not be child projects. The build-project rule is used for that:
build-project src ;
The third kind is the 'use' relationship. In means that one project uses targets from another. It is possible to just refer to target in other projects using target id. However, if target id uses project id, it is required that the project id is known. The use-project rule is employed to guarantee that.
use-project ( id : location )It loads the project at the specified location, which makes its project id available in the project which invokes the rule. It is required that the id parameter passed to the use-project rule be equal to the id that the loaded project declared. At this moment, the id paremeter should be absolute project id.
Main target is a named entity which can be build, for example a named executable file. To declare a main target, user invokes some of the main target rules, passing it things like list of source and requirement.
It is possible to have different list of sources for different toolsets, therefore it is possible to invoke main target rules several times for a single main target. For example:
exe a : a_gcc.cpp : <toolset> ; exe a : a.cpp ;Each call to the 'exe' rule defines a new main target alternative for the main target a.exe. In this case, the first alternative will be used for the gcc toolset, while the second alternative will be used in other cases. TODO: document the exact selection method under "Build process" below.
Target identifier is used to denote a target. It is described by the following grammar:
target-id -> project-reference local-target-name project-reference -> [jamfile-location] [ "@" [project-id] ] jamfile-location -> pathname project-id -> pathname local-target-name -> identifierFor example, valid target ids might be:
a lib/b @/boost/thread /home/ghost/build/lr_library@parser/lalr1To map the target id into target, the project where that target is contained is first found:
Target reference is used to specify a source target, and may additionally specify desired properties for that target. It has this syntax:
target-reference -> target-id [ "/" requested-properties ] requested-properties -> property-pathFor example,
exe compiler : compiler.cpp libs/cmdline/<optimization>space ;would cause the version of cmdline library, optimized for space, to be linked in even if the compile executable is build with optimization for speed.
Target reference may have the same form as a pathname, for example lib/a. In order to determine if this is target reference or pathname, it is checked if there's a jamfile in the specified path. If there is one, it is loaded and if the specified target is declared by that project it is used. Otherwise, we just treat the target reference as a file name.
To distinguish targets build with different properties, they are put in different directories. Rules for determining target paths are given below:
For example, we might have these paths:
debug/optimization-off debug/main-target-a
The build works in this way. On startup, the project in the current directory is read. In turn, it may request building of other projects, which will be loaded recursively. Parent projects are also loaded to inherit some of their properties. As the result, a tree of projects is constructed. After that, the build request is constructed from the command line. Then, the steps are:
The dependency graph constructed for each target is build of so called "virtual targets", which do not yet correspond to jam's targets. It is therefore converted to jam's dependency graph which is then build.
Last modified: Aug 15, 2002
© Copyright Vladimir Prus 2002. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided ``as is'' without express or implied warranty, and with no claim as to its suitability for any purpose.