The directory containing the zlib headers.
If none of these options is specified, then the environmental variables ZLIB_LIBRARY_PATH, ZLIB_NAME, and ZLIB_INCLUDE will be used instead.
Options for building zlib from source:
source
-
The zlib source directory. Defaults to the environmental variable ZLIB_SOURCE.
tag
-
Sets the tag property to adjust the file name of the library. Ignored when using precompiled binaries.
build-name
-
The base name to use for the compiled library. Ignored when using precompiled binaries.
Examples:
# Find zlib in the default system location
using zlib ;
# Build zlib from source
using zlib : 1.2.7 : <source>/home/steven/zlib-1.2.7 ;
# Find zlib in /usr/local
using zlib : 1.2.7 : <include>/usr/local/include <search>/usr/local/lib ;
# Build zlib from source for msvc and find
# prebuilt binaries for gcc.
using zlib : 1.2.7 : <source>C:/Devel/src/zlib-1.2.7 : <toolset>msvc ;
using zlib : 1.2.7 : : <toolset>gcc ;
bzip2
Provides support for the bzip2 library. bzip2 can be configured either to use precompiled binaries or to build the library from source.
bzip2 can be initialized using the following syntax
using bzip2 : version : options : condition : is-default ;
Options for using a prebuilt library:
search
-
The directory containing the bzip2 binaries.
name
-
Overrides the default library name.
include
-
The directory containing the bzip2 headers.
If none of these options is specified, then the environmental variables BZIP2_LIBRARY_PATH, BZIP2_NAME, and BZIP2_INCLUDE will be used instead.
Options for building bzip2 from source:
source
-
The bzip2 source directory. Defaults to the environmental variable BZIP2_SOURCE.
tag
-
Sets the tag property to adjust the file name of the library. Ignored when using precompiled binaries.
build-name
-
The base name to use for the compiled library. Ignored when using precompiled binaries.
Examples:
# Find bzip in the default system location
using bzip2 ;
# Build bzip from source
using bzip2 : 1.0.6 : <source>/home/sergey/src/bzip2-1.0.6 ;
# Find bzip in /usr/local
using bzip2 : 1.0.6 : <include>/usr/local/include <search>/usr/local/lib ;
# Build bzip from source for msvc and find
# prebuilt binaries for gcc.
using bzip2 : 1.0.6 : <source>C:/Devel/src/bzip2-1.0.6 : <toolset>msvc ;
using bzip2 : 1.0.6 : : <toolset>gcc ;
Python
Provides support for the python language environment to be linked in as a library.
python can be initialized using the following syntax
using python : [version] : [command-or-prefix] : [includes] : [libraries] : [conditions] : [extension-suffix] ;
Options for using python:
version
-
The version of Python to use. Should be in Major.Minor format, for example 2.3. Do not include the sub-minor version.
command-or-prefix
-
Preferably, a command that invokes a Python interpreter. Alternatively, the installation prefix for Python libraries and includes. If empty, will be guessed from the version, the platform’s installation patterns, and the python executables that can be found in PATH.
includes
-
the include path to Python headers. If empty, will be guessed.
libraries
-
the path to Python library binaries. If empty, will be guessed. On MacOS/Darwin, you can also pass the path of the Python framework.
conditions
-
if specified, should be a set of properties that are matched against the build configuration when B2 selects a Python configuration to use.
extension-suffix
-
A string to append to the name of extension modules before the true filename extension. Ordinarily we would just compute this based on the value of the
<python-debugging>
feature. However ubuntu’spython-dbg
package uses the windows convention of appending _d to debug-build extension modules. We have no way of detecting ubuntu, or of probing python for the "_d" requirement, and if you configure and build python using--with-pydebug
, you’ll be using the standard *nix convention. Defaults to "" (or "_d" when targeting windows and <python-debugging> is set).
Examples:
# Find python in the default system location
using python ;
# 2.7
using python : 2.7 ;
# 3.5
using python : 3.5 ;
# On ubuntu 16.04
using python
: 2.7 # version
: # Interpreter/path to dir
: /usr/include/python2.7 # includes
: /usr/lib/x86_64-linux-gnu # libs
: # conditions
;
using python
: 3.5 # version
: # Interpreter/path to dir
: /usr/include/python3.5 # includes
: /usr/lib/x86_64-linux-gnu # libs
: # conditions
;
# On windows
using python
: 2.7 # version
: C:\\Python27-32\\python.exe # Interperter/path to dir
: C:\\Python27-32\\include # includes
: C:\\Python27-32\\libs # libs
: <address-model>32 <address-model> # conditions - both 32 and unspecified
;
using python
: 2.7 # version
: C:\\Python27-64\\python.exe # Interperter/path to dir
: C:\\Python27-64\\include # includes
: C:\\Python27-64\\libs # libs
: <address-model>64 # conditions
;
6.4.3. Documentation tools
B2 support for the Boost documentation tools is documented below.
xsltproc
To use xsltproc, you first need to configure it using the following syntax:
using xsltproc : xsltproc ;
Where xsltproc is the xsltproc executable. If xsltproc is not specified, and the variable XSLTPROC is set, the value of XSLTPROC will be used. Otherwise, xsltproc will be searched for in PATH.
The following options can be provided, using `<option-name>option-value syntax`:
xsl:param
-
Values should have the form name=value
xsl:path
-
Sets an additional search path for xi:include elements.
catalog
-
A catalog file used to rewrite remote URL’s to a local copy.
The xsltproc module provides the following rules. Note that these operate on jam targets and are intended to be used by another toolset, such as boostbook, rather than directly by users.
xslt
-
rule xslt ( target : source stylesheet : properties * )
Runs xsltproc to create a single output file.
xslt-dir
-
rule xslt-dir ( target : source stylesheet : properties * : dirname )
Runs xsltproc to create multiple outputs in a directory.
dirname
is unused, but exists for historical reasons. The output directory is determined from the target.
boostbook
To use boostbook, you first need to configure it using the following syntax:
using boostbook : docbook-xsl-dir : docbook-dtd-dir : boostbook-dir ;
docbook-xsl-dir
is the DocBook XSL stylesheet directory. If not
provided, we use DOCBOOK_XSL_DIR
from the environment (if available) or
look in standard locations. Otherwise, we let the XML processor load the
stylesheets remotely.
docbook-dtd-dir
is the DocBook DTD directory. If not provided, we use
DOCBOOK_DTD_DIR
From the environment (if available) or look in standard
locations. Otherwise, we let the XML processor load the DTD remotely.
boostbook-dir
is the BoostBook directory with the DTD and XSL sub-dirs.
The boostbook module depends on xsltproc. For pdf or ps output, it also depends on fop.
The following options can be provided, using `<option-name>option-value syntax`:
format
-
Allowed values:
html
,xhtml
,htmlhelp
,onehtml
,man
,pdf
,ps
,docbook
,fo
,tests
.The
format
feature determines the type of output produced by the boostbook rule.
The boostbook module defines a rule for creating a target following the common syntax.
boostbook
-
rule boostbook ( target-name : sources * : requirements * : default-build * )
Creates a boostbook target.
doxygen
To use doxygen, you first need to configure it using the following syntax:
using doxygen : name ;
name
is the doxygen command. If it is not specified, it will be found in
the PATH.
The doxygen module depends on the boostbook module when generating BoostBook XML.
The following options can be provided, using `<option-name>option-value syntax`:
doxygen:param
-
All the values of
doxygen:param
are added to thedoxyfile
. prefix
-
Specifies the common prefix of all headers when generating BoostBook XML. Everything before this will be stripped off.
reftitle
-
Specifies the title of the library-reference section, when generating BoostBook XML.
doxygen:xml-imagedir
-
When generating BoostBook XML, specifies the directory in which to place the images generated from LaTex formulae.
⚠The path is interpreted relative to the current working directory, not relative to the Jamfile. This is necessary to match the behavior of BoostBook.
The doxygen module defines a rule for creating a target following the common syntax.
doxygen
-
rule doxygen ( target : sources * : requirements * : default-build * : usage-requirements * )
Creates a doxygen target. If the target name ends with .html, then this will generate an html directory. Otherwise it will generate BoostBook XML.
quickbook
The quickbook module provides a generator to convert from Quickbook to BoostBook XML.
To use quickbook, you first need to configure it using the following syntax:
using quickbook : command ;
command
is the quickbook executable. If it is not specified, B2
will compile it from source. If it is unable to find the source it will
search for a quickbook executable in PATH.
fop
The fop module provides generators to convert from XSL formatting objects to Postscript and PDF.
To use fop, you first need to configure it using the following syntax:
using fop : fop-command : java-home : java ;
fop-command
is the command to run fop. If it is not specified,
B2 will search for it in PATH and FOP_HOME.
Either java-home
or java
can be used to specify where to find java.
6.5. Builtin modules
This section describes the modules that are provided by B2. The import rule allows rules from one module to be used in another module or Jamfile.
6.5.1. modules
The modules
module defines basic functionality for handling modules.
A module defines a number of rules that can be used in other modules. Modules can contain code at the top level to initialize the module. This code is executed the first time the module is loaded.
|
ℹ
|
A Jamfile is a special kind of module which is managed by the build system. Although they cannot be loaded directly by users, the other features of modules are still useful for Jamfiles. |
Each module has its own namespaces for variables and rules. If two modules A and B both use a variable named X, each one gets its own copy of X. They won’t interfere with each other in any way. Similarly, importing rules into one module has no effect on any other module.
Every module has two special variables. $(file)
contains the name
of the file that the module was loaded from and $(name)
contains
the name of the module.
|
ℹ
|
$(file) does not contain the full path to the file. If you need
this, use modules.binding .
|
-
rule binding ( module-name )
Returns the filesystem binding of the given module.
For example, a module can get its own location with:
me = [ modules.binding $(__name__) ] ;
-
rule poke ( module-name ? : variables + : value * )
Sets the module-local value of a variable.
For example, to set a variable in the global module:
modules.poke : ZLIB_INCLUDE : /usr/local/include ;
-
rule peek ( module-name ? : variables + )
Returns the module-local value of a variable.
For example, to read a variable from the global module:
local ZLIB_INCLUDE = [ modules.peek : ZLIB_INCLUDE ] ;
-
rule call-in ( module-name ? : rule-name args * : * )
Call the given rule locally in the given module. Use this for rules accepting rule names as arguments, so that the passed rule may be invoked in the context of the rule’s caller (for example, if the rule accesses module globals or is a local rule).
ℹrules called this way may accept at most 8 parameters. Example:
rule filter ( f : values * ) { local m = [ CALLER_MODULE ] ; local result ; for v in $(values) { if [ modules.call-in $(m) : $(f) $(v) ] { result += $(v) ; } } return result ; }
-
rule load ( module-name : filename ? : search * )
Load the indicated module if it is not already loaded.
module-name
-
Name of module to load.
filename
-
(partial) path to file; Defaults to
$(module-name).jam
search
-
Directories in which to search for filename. Defaults to
$(BOOST_BUILD_PATH)
.
-
rule import ( module-names + : rules-opt * : rename-opt * )
Load the indicated module and import rule names into the current module. Any members of
rules-opt
will be available without qualification in the caller’s module. Any members ofrename-opt
will be taken as the names of the rules in the caller’s module, in place of the names they have in the imported module. Ifrules-opt = '*'
, all rules from the indicated module are imported into the caller’s module. Ifrename-opt
is supplied, it must have the same number of elements asrules-opt
.ℹThe import
rule is available without qualification in all modules.Examples:
import path ; import path : * ; import path : join ; import path : native make : native-path make-path ;
-
rule clone-rules ( source-module target-module )
Define exported copies in
$(target-module)
of all rules exported from$(source-module)
. Also make them available in the global module with qualification, so that it is just as though the rules were defined originally in$(target-module)
.
6.5.2. path
Performs various path manipulations. Paths are always in a 'normalized' representation. In it, a path may be either:
-
'.'
, or -
['/'] [ ( '..' '/' )* (token '/')* token ]
In plain english, a path can be rooted, '..'
elements are allowed only
at the beginning, and it never ends in slash, except for the path
consisting of slash only.
-
Converts the native path into normalized form.
-
Builds the native representation of the path.
-
Tests if a path is rooted.
-
Tests if a path has a parent.
-
Returns the path without any directory components.
-
Returns the parent directory of the path. If no parent exists, an error is issued.
-
Returns
path2
such that[ join path path2 ] = "."
. The path may not contain".."
element or be rooted. -
Concatenates the passed path elements. Generates an error if any element other than the first one is rooted. Skips any empty or undefined path elements.
-
If
path
is relative, it is rooted atroot
. Otherwise, it is unchanged. -
Returns the current working directory.
-
rule glob ( dirs * : patterns + : exclude-patterns * )
Returns the list of files matching the given pattern in the specified directory. Both directories and patterns are supplied as portable paths. Each pattern should be a non-absolute path, and can’t contain "." or ".." elements. Each slash separated element of a pattern can contain the following special characters:
-
'?' matches any character
-
'*' matches an arbitrary number of characters
A file
$(d)/e1/e2/e3
(where 'd' is in$(dirs)
) matches the pattern p1/p2/p3 if and only if e1 matches p1, e2 matches p2 and so on. For example:[ glob . : *.cpp ] [ glob . : */build/Jamfile ]
-
-
rule glob-tree ( roots * : patterns + : exclude-patterns * )
Recursive version of glob. Builds the glob of files while also searching in the subdirectories of the given roots. An optional set of exclusion patterns will filter out the matching entries from the result. The exclusions also apply to the subdirectory scanning, such that directories that match the exclusion patterns will not be searched.
-
Returns true if the specified file exists.
-
rule all-parents ( path : upper_limit ? : cwd ? )
Find out the absolute name of path and return the list of all the parents, starting with the immediate one. Parents are returned as relative names. If
upper_limit
is specified, directories above it will be pruned. -
rule glob-in-parents ( dir : patterns + : upper-limit ? )
Search for
patterns
in parent directories ofdir
, up to and includingupper_limit
, if it is specified, or till the filesystem root otherwise. -
rule relative ( child parent : no-error ? )
Assuming
child
is a subdirectory ofparent
, return the relative path fromparent
tochild
. -
rule relative-to ( path1 path2 )
Returns the minimal path to path2 that is relative path1.
-
Returns the list of paths which are used by the operating system for looking up programs.
-
Creates a directory and all parent directories that do not already exist.
6.5.3. regex
Contains rules for string processing using regular expressions.
-
"x*"
matches the pattern"x"
zero or more times. -
"x+"
matches"x"
one or more times. -
"x?"
matches"x"
zero or one time. -
"[abcd]"
matches any of the characters,"a"
,"b"
,"c"
, and"d"
. A character range such as"[a-z]"
matches any character between"a"
and"z"
."[^abc]"
matches any character which is not"a"
,"b"
, or"c"
. -
"x|y"
matches either pattern"x"
or pattern"y"
-
(x)
matches"x"
and captures it. -
"^"
matches the beginning of the string. -
"$"
matches the end of the string. -
"\<" matches the beginning of a word.
-
"\>" matches the end of a word.
-
rule split ( string separator )
Returns a list of the following substrings:
-
from beginning till the first occurrence of
separator
or till the end, -
between each occurrence of
separator
and the next occurrence, -
from the last occurrence of
separator
till the end.If no separator is present, the result will contain only one element.
-
-
rule split-list ( list * : separator )
Returns the concatenated results of applying regex.split to every element of the list using the separator pattern.
-
rule match ( pattern : string : indices * )
Match
string
againstpattern
, and return the elements indicated byindices
. -
rule transform ( list * : pattern : indices * )
Matches all elements of
list
against thepattern
and returns a list of elements indicated byindices
of all successful matches. Ifindices
is omitted returns a list of first parenthesized groups of all successful matches. -
rule escape ( string : symbols : escape-symbol )
Escapes all of the characters in
symbols
using the escape symbolescape-symbol
for the given string, and returns the escaped string. -
rule replace ( string match replacement )
Replaces occurrences of a match string in a given string and returns the new string. The match string can be a regex expression.
-
rule replace-list ( list * : match : replacement )
Replaces occurrences of a match string in a given list of strings and returns a list of new strings. The match string can be a regex expression.
-
See also: MATCH
6.5.4. sequence
Various useful list functions. Note that algorithms in this module execute largely in the caller’s module namespace, so that local rules can be used as function objects. Also note that most predicates can be multi-element lists. In that case, all but the first element are prepended to the first argument which is passed to the rule named by the first element.
-
rule filter ( predicate + : sequence * )
Return the elements
e
of$(sequence)
for which[ $(predicate) e ]
has a non-null value. -
rule transform ( function + : sequence * )
Return a new sequence consisting of
[ $(function) $(e) ]
for each elemente
of$(sequence)
. -
rule reverse ( s * )
Returns the elements of
s
in reverse order. -
rule insertion-sort ( s * : ordered * )
Insertion-sort
s
using the BinaryPredicateordered
. -
rule merge ( s1 * : s2 * : ordered * )
Merge two ordered sequences using the BinaryPredicate
ordered
. -
rule join ( s * : joint ? )
Join the elements of
s
into one long string. Ifjoint
is supplied, it is used as a separator. -
rule length ( s * )
Find the length of any sequence.
-
rule unique ( list * : stable ? )
Removes duplicates from
list
. Ifstable
is passed, then the order of the elements will be unchanged. -
rule max-element ( elements + : ordered ? )
Returns the maximum number in
elements
. Usesordered
for comparisons ornumbers.less
if none is provided. -
rule select-highest-ranked ( elements * : ranks * )
Returns all of
elements
for which the corresponding element in the parallel listrank
is equal to the maximum value inrank
.
6.5.5. stage
This module defines the install
rule, used to copy a set of targets to a
single location.
-
rule add-install-dir ( name : suffix ? : parent ? : options * )
Defines a named installation directory.
For example,
add-install-dir foo : bar : baz ;
creates feature<install-foo>
and adds support for named directory(foo)
toinstall
rule. The rule will try to use the value of<install-foo>
property if present, otherwise will fallback to(baz)/bar
.Arguments:
-
name
: the name of the directory. -
suffix
: the path suffix appended to the parent named directory. -
parent
: the optional name of parent named directory. -
options
: special options that modify treatment of the directory. Allowed options:-
package-suffix
: append the package name to the default value. For example:add-install-dir foo : bar : baz : package-suffix ; install (foo) : a : <install-package>xyz ;
installs
a
into(baz)/bar/xyz
.
-
-
-
rule install-dir-names ( )
Returns names of all registered installation directories.
-
rule get-dir ( name : property-set : package-name : flags * )
Returns the path to a named installation directory. For a given
name=xyz
the rule uses the value of<install-xyz>
property if it is present inproperty-set
. Otherwise it tries to construct the default value of the path recursively getting the path toname
's registered base named directory and relative path. For example:stage.add-install-dir foo : bar : baz ; local ps = [ property-set.create <install-foo>x/y/z ] ; echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs x/y/z ps = [ property-set.create <install-baz>a/b/c/d ] ; echo [ stage.get-dir foo : $(ps) : $(__name__) ] ; # outputs a/b/c/d/bar
The argument
package-name
is used to construct the path for named directories that were registered withpackage-suffix
option and also to constructinstall-prefix
when targeting Windows.Available
flags
:-
staged
: takestaging-prefix
into account. -
relative
: return the path toname
relative to its base directory.
-
-
rule get-package-name ( property-set : project-module ? )
Returns the package name that will be used for
install
targets when constructing installation location. The rule uses the value of<install-package>
property if it’s present inproperty-set
. Otherwise it deduces the package name usingproject-module
's attributes. It traverses the project hierarchy up to the root searching for the first project with an id. If none is found, the base name of the root project’s location is used. Ifproject-module
is empty, the caller module is used (this allows invoking just[ get-package-name $(ps) ]
in project jam files).
6.5.6. type
Deals with target type declaration and defines target class which supports typed targets.
-
rule register ( type : suffixes * : base-type ? )
Registers a target type, possible derived from a
base-type
. Providing a list of suffixes here is a shortcut for separately calling the register-suffixes rule with the given suffixes and the set-generated-target-suffix rule with the first given suffix. -
rule register-suffixes ( suffixes + : type )
Specifies that files with suffix from
suffixes
be recognized as targets of typetype
. Issues an error if a different type is already specified for any of the suffixes. -
Returns true iff type has been registered.
-
Issues an error if
type
is unknown. -
rule set-scanner ( type : scanner )
Sets a scanner class that will be used for this type.
-
rule get-scanner ( type : property-set )
Returns a scanner instance appropriate to
type
andproperty-set
. -
Returns a base type for the given type or nothing in case the given type is not derived.
-
Returns the given type and all of its base types in order of their distance from type.
-
Returns the given type and all of its derived types in order of their distance from type.
-
Returns true if
type
is equal tobase
or hasbase
as its direct or indirect base. -
rule set-generated-target-suffix ( type : properties * : suffix )
Sets a file suffix to be used when generating a target of
type
with the specified properties. Can be called with no properties if no suffix has already been specified for thetype
. Thesuffix
parameter can be an empty string (""
) to indicate that no suffix should be used.Note that this does not cause files with
suffix
to be automatically recognized as being oftype
. Two different types can use the same suffix for their generated files but only one type can be auto-detected for a file with that suffix. User should explicitly specify which one using the register-suffixes rule. -
rule change-generated-target-suffix ( type : properties * : suffix )
Change the suffix previously registered for this type/properties combination. If suffix is not yet specified, sets it.
-
rule generated-target-suffix ( type : property-set )
Returns the suffix used when generating a file of
type
with the given properties. -
rule set-generated-target-prefix ( type : properties * : prefix )
Sets a target prefix that should be used when generating targets of
type
with the specified properties. Can be called with empty properties if no prefix fortype
has been specified yet.The
prefix
parameter can be empty string (""
) to indicate that no prefix should be used.Usage example: library names use the
"lib"
prefix on unix. -
rule change-generated-target-prefix ( type : properties * : prefix )
Change the prefix previously registered for this type/properties combination. If prefix is not yet specified, sets it.
-
rule generated-target-prefix ( type : property-set )
Returns the prefix used when generating a file of
type
with the given properties. -
Returns file type given its name. If there are several dots in filename, tries each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and "so" will be tried.
6.6. Builtin classes
6.6.1. Class abstract-target
Base class for all abstract targets.
class abstract-target {
rule __init__ ( name : project )
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
rule generate ( property-set )
}
Classes derived from abstract-target:
-
project-target
-
main-target
-
basic-target
-
rule init ( name : project )
name
-
The name of the target in the Jamfile.
project
-
The project to which this target belongs.
-
rule name ( )
Returns the name of this target.
-
rule project ( )
Returns the project for this target.
-
rule location ( )
Returns the location where the target was declared.
-
rule full-name ( )
Returns a user-readable name for this target.
-
rule generate ( property-set )
Generates virtual targets for this abstract target using the specified properties, unless a different value of some feature is required by the target. This is an abstract method which must be overridden by derived classes.
On success, returns:
-
a property-set with the usage requirements to be applied to dependents
-
a list of produced virtual targets, which may be empty.
If
property-set
is empty, performs the default build of this target, in a way specific to the derived class.
-
6.6.2. Class project-target
class project-target : abstract-target {
rule generate ( property-set )
rule build-dir ( )
rule main-target ( name )
rule has-main-target ( name )
rule find ( id : no-error ? )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
}
This class has the following responsibilities:
-
Maintaining a list of main targets in this project and building them.
-
rule generate ( property-set )
Overrides abstract-target.generate. Generates virtual targets for all the targets contained in this project.
On success, returns:
-
a property-set with the usage requirements to be applied to dependents
-
a list of produced virtual targets, which may be empty.
-
-
rule build-dir ( )
Returns the root build directory of the project.
-
rule main-target ( name )
Returns a main-target class instance corresponding to
name
. Can only be called after the project has been fully loaded. -
rule has-main-target ( name )
Returns whether a main-target with the specified name exists. Can only be called after the project has been fully loaded.
-
rule find ( id : no-error ? )
Find and return the target with the specified id, treated relative to self. Id may specify either a target or a file name with the target taking priority. May report an error or return nothing if the target is not found depending on the
no-error
parameter.
6.6.3. Class main-target
class main-target : abstract-target {
rule generate ( property-set )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
}
A main-target represents a named top-level target in a Jamfile.
-
rule generate ( property-set )
Overrides abstract-target.generate. Select an alternative for this main target, by finding all alternatives whose requirements are satisfied by
property-set
and picking the one with the longest requirements set. Returns the result of calling generate on that alternative.On success, returns:
-
a property-set with the usage requirements to be applied to dependents
-
a list of produced virtual targets, which may be empty.
-
6.6.4. Class basic-target
class basic-target : abstract-target {
rule __init__ ( name : project : sources * : requirements * : default-build * : usage-requirements * )
rule generate ( property-set )
rule construct ( name : source-targets * : property-set )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
}
Implements the most standard way of constructing main target alternative from sources. Allows sources to be either files or other main targets and handles generation of those dependency targets.
-
rule init ( name : project : sources * : requirements * : default-build * : usage-requirements * )
name
-
The name of the target
project
-
The project in which the target is declared.
-
rule generate ( property-set )
Overrides abstract-target.generate. Determines final build properties, generates sources, and calls construct. This method should not be overridden.
On success, returns:
-
a property-set with the usage requirements to be applied to dependents
-
a list of produced virtual targets, which may be empty.
-
-
rule construct ( name : source-targets * : property-set )
Constructs virtual targets for this abstract target. Returns a usage-requirements property-set and a list of virtual targets. Should be overridden in derived classes.
6.6.5. Class typed-target
class typed-target : basic-target {
rule __init__ ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )
rule type ( )
rule construct ( name : source-targets * : property-set )
# Methods inherited from abstract-target
rule name ( )
rule project ( )
rule location ( )
rule full-name ( )
# Methods inherited from basic-target
rule generate ( property-set )
}
typed-target is the most common kind of target alternative. Rules for creating typed targets are defined automatically for each type.
-
rule init ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )
-
rule type ( )
Returns the type of the target.
-
rule construct ( name : source-targets * : property-set )
Implements basic-target.construct. Attempts to create a target of the correct type using generators appropriate for the given property-set. Returns a property-set containing the usage requirements and a list of virtual targets.
ℹThis function is invoked automatically by basic-target.generate and should not be called directly by users.
6.6.6. Class property-set
Class for storing a set of properties.
class property-set {
rule raw ( )
rule str ( )
rule propagated ( )
rule add ( ps )
rule add-raw ( properties * )
rule refine ( ps )
rule get ( feature )
}
There is 1<→1 correspondence between identity and value. No two instances of the class are equal. To maintain this property, the 'property-set.create' rule should be used to create new instances. Instances are immutable.
-
rule raw ( )
Returns a Jam list of the stored properties.
-
rule str ( )
Returns the string representation of the stored properties.
-
rule propagated ( )
Returns a property-set containing all the propagated properties in this property-set.
-
Returns a new property-set containing the union of the properties in this property-set and in
ps
.ℹIf ps
contains non-free properties that should override the values in this object, use refine instead. -
rule add-raw ( properties * )
Link add, except that it takes a list of properties instead of a property-set.
-
Refines properties by overriding any non-free and non-conditional properties for which a different value is specified in
ps
. Returns the resulting property-set. -
rule get ( feature )
Returns all the values of
feature
.
6.7. Build process
The general overview of the build process was given in the user documentation. This section provides additional details, and some specific rules.
To recap, building a target with specific properties includes the following steps:
-
applying the default build,
-
selecting the main target alternative to use,
-
determining the "common" properties,
-
building targets referred by the the sources list and dependency properties,
-
adding the usage requirements produced when building dependencies to the "common" properties,
-
building the target using generators,
-
computing the usage requirements to be returned.
6.7.1. Alternative selection
When a target has several alternatives, one of them must be selected. The process is as follows:
-
For each alternative, its condition is defined as the set of base properties in its requirements. Conditional properties are excluded.
-
An alternative is viable only if all properties in its condition are present in the build request.
-
If there’s only one viable alternative, it’s chosen. Otherwise, an attempt is made to find the best alternative. An alternative a is better than another alternative b, if the set of properties in b’s condition is a strict subset of the set of properties of a’s condition. If one viable alternative is better than all the others, it’s selected. Otherwise, an error is reported.
6.7.2. Determining common properties
"Common" properties is a somewhat artificial term. This is the intermediate property set from which both the build request for dependencies and the properties for building the target are derived.
Since the default build and alternatives are already handled, we have only two inputs: the build request and the requirements. Here are the rules about common properties.
-
Non-free features can have only one value
-
A non-conditional property in the requirements is always present in common properties.
-
A property in the build request is present in common properties, unless it is overridden by a property in the requirements.
-
If either the build request, or the requirements (non-conditional or conditional) include an expandable property (either composite, or with a specified sub-feature value), the behavior is equivalent to explicitly adding all the expanded properties to the build request or the requirements respectively.
-
If the requirements include a conditional property, and the condition of this property is true in the context of common properties, then the conditional property should be in common properties as well.
-
If no value for a feature is given by other rules here, it has default value in common properties.
These rules are declarative. They don’t specify how to compute the common properties. However, they provide enough information for the user. The important point is the handling of conditional requirements. The condition can be satisfied either by a property in the build request, by non-conditional requirements, or even by another conditional property. For example, the following example works as expected:
exe a : a.cpp
: <toolset>gcc:<variant>release
<variant>release:<define>FOO ;
6.7.3. Target Paths
Several factors determine the location of a concrete file target. All
files in a project are built under the directory bin unless this is
overridden by the build-dir project attribute. Under bin is a path that
depends on the properties used to build each target. This path is
uniquely determined by all non-free, non-incidental properties. For
example, given a property set containing: <toolset>gcc
<toolset-gcc:version>4.6.1
<variant>debug
<warnings>all
<define>_DEBUG
<include>/usr/local/include
<link>static
, the path will be
gcc-4.6.1/debug/link-static
. <warnings>
is an incidental feature and
<define>
and <include>
are free features, so they do not affect the path.
Sometimes the paths produced by B2 can become excessively long.
There are a couple of command line options that can help with this.
--abbreviate-paths
reduces each element to no more than five characters.
For example, link-static
becomes lnk-sttc
. The --hash
option reduces the
path to a single directory using an MD5 hash.
There are two features that affect the build directory. The <location>
feature completely overrides the default build directory. For example,
exe a : a.cpp : <location>. ;
builds all the files produced by a
in the directory of the Jamfile.
This is generally discouraged, as it precludes variant builds.
The <location-prefix> feature adds a prefix to the path, under the project’s build directory. For example,
exe a : a.cpp : <location-prefix>subdir ;
will create the files for a
in bin/subdir/gcc-4.6.1/debug
6.8. Definitions
6.8.1. Features and properties
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 for non-free features may not contain the
punctuation characters of pointy bracket (‘<
’), colon (‘:
’ ),
equal sign (‘=
’) and dashes (‘-
’). Feature values for free
features may not contain the pointy bracket (‘<
’) character.
A property is a (feature,value) pair, expressed as <feature>value.
A subfeature is a feature that 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 subfeature’s parent can never be another subfeature. Thus, features and their subfeatures form a two-level hierarchy.
A value-string for a feature F is a string of the form
value-subvalue1-subvalue2
…-subvalueN
, where value
is a legal
value for F and subvalue1
…subvalueN
are legal values of some of
F's subfeatures separated with dashes (‘-
’).
For example, the properties <toolset>gcc <toolset-version>3.0.1
can
be expressed more concisely using a value-string, as <toolset>gcc-3.0.1
.
A property set is a set of properties (i.e. a collection without
duplicates), 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 that fully describes the set of features used to build a target.
6.8.2. Property Validity
For free features, all
values are valid. For all other features, the valid values are
explicitly specified, and the build system will report an error for the
use of an invalid feature-value. Subproperty validity may be restricted
so that certain values are valid only in the presence of certain other
subproperties. For example, it is possible to specify that the
<gcc-target>mingw
property is only valid in the presence of
<gcc-version>2.95.2
.
6.8.3. Feature Attributes
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 an incidental property, for example, is one whose feature 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 that 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.
-
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 executable 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 that is not required to appear in a build specification. Every non-optional non-free feature has a default value that 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]
-
Normally a feature only generates a sub-variant directory when its value differs from its default value, leading to an asymmetric sub-variant directory structure for certain values of the feature. A symmetric feature always generates a corresponding sub-variant 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>gcc", 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 necessary. Non-composite non-free features override components of composite features in a build property set.
-
The value of a dependency feature is a target reference. When used for building of a main target, the value of dependency feature is treated as additional dependency.
For example, dependency features allow to state that library A depends on library B. As the result, whenever an application will link to A, it will also link to B. Specifying B as dependency of A is different from adding B to the sources of A.
Features that are neither free nor incidental are called base features.
6.8.4. Feature Declaration
The low-level feature declaration interface is the feature
rule from
the feature
module:
rule feature ( name : allowed-values * : attributes * )
A feature’s allowed-values may be extended with the feature.extend
rule.
6.8.5. Property refinement
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
-
Each property in the required set is added to the original property set
-
If the original property set includes property with a different value of non free feature, that property is removed.
6.8.6. Conditional properties
Sometime it’s desirable to apply certain requirements only for a specific combination of other properties. For example, one of compilers that you use issues a pointless warning that you want to suppress by passing a command line option to it. You would not want to pass that option to other compilers. Conditional properties allow you to do just that. Their syntax is:
property ( "," property ) * ":" property
For example, the problem above would be solved by:
exe hello : hello.cpp : <toolset>yfc:<cxxflags>-disable-pointless-warning ;
The syntax also allows several properties in the condition, for example:
exe hello : hello.cpp : <os>NT,<toolset>gcc:<link>static ;
6.8.7. Target identifiers and references
Target identifier is used to denote a target. The syntax is:
target-id -> (target-name | file-name | project-id | directory-name) | (project-id | directory-name) "//" target-name project-id -> path target-name -> path file-name -> path directory-name -> path
This grammar allows some elements to be recognized as either
-
name of target declared in current Jamfile (note that target names may include slash).
-
a regular file, denoted by absolute name or name relative to project’s sources location.
-
project id (at this point, all project ids start with slash).
-
the directory of another project, denoted by absolute name or name relative to the current project’s location.
To determine the real meaning the possible interpretations are checked in this order. For example, valid target ids might be:
|
target in current project |
|
regular file |
|
project "/boost/thread" |
|
target in specific project |
|
project in specific directory |
Rationale:Target is separated from project by special separator (not just slash), because:
-
It emphasis that projects and targets are different things.
-
It allows to have main target names with slashes.
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-path
For 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 compiler
executable is build with optimization
for speed.
7. Utilities
7.1. Debugger
7.1.1. Overview
B2 comes with a debugger for Jamfiles. To run the debugger,
start B2 with b2 -dconsole
.
$ b2 -dconsole (b2db) break gcc.init Breakpoint 1 set at gcc.init (b2db) run Starting program: /usr/bin/b2 Breakpoint 1, gcc.init ( ) at /usr/share/b2/tools/gcc.jam:74 74 local tool-command = ; (b2db) quit
7.1.2. Running the Program
The run
command is used to start a new b2
subprocess for debugging.
The arguments to run
are passed on the command line. If a child
process is already running, it will be terminated before the new child
is launched.
When the program is paused continue
will resume execution. The step
command will advance the program by a single statement, stopping on
entry to another function or return from the current function. next
is
like step
except that it skips over function calls. finish
executes
until the current function returns.
 Breakpoints
Breakpoints are set using the break
command. The location of the
breakpoint can be specified as either the name of a function (including
the module name) or or a file name and line number of the form
file:line
. When a breakpoint is created it is given a unique id which
is used to identify it for other commands.
(b2db) break Jamfile:10 Breakpoint 1 set at Jamfile:10 (b2db) break msvc.init Breakpoint 2 set at msvc.init
A breakpoint can be temporarily disabled using the disable
command.
While a breakpoint is disabled, the child will not stop when it is hit.
A disabled breakpoint can be activated again with enable
.
(b2db) disable 1 (b2db) enable 1
Breakpoints can be removed permanently with delete
or clear
. The
difference between them is that delete
takes the breakpoint id while
clear
takes the location of the breakpoint as originally specified to
break.
(b2db) clear Jamfile:10 Deleted breakpoint 1 (b2db) delete 2
8. Extender Manual
8.1. Introduction
This section explains how to extend B2 to accommodate your local requirements — primarily to add support for non-standard tools you have. Before we start, be sure you have read and understood the concept of metatarget, Concepts, which is critical to understanding the remaining material.
The current version of B2 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.
|
⚠
|
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.
|
8.1.1. 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 metatarget 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.
8.1.2. 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 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 B2 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) ] ;
8.1.3. Generators
In theory, every kind of metatarget in B2 (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, B2 defines concept of target type and generators 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.
8.2. Example: 1-to-1 generator
Say you’re writing an application that generates C++ code. If you ever did this, you know that it’s not nice. Embedding large portions of C++ code in string literals is very awkward. A much better solution is:
-
Write the template of the code to be generated, leaving placeholders at the points that will change
-
Access the template in your application and replace placeholders with appropriate text.
-
Write the result.
It’s quite easy to achieve. You write special verbatim files that are
just C++, except that the very first line of the file contains the name
of a variable that should be generated. A simple tool is created that
takes a verbatim file and creates a cpp file with a single char*
variable whose name is taken from the first line of the verbatim file
and whose value is the file’s properly quoted content.
Let’s see what B2 can do.
First off, B2 has no idea about "verbatim files". So, you must register a new target type. The following code does it:
import type ;
type.register VERBATIM : verbatim ;
The first parameter to
type.register gives the name
of the declared type. By convention, it’s uppercase. The second
parameter is the suffix for files of this type. So, if B2 sees
code.verbatim
in a list of sources, it knows that it’s of type
VERBATIM
.
Next, you tell B2 that the verbatim files can be transformed
into C++ files in one build step. A generator is a template for a build
step that transforms targets of one type (or set of types) into another.
Our generator will be called verbatim.inline-file
; it transforms
VERBATIM
files into CPP
files:
import generators ;
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
Lastly, you have to inform B2 about the shell commands used to
make that transformation. That’s done with an actions
declaration.
actions inline-file
{
"./inline-file.py" $(<) $(>)
}
Now, we’re ready to tie it all together. Put all the code above in file
verbatim.jam
, add import verbatim ;
to Jamroot.jam
, and it’s
possible to write the following in your Jamfile:
exe codegen : codegen.cpp class_template.verbatim usage.verbatim ;
The listed verbatim files will be automatically converted into C++
source files, compiled and then linked to the codegen
executable.
In subsequent sections, we will extend this example, and review all the
mechanisms in detail. The complete code is available in the
example/customization
directory.
8.3. Target types
The first thing we did in the introduction was declaring a new target type:
import type ;
type.register VERBATIM : verbatim ;
The type is the most important property of a target. B2 can automatically generate necessary build actions only because you specify the desired type (using the different main target rules), and because B2 can guess the type of sources from their extensions.
The first two parameters for the type.register
rule are the name of
new type and the list of extensions associated with it. A file with an
extension from the list will have the given target type. In the case
where a target of the declared type is generated from other sources, the
first specified extension will be used.
Sometimes you want to change the suffix used for generated targets
depending on build properties, such as toolset. For example, some
compiler uses extension elf
for executable files. You can use the
type.set-generated-target-suffix
rule:
type.set-generated-target-suffix EXE : <toolset>elf : elf ;
A new target type can be inherited from an existing one.
type.register PLUGIN : : SHARED_LIB ;
The above code defines a new type derived from SHARED_LIB
. Initially,
the new type inherits all the properties of the base type - in
particular generators and suffix. Typically, you’ll change the new type
in some way. For example, using type.set-generated-target-suffix
you
can set the suffix for the new type. Or you can write a special
generator for the new type. For example, it can generate additional
meta-information for the plugin. In either way, the PLUGIN
type can be
used whenever SHARED_LIB
can. For example, you can directly link
plugins to an application.
A type can be defined as "main", in which case B2 will automatically declare a main target rule for building targets of that type. More details can be found later.
8.4. Scanners
Sometimes, a file can refer to other files via some include system. To make B2 track dependencies between included files, you need to provide a scanner. The primary limitation is that only one scanner can be assigned to a target type.
First, we need to declare a new class for the scanner:
class verbatim-scanner : common-scanner
{
rule pattern ( )
{
return "//###include[ ]*\"([^\"]*)\"" ;
}
}
All the complex logic is in the common-scanner
class, and you only
need to override the method that returns the regular expression to be
used for scanning. The parentheses in the regular expression indicate
which part of the string is the name of the included file. Only the
first parenthesized group in the regular expression will be recognized;
if you can’t express everything you want that way, you can return
multiple regular expressions, each of which contains a parenthesized
group to be matched.
After that, we need to register our scanner class:
scanner.register verbatim-scanner : include ;
The value of the second parameter, in this case include
, specifies the
properties that contain the list of paths that should be searched for
the included files.
Finally, we assign the new scanner to the VERBATIM
target type:
type.set-scanner VERBATIM : verbatim-scanner ;
That’s enough for scanning include dependencies.
8.5. Tools and generators
This section will describe how B2 can be extended to support new tools.
For each additional tool, a B2 object called generator must be
created. That object has specific types of targets that it accepts and
produces. Using that information, B2 is able to automatically
invoke the generator. For example, if you declare a generator that takes
a target of the type D
and produces a target of the type OBJ
, when
placing a file with extension .d
in a list of sources will cause
B2 to invoke your generator, and then to link the resulting
object file into an application. (Of course, this requires that you
specify that the .d
extension corresponds to the D
type.)
Each generator should be an instance of a class derived from the
generator
class. In the simplest case, you don’t need to create a
derived class, but simply create an instance of the generator
class.
Let’s review the example we’ve seen in the
introduction.
import generators ;
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
actions inline-file
{
"./inline-file.py" $(<) $(>)
}
We declare a standard generator, specifying its id, the source type and
the target type. When invoked, the generator will create a target of
type CPP
with a source target of type VERBATIM
as the only source.
But what command will be used to actually generate the file? In
B2, actions are specified using named "actions" blocks and the
name of the action block should be specified when creating targets. By
convention, generators use the same name of the action block as their
own id. So, in above example, the "inline-file" actions block will be
used to convert the source into the target.
There are two primary kinds of generators: standard and composing, which
are registered with the generators.register-standard
and the
generators.register-composing
rules, respectively. For example:
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
generators.register-composing mex.mex : CPP LIB : MEX ;
The first (standard) generator takes a single source of type
VERBATIM
and produces a result. The second (composing) generator takes
any number of sources, which can have either the CPP
or the LIB
type. Composing generators are typically used for generating top-level
target type. For example, the first generator invoked when building an
exe
target is a composing generator corresponding to the proper
linker.
You should also know about two specific functions for registering
generators: generators.register-c-compiler
and
generators.register-linker
. The first sets up header dependency
scanning for C files, and the seconds handles various complexities like
searched libraries. For that reason, you should always use those
functions when adding support for compilers and linkers.
(Need a note about UNIX)
Custom generator classes
The standard generators allows you to specify source and target types, an action, and a set of flags. If you need anything more complex, you need to create a new generator class with your own logic. Then, you have to create an instance of that class and register it. Here’s an example how you can create your own generator class:
class custom-generator : generator
{
rule __init__ ( * : * )
{
generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
}
}
generators.register
[ new custom-generator verbatim.inline-file : VERBATIM : CPP ] ;
This generator will work exactly like the verbatim.inline-file
generator we’ve defined above, but it’s possible to customize the
behavior by overriding methods of the generator
class.
There are two methods of interest. The run
method is responsible for
the overall process - it takes a number of source targets, converts them
to the right types, and creates the result. The generated-targets
method is called when all sources are converted to the right types to
actually create the result.
The generated-targets
method can be overridden when you want to add
additional properties to the generated targets or use additional
sources. For a real-life example, suppose you have a program analysis
tool that should be given a name of executable and the list of all
sources. Naturally, you don’t want to list all source files manually.
Here’s how the generated-targets
method can find the list of sources
automatically:
class itrace-generator : generator {
...
rule generated-targets ( sources + : property-set : project name ? )
{
local leaves ;
local temp = [ virtual-target.traverse $(sources[1]) : : include-sources ] ;
for local t in $(temp)
{
if ! [ $(t).action ]
{
leaves += $(t) ;
}
}
return [ generator.generated-targets $(sources) $(leafs)
: $(property-set) : $(project) $(name) ] ;
}
}
generators.register [ new itrace-generator nm.itrace : EXE : ITRACE ] ;
The generated-targets
method will be called with a single source
target of type EXE
. The call to virtual-target.traverse
will return
all targets the executable depends on, and we further find files that
are not produced from anything. The found targets are added to the
sources.
The run
method can be overridden to completely customize the way the
generator works. In particular, the conversion of sources to the desired
types can be completely customized. Here’s another real example. Tests
for the Boost Python library usually consist of two parts: a Python
program and a C++ file. The C++ file is compiled to Python extension
that is loaded by the Python program. But in the likely case that both
files have the same name, the created Python extension must be renamed.
Otherwise, the Python program will import itself, not the extension.
Here’s how it can be done:
rule run ( project name ? : property-set : sources * )
{
local python ;
for local s in $(sources)
{
if [ $(s).type ] = PY
{
python = $(s) ;
}
}
local libs ;
for local s in $(sources)
{
if [ type.is-derived [ $(s).type ] LIB ]
{
libs += $(s) ;
}
}
local new-sources ;
for local s in $(sources)
{
if [ type.is-derived [ $(s).type ] CPP ]
{
local name = [ $(s).name ] ; # get the target's basename
if $(name) = [ $(python).name ]
{
name = $(name)_ext ; # rename the target
}
new-sources += [ generators.construct $(project) $(name) :
PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ;
}
}
result = [ construct-result $(python) $(new-sources) : $(project) $(name)
: $(property-set) ] ;
}
First, we separate all source into python files, libraries and C++
sources. For each C++ source we create a separate Python extension by
calling generators.construct
and passing the C++ source and the
libraries. At this point, we also change the extension’s name, if
necessary.
8.6. Features
Often, we need to control the options passed the invoked tools. This is done with features. Consider an example:
# Declare a new free feature
import feature : feature ;
feature verbatim-options : : free ;
# Cause the value of the 'verbatim-options' feature to be
# available as 'OPTIONS' variable inside verbatim.inline-file
import toolset : flags ;
flags verbatim.inline-file OPTIONS <verbatim-options> ;
# Use the "OPTIONS" variable
actions inline-file
{
"./inline-file.py" $(OPTIONS) $(<) $(>)
}
We first define a new feature. Then, the flags
invocation says that
whenever verbatim.inline-file action is run, the value of the
verbatim-options
feature will be added to the OPTIONS
variable, and
can be used inside the action body. You’d need to consult online help
(--help) to find all the features of the toolset.flags
rule.
Although you can define any set of features and interpret their values in any way, B2 suggests the following coding standard for designing features.
Most features should have a fixed set of values that is portable (tool
neutral) across the class of tools they are designed to work with. The
user does not have to adjust the values for a exact tool. For example,
<optimization>speed
has the same meaning for all C++ compilers and the
user does not have to worry about the exact options passed to the
compiler’s command line.
Besides such portable features there are special 'raw' features that
allow the user to pass any value to the command line parameters for a
particular tool, if so desired. For example, the <cxxflags>
feature
allows you to pass any command line options to a C++ compiler. The
<include>
feature allows you to pass any string preceded by -I
and
the interpretation is tool-specific. (See Can I get capture external program output using a Boost.Jam variable?
for an example of very smart usage of that feature). Of course one
should always strive to use portable features, but these are still be
provided as a backdoor just to make sure B2 does not take away
any control from the user.
Using portable features is a good idea because:
-
When a portable feature is given a fixed set of values, you can build your project with two different settings of the feature and B2 will automatically use two different directories for generated files. B2 does not try to separate targets built with different raw options.
-
Unlike with “raw” features, you don’t need to use specific command-line flags in your Jamfile, and it will be more likely to work with other tools.
Steps for adding a feature
Adding a feature requires three steps:
-
Declaring a feature. For that, the "feature.feature" rule is used. You have to decide on the set of feature attributes:
-
if you want a feature value set for one target to automatically propagate to its dependent targets then make it “propagated”.
-
if a feature does not have a fixed list of values, it must be “free.” For example, the
include
feature is a free feature. -
if a feature is used to refer to a path relative to the Jamfile, it must be a “path” feature. Such features will also get their values automatically converted to B2’s internal path representation. For example,
include
is a path feature. -
if feature is used to refer to some target, it must be a “dependency” feature.
-
-
Representing the feature value in a target-specific variable. Build actions are command templates modified by Boost.Jam variable expansions. The
toolset.flags
rule sets a target-specific variable to the value of a feature. -
Using the variable. The variable set in step 2 can be used in a build action to form command parameters or files.
Another example
Here’s another example. Let’s see how we can make a feature that refers to a target. For example, when linking dynamic libraries on Windows, one sometimes needs to specify a "DEF file", telling what functions should be exported. It would be nice to use this file like this:
lib a : a.cpp : <def-file>a.def ;
Actually, this feature is already supported, but anyway…
-
Since the feature refers to a target, it must be "dependency".
feature def-file : : free dependency ;
-
One of the toolsets that cares about DEF files is msvc. The following line should be added to it.
flags msvc.link DEF_FILE <def-file> ;
-
Since the DEF_FILE variable is not used by the msvc.link action, we need to modify it to be:
actions link bind DEF_FILE { $(.LD) .... /DEF:$(DEF_FILE) .... }
Note the
bind DEF_FILE
part. It tells B2 to translate the internal target name inDEF_FILE
to a corresponding filename in thelink
action. Without it the expansion of$(DEF_FILE)
would be a strange symbol that is not likely to make sense for the linker.We are almost done, except for adding the following code to
msvc.jam
:rule link { DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ; }
This is a workaround for a bug in B2 engine, which will hopefully be fixed one day.
Variants and composite features.
Sometimes you want to create a shortcut for some set of features. For
example, release
is a value of <variant>
and is a shortcut for a set
of features.
It is possible to define your own build variants. For example:
variant crazy : <optimization>speed <inlining>off
<debug-symbols>on <profiling>on ;
will define a new variant with the specified set of properties. You can also extend an existing variant:
variant super_release : release : <define>USE_ASM ;
In this case, super_release
will expand to all properties specified by
release
, and the additional one you’ve specified.
You are not restricted to using the variant
feature only. Here’s
example that defines a brand new feature:
feature parallelism : mpi fake none : composite link-incompatible ;
feature.compose <parallelism>mpi : <library>/mpi//mpi/<parallelism>none ;
feature.compose <parallelism>fake : <library>/mpi//fake/<parallelism>none ;
This will allow you to specify the value of feature parallelism
, which
will expand to link to the necessary library.
8.7. Main target rules
A main target rule (e.g “exe” Or “lib”) creates a top-level target. It’s quite likely that you’ll want to declare your own and there are two ways to do that.
The first way applies when your target rule
should just produce a target
of specific type. In that case, a rule is already defined for you! When
you define a new type, B2 automatically defines a corresponding
rule. The name of the rule is obtained from the name of the type, by
down-casing all letters and replacing underscores with dashes. For
example, if you create a module obfuscate.jam
containing:
import type ;
type.register OBFUSCATED_CPP : ocpp ;
import generators ;
generators.register-standard obfuscate.file : CPP : OBFUSCATED_CPP ;
and import that module, you’ll be able to use the rule "obfuscated-cpp" in Jamfiles, which will convert source to the OBFUSCATED_CPP type.
The second way is to write a wrapper rule that calls any of the existing rules. For example, suppose you have only one library per directory and want all cpp files in the directory to be compiled into that library. You can achieve this effect using:
lib codegen : [ glob *.cpp ] ;
If you want to make it even simpler, you could add the following
definition to the Jamroot.jam
file:
rule glib ( name : extra-sources * : requirements * )
{
lib $(name) : [ glob *.cpp ] $(extra-sources) : $(requirements) ;
}
allowing you to reduce the Jamfile to just
glib codegen ;
Note that because you can associate a custom generator with a target
type, the logic of building can be rather complicated. For example, the
boostbook
module declares a target type BOOSTBOOK_MAIN
and a custom
generator for that type. You can use that as example if your main target
rule is non-trivial.
8.8. Toolset modules
If your extensions will be used only on one project, they can be placed
in a separate .jam
file and imported by your Jamroot.jam
. If the
extensions will be used on many projects, users will thank you for a
finishing touch.
The using
rule provides a standard mechanism for loading and
configuring extensions. To make it work, your module should provide an
init
rule. The rule will be called with the same parameters that were
passed to the using
rule. The set of allowed parameters is determined
by you. For example, you can allow the user to specify paths, tool
versions, and other options.
Here are some guidelines that help to make B2 more consistent:
-
The
init
rule should never fail. Even if the user provided an incorrect path, you should emit a warning and go on. Configuration may be shared between different machines, and wrong values on one machine can be OK on another. -
Prefer specifying the command to be executed to specifying the tool’s installation path. First of all, this gives more control: it’s possible to specify
/usr/bin/g++-snapshot time g++
as the command. Second, while some tools have a logical "installation root", it’s better if the user doesn’t have to remember whether a specific tool requires a full command or a path.
-
Check for multiple initialization. A user can try to initialize the module several times. You need to check for this and decide what to do. Typically, unless you support several versions of a tool, duplicate initialization is a user error. If the tool’s version can be specified during initialization, make sure the version is either always specified, or never specified (in which case the tool is initialized only once). For example, if you allow:
using yfc ; using yfc : 3.3 ; using yfc : 3.4 ;
Then it’s not clear if the first initialization corresponds to version 3.3 of the tool, version 3.4 of the tool, or some other version. This can lead to building twice with the same version.
-
If possible,
init
must be callable with no parameters. In which case, it should try to autodetect all the necessary information, for example, by looking for a tool in PATH or in common installation locations. Often this is possible and allows the user to simply write:using yfc ;
-
Consider using facilities in the
tools/common
module. You can take a look at howtools/gcc.jam
uses that module in theinit
rule.
9. Frequently Asked Questions
9.1. How do I get the current value of feature in Jamfile?
This is not possible, since Jamfile does not have "current" value of any feature, be it toolset, build variant or anything else. For a single run of B2, any given main target can be built with several property sets. For example, user can request two build variants on the command line. Or one library is built as shared when used from one application, and as static when used from another. Each Jamfile is read only once so generally there is no single value of a feature you can access in Jamfile.
A feature has a specific value only when building a target, and there are two ways you can use that value:
-
Use conditional requirements or indirect conditional requirements. See the section called “Requirements”.
-
Define a custom generator and a custom main target type. The custom generator can do arbitrary processing or properties. See the extender manual
9.2. I am getting a "Duplicate name of actual target" error. What does that mean?
The most likely case is that you are trying to compile the same file twice, with almost the same, but differing properties. For example:
exe a : a.cpp : <include>/usr/local/include ;
exe b : a.cpp ;
The above snippet requires two different compilations of a.cpp
, which
differ only in their include
property. Since the include
feature is
declared as free
B2 does not create a separate build
directory for each of its values and those two builds would both produce
object files generated in the same build directory. Ignoring this and
compiling the file only once would be dangerous as different includes
could potentially cause completely different code to be compiled.
To solve this issue, you need to decide if the file should be compiled once or twice.
-
To compile the file only once, make sure that properties are the same for both target requests:
exe a : a.cpp : <include>/usr/local/include ; exe b : a.cpp : <include>/usr/local/include ;
or:
alias a-with-include : a.cpp : <include>/usr/local/include ; exe a : a-with-include ; exe b : a-with-include ;
or if you want the
includes
property not to affect how any other sources added for the builta
andb
executables would be compiled:obj a-obj : a.cpp : <include>/usr/local/include ; exe a : a-obj ; exe b : a-obj ;
Note that in both of these cases the
include
property will be applied only for building these object files and not any other sources that might be added for targetsa
andb
. -
To compile the file twice, you can tell B2 to compile it to two separate object files like so:
obj a_obj : a.cpp : <include>/usr/local/include ; obj b_obj : a.cpp ; exe a : a_obj ; exe b : b_obj ;
or you can make the object file targets local to the main target:
exe a : [ obj a_obj : a.cpp : <include>/usr/local/include ] ; exe b : [ obj a_obj : a.cpp ] ;
which will cause B2 to actually change the generated object file names a bit for you and thus avoid any conflicts.
Note that in both of these cases the
include
property will be applied only for building these object files and not any other sources that might be added for targetsa
andb
.
A good question is why B2 can not use some of the above approaches automatically. The problem is that such magic would only help in half of the cases, while in the other half it would be silently doing the wrong thing. It is simpler and safer to ask the user to clarify his intention in such cases.
9.3. Accessing environment variables
Many users would like to use environment variables in Jamfiles, for example, to control the location of external libraries. In many cases it is better to declare those external libraries in the site-config.jam file, as documented in the recipes section. However, if the users already have the environment variables set up, it may not be convenient for them to set up their site-config.jam files as well and using the environment variables might be reasonable.
Boost.Jam automatically imports all environment variables into its built-in .ENVIRON module so user can read them from there directly or by using the helper os.environ rule. For example:
import os ;
local unga-unga = [ os.environ UNGA_UNGA ] ;
ECHO $(unga-unga) ;
or a bit more realistic:
import os ;
local SOME_LIBRARY_PATH = [ os.environ SOME_LIBRARY_PATH ] ;
exe a : a.cpp : <include>$(SOME_LIBRARY_PATH) ;
9.4. How to control properties order?
For internal reasons, B2 sorts all the properties alphabetically. This means that if you write:
exe a : a.cpp : <include>b <include>a ;
then the command line with first mention the a
include directory, and
then b
, even though they are specified in the opposite order. In most
cases, the user does not care. But sometimes the order of includes, or
other properties, is important. For such cases, a special syntax is
provided:
exe a : a.cpp : <include>a&&b ;
The &&
symbols separate property values and specify that their order
should be preserved. You are advised to use this feature only when the
order of properties really matters and not as a convenient shortcut.
Using it everywhere might negatively affect performance.
9.5. How to control the library linking order on Unix?
On Unix-like operating systems, the order in which static libraries are specified when invoking the linker is important, because by default, the linker uses one pass though the libraries list. Passing the libraries in the incorrect order will lead to a link error. Further, this behavior is often used to make one library override symbols from another. So, sometimes it is necessary to force specific library linking order.
B2 tries to automatically compute the right order. The primary
rule is that if library a
"uses" library b
, then library a
will
appear on the command line before library b
. Library a
is considered
to use b
if b
is present either in the a
library’s sources or its
usage is listed in its requirements. To explicitly specify the use
relationship one can use the <use>
feature. For example, both of the
following lines will cause a
to appear before b
on the command line:
lib a : a.cpp b ;
lib a : a.cpp : <use>b ;
The same approach works for searched libraries as well:
lib z ;
lib png : : <use>z ;
exe viewer : viewer png z ;
9.6. Can I get capture external program output using a Boost.Jam variable?
The SHELL
builtin rule may be used for this purpose:
local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
9.7. How to get the project root (a.k.a. Jamroot) location?
You might want to use your project’s root location in your Jamfiles. To
access it just declare a path constant in your Jamroot.jam
file using:
path-constant TOP : . ;
After that, the TOP
variable can be used in every Jamfile.
9.8. How to change compilation flags for one file?
If one file must be compiled with special options, you need to
explicitly declare an obj
target for that file and then use that
target in your exe
or lib
target:
exe a : a.cpp b ;
obj b : b.cpp : <optimization>off ;
Of course you can use other properties, for example to specify specific C/C++ compiler options:
exe a : a.cpp b ;
obj b : b.cpp : <cflags>-g ;
You can also use conditional properties for finer control:
exe a : a.cpp b ;
obj b : b.cpp : <variant>release:<optimization>off ;
9.9. Why are the dll-path
and hardcode-dll-paths
properties useful?
|
ℹ
|
This entry is specific to Unix systems. |
Before answering the questions, let us recall a few points about shared libraries. Shared libraries can be used by several applications, or other libraries, without physically including the library in the application which can greatly decrease the total application size. It is also possible to upgrade a shared library when the application is already installed.
However, in order for application depending on shared libraries to be
started the OS may need to find the shared library when the application
is started. The dynamic linker will search in a system-defined list of
paths, load the library and resolve the symbols. Which means that you
should either change the system-defined list, given by the
LD_LIBRARY_PATH
environment variable, or install the libraries to a
system location. This can be inconvenient when developing, since the
libraries are not yet ready to be installed, and cluttering system paths
may be undesirable. Luckily, on Unix there is another way.
An executable can include a list of additional library paths, which will
be searched before system paths. This is excellent for development
because the build system knows the paths to all libraries and can
include them in the executables. That is done when the
hardcode-dll-paths
feature has the true
value, which is the default.
When the executables should be installed, the story is different.
Obviously, installed executable should not contain hardcoded paths to
your development tree. (The install
rule explicitly disables the
hardcode-dll-paths
feature for that reason.) However, you can use the
dll-path
feature to add explicit paths manually. For example:
install installed : application : <dll-path>/usr/lib/snake
<location>/usr/bin ;
will allow the application to find libraries placed in the
/usr/lib/snake
directory.
If you install libraries to a nonstandard location and add an explicit path, you get more control over libraries which will be used. A library of the same name in a system location will not be inadvertently used. If you install libraries to a system location and do not add any paths, the system administrator will have more control. Each library can be individually upgraded, and all applications will use the new library.
Which approach is best depends on your situation. If the libraries are relatively standalone and can be used by third party applications, they should be installed in the system location. If you have lots of libraries which can be used only by your application, it makes sense to install them to a nonstandard directory and add an explicit path, like the example above shows. Please also note that guidelines for different systems differ in this respect. For example, the Debian GNU guidelines prohibit any additional search paths while Solaris guidelines suggest that they should always be used.
9.10. Targets in site-config.jam
It is desirable to declare standard libraries available on a given
system. Putting target declaration in a specific project’s Jamfile is
not really good, since locations of the libraries can vary between
different development machines and then such declarations would need to
be duplicated in different projects. The solution is to declare the
targets in B2’s site-config.jam
configuration file:
project site-config ;
lib zlib : : <name>z ;
Recall that both site-config.jam
and user-config.jam
are projects,
and everything you can do in a Jamfile you can do in those files as
well. So, you declare a project id and a target. Now, one can write:
exe hello : hello.cpp /site-config//zlib ;
in any Jamfile.
9.11. Header-only libraries
In modern C++, libraries often consist of just header files, without any source files to compile. To use such libraries, you need to add proper includes and possibly defines to your project. But with a large number of external libraries it becomes problematic to remember which libraries are header only, and which ones you have to link to. However, with B2 a header-only library can be declared as B2 target and all dependents can use such library without having to remember whether it is a header-only library or not.
Header-only libraries may be declared using the alias
rule, specifying
their include path as a part of its usage requirements, for example:
alias my-lib
: # no sources
: # no build requirements
: # no default build
: <include>whatever ;
The includes specified in usage requirements of my-lib
are
automatically added to all of its dependents build properties. The
dependents need not care if my-lib
is a header-only or not, and it is
possible to later make my-lib
into a regular compiled library without
having to add the includes to its dependents declarations.
If you already have proper usage requirements declared for a project
where a header-only library is defined, you do not need to duplicate
them for the alias
target:
project my : usage-requirements <include>whatever ;
alias mylib ;
9.12. What is the difference between B2, b2
, bjam
and Perforce Jam?
B2 is the name of the complete build system. The executable
that runs it is b2
. That executable is written in C and implements
performance-critical algorithms, like traversal of dependency graph and
executing commands. It also implements an interpreted language used to
implement the rest of B2. This executable is formally called
"B2 engine".
The B2 engine is derived from an earlier build tool called
Perforce Jam. Originally, there were just minor changes, and the
filename was bjam
. Later on, with more and more changes, the
similarity of names became a disservice to users, and as of Boost
1.47.0, the official name of the executable was changed to b2
. A copy
named bjam
is still created for compatibility, but you are encouraged
to use the new name in all cases.
Perforce Jam was an important foundation, and we gratefully acknowledge its influence, but for users today, these tools share only some basics of the interpreted language.
10. Extra Tools
10.1. Documentation Tools
10.1.1. Asciidoctor
The asciidoctor tool converts the ascidoc documentation format to various backend formats for either viewing or further processing by documentation tools. This tool supports the baseline asciidoctor distribution (i.e. the Ruby based tool).
Feature: asciidoctor-attribute
Defines arbitrary asciidoctor attributes. The value of the feature should be specified with the CLI syntax for attributes. For example to use as a target requirement:
html example : example.adoc :
<asciidoctor-attribute>idprefix=ex ;
This is a free
feature and is not propagated
. I.e. it applies only to the
target it’s specified on.
Feature: asciidoctor-doctype
Specifies the doctype
to use for generating the output format. Allowed
doctype
values are: article
, book
, manpage
, and inline
.
Feature: asciidoctor-backend
Specifies the backend
to use to produce output from the source asciidoc.
This feature is automatically applied to fit the build target type. For
example, when specifying an html
target for an asciidoc
source:
html example : example.adoc ;
The target will by default acquire the <asciidoctor-backend>html5
requirement. The default for each target type are:
-
html
:<asciidoctor-backend>html5
-
docbook
:<asciidoctor-backend>docbook45
-
man
:<asciidoctor-backend>manpage
-
pdf
:<asciidoctor-backend>pdf
To override the defaults you specify it as a requirement on the target:
docbook example : example.adoc :
<asciidoctor-backend>docbook5 ;
Allowed backend
values are: html5
, docbook45
, docbook5
, pdf
.
Initialization
To use the asciidoctor
tool you need to declare it in a configuration file
with the using
rule. The initialization takes the following arguments:
-
command
: The command, with any extra arguments, to execute.
For example you could insert the following in your user-config.jam
:
using asciidoctor : "/usr/local/bin/asciidoctor" ;
If no command
is given it defaults to just asciidoctor
with assumption
that the asciidoctor
is available in the search PATH
.
10.2. Miscellaneous Tools
10.2.1. pkg-config
The pkg-config program is used to retrieve information about installed
libraries in the system. It retrieves information about packages from special
metadata files. These files are named after the package, and have a .pc
extension. The package name specified to pkg-config is defined to be the name
of the metadata file, minus the .pc
extension.
Feature: pkg-config
Selects one of the initialized pkg-config
configurations. This feature is
propagated
to dependencies. Its use is dicussed in
section Initialization.
Feature: pkg-config-define
This free
feature adds a variable assignment to pkg-config invocation. For
example,
pkg-config.import mypackage : requirements <pkg-config-define>key=value ;
is equivalent to invoking on the comand line
pkg-config --define-variable=key=value mypackage ;
Rule: import
Main target rule that imports a pkg-config package. When its consumer targets are built, pkg-config command will be invoked with arguments that depend on current property set. The features that have an effect are:
-
<pkg-config-define>
: adds a--define-variable
argument; -
<link>
: adds--static
argument when<link>static
; -
<link>
: adds--static
argument when<link>static
; -
<name>
: specifies package name (target name is used instead if the property is not present); -
<version>
: specifies package version range, can be used multiple times and should be a dot-separated sequence of numbers optionally prefixed with=
,<
,>
,⇐
or>=
.
Example:
pkg-config.import my-package
: requirements <name>my_package <version><4 <version>>=3.1 ;
Initialization
To use the pkg-config
tool you need to declare it in a configuration file
with the using
rule:
using pkg-config : [config] : [command] ... : [ options ] ... ;
-
config
: the name of initialized configuration. The name can be omitted, in which case the configuration will become the default one. -
command
: the command, with any extra arguments, to execute. If no command is given, firstPKG_CONFIG
environment variable is checked, and if its empty the stringpkg-config
is used. -
options
: options that modifypkg-config
behavior. Allowed options are: -
<path>
: setsPKG_CONFIG_PATH
environment variable; multiple occurences are allowed. -
<libdir>
: setsPKG_CONFIG_LIBDIR
environment variable; multiple occurences are allowed. -
<allow-system-cflags>
: setsPKG_CONFIG_ALLOW_SYSTEM_CFLAGS
environment variable; multiple occurences are allowed. -
<allow-system-libs>
: setsPKG_CONFIG_ALLOW_SYSTEM_LIBS
environment variable; multiple occurences are allowed. -
<sysroot>
: setsPKG_CONFIG_SYSROOT_DIR
environment variable; multiple occurences are allowed. -
<variable>
: adds a variable definition argument to command invocation; multiple occurences are allowed.
Class pkg-config-target
class pkg-config-target : alias-target-class {
rule construct ( name : sources * : property-set )
rule version ( property-set )
rule variable ( name : property-set )
}
The class of objects returned by import
rule. The objects themselves could be
useful in situations that require more complicated logic for consuming a
package. See Tips for examples.
-
rule construct ( name : sources * : property-set )
Overridesalias-target.construct
. -
rule version ( property-set )
Returns the package’s version, in the context ofproperty-set
. -
rule variable ( name : property-set )
Returns the value of variablename
in the package, in the context ofproperty-set
.
Tips
Using several configurations
Suppose, you have 2 collections of .pc
files: one for platform A, and another
for platform B. You can initialize 2 configurations of pkg-config
tool each
corresponding to specific collection:
using pkg-config : A : : <libdir>path/to/collection/A ;
using pkg-config : B : : <libdir>path/to/collection/B ;
Then, you can specify that builds for platform A should use configuration A, while builds for B should use configuration B:
project
: requirements
<target-os>A-os,<architecture>A-arch:<pkg-config>A
<target-os>B-os,<architecture>B-arch:<pkg-config>B
;
Thanks to the fact, that project-config
, user-config
and site-config
modules are parents of jamroot module, you can put it in any of those files.o
Choosing the package name based on the property set
Since a file for a package should be named after the package suffixed with
.pc
, some projects came up with naming schemes in order to allow simultaneous
installation of several major versions or build variants. In order to pick the
specific name corresponding to the build request you can use <conditional>
property in requirements:
pkg-config.import mypackage : requirements <conditional>@infer-name ;
rule infer-name ( properties * )
{
local name = mypackage ;
local variant = [ property.select <variant> : $(properties) ] ;
if $(variant) = debug
{
name += -d ;
}
return <name>$(name) ;
}
The common.format-name
rule can be very useful in this situation.
Modify usage requirements based on package version or variable
Sometimes you need to apply some logic based on package’s version or a
variable that it defines. For that you can use <conditional>
property in
usage requirements:
mypackage =
[ pkg-config.import mypackage : usage-requirements <conditional>@define_ns
] ;
rule extra-props ( properties * )
{
local ps = [ property-set.create $(properties) ] ;
local prefix = [ $(mypackage).variable name_prefix : $(ps) ] ;
prefix += [ $(mypackage).version $(ps) ] ;
return <define>$(prefix:J=_) ;
}
10.2.2. Sass
This tool converts SASS and SCSS files into CSS. This tool explicitly supports
both the version written in C (sassc) and the original Ruby implementation
(scss) but other variants might also work. In addition to tool-specific
features, described in this section, the tool recognizes features <flags>
and <include>
.
Feature: sass-style
Sets the output style. Available values are
-
nested
: each property is put on its own line, rules are indented based on how deeply they are nested; -
expanded
: each property is put on its own line, rules are not indented; -
compact
: each rule is put on a single line, nested rules occupy adjacent lines, while groups of unrelated rules are separated by newlines; -
compressed
: takes minimum amount of space: all unnecessary whitespace is removed, property values are compressed to have minimal representation.
The feature is optional
and is not propagated
to dependent targets. If no
style is specified, then, if property set contains property <optimization>on
,
compressed
style is selected. Otherwise, nested
style is selected.
Feature: sass-line-numbers
Enables emitting comments showing original line numbers for rules. This can be
useful for debugging a stylesheet. Available values are on
and off
. The
feature is optional
and is not propagated
to dependent targets. If no value
for this feature is specified, then one is copied from the feature
debug-symbols
.
Initialization
To use the sass
tool you need to declare it in a configuration file with the
using
rule. The initialization takes the following arguments:
-
command
: the command, with any extra arguments, to execute.
For example you could insert the following in your user-config.jam
:
using sass : /usr/local/bin/psass -p2 ; # Perl libsass-based version
If no command
is given, sassc
is tried, after which scss
is tried.
11. Examples
11.1. Introduction
Here we include a collection of simple to complex fully working examples of using Boost Build v2 for various tasks. They show the gamut from simple to advanced features. If you find yourself looking at the examples and not finding something you want to see working please post to our support list and we’ll try and come up with a solution and add it here for others to learn from.
11.2. Hello
This example shows a very basic Boost Build project set up so it compiles a single executable from a single source file:
hello.cpp
#include <iostream>
int main()
{
std::cout << "Hello!\n";
}
Our jamroot.jam
is minimal and only specifies one exe
target for the
program:
jamroot.jam
exe hello : hello.cpp ;
Building the example yields:
> cd /example/hello
> b2
...found 8 targets...
...updating 4 targets...
common.mkdir bin/clang-darwin-4.2.1
common.mkdir bin/clang-darwin-4.2.1/debug
clang-darwin.compile.c++ bin/clang-darwin-4.2.1/debug/hello.o
clang-darwin.link bin/clang-darwin-4.2.1/debug/hello
...updated 4 targets...
> bin/clang-darwin-4.2.1/debug/hello
Hello!
|
ℹ
|
The actual paths in the bin sub-directory will depend on your
toolset.
|
11.3. Sanitizers
This example shows how to enable sanitizers when using a clang or gcc toolset
main.cpp
int main()
{
char* c = nullptr;
std::cout << "Hello sanitizers\n " << *c;
}
Our jamroot.jam
is minimal and only specifies one exe
target for the
program:
jamroot.jam
exe main : main.cpp ;
Sanitizers can be enabled by passing on
or norecover
to the appropriate sanitizer feature
(e.g. thread-sanitizer=on
). The norecover
option causes the program to terminate after
the first sanitizer issue is detected. The following example shows how to enable address
and undefined
sanitizers in a simple program:
> cd /example/sanitizers
> b2 toolset=gcc address-sanitizer=norecover undefined-sanitizer=on
...found 10 targets...
...updating 7 targets...
gcc.compile.c++ bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main.o
gcc.link bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main
...updated 7 targets...
Running the produced program may produce an output simillar to the following:
> ./bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main
Hello sanitizers
main.cpp:6:43: runtime error: load of null pointer of type 'char'
ASAN:DEADLYSIGNAL
=================================================================
==29767==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55ba7988af1b bp 0x7ffdf3d76560 sp 0x7ffdf3d76530 T0)
==29767==The signal is caused by a READ memory access.
==29767==Hint: address points to the zero page.
#0 0x55ba7988af1a in main /home/damian/projects/boost/tools/build/example/sanitizers/main.cpp:6
#1 0x7f42f2ba1b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#2 0x55ba7988adb9 in _start (/home/damian/projects/boost/tools/build/example/sanitizers/bin/gcc-7.3.0/debug/address-sanitizer-norecover/undefined-sanitizer-on/main+0xdb9)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/damian/projects/boost/tools/build/example/sanitizers/main.cpp:6 in main
==29767==ABORTING
|
ℹ
|
The actual paths in the bin sub-directory will depend on your
toolset and configuration. The presented output may vary depending on your compiler version.
|
12. Boost.Jam Documentation
Jam is a make(1) replacement that makes building simple things simple and building complicated things manageable.
12.1. Building B2
Installing B2
after building it is simply a matter of copying the
generated executables someplace in your PATH
. For building the
executables there are a set of build
bootstrap scripts to accommodate
particular environments. The scripts take one optional argument, the
name of the toolset to build with. When the toolset is not given an
attempt is made to detect an available toolset and use that. The build
scripts accept these arguments:
build [toolset]
Running the scripts without arguments will give you the best chance of success. On Windows platforms from a command console do:
cd jam source location
.\build.bat
On Unix type platforms do:
cd jam source location
sh ./build.sh
For the Boost.Jam source included with the Boost distribution the jam
source location is BOOST_ROOT/tools/build/src/engine
.
If the scripts fail to detect an appropriate toolset to build with your
particular toolset may not be auto-detectable. In that case, you can
specify the toolset as the first argument, this assumes that the toolset
is readily available in the PATH
.
|
ℹ
|
The toolset used to build Boost.Jam is independent of the toolsets used for B2. Only one version of Boost.Jam is needed to use B2. |
The supported toolsets, and whether they are auto-detected, are:
| Script | Platform | Toolset | Detection and Notes |
|---|---|---|---|
|
Windows |
||
|
Microsoft Visual Studio C++ 2019
|
||
|
Microsoft Visual Studio C++ 2017
|
||
|
Microsoft Visual Studio C++ 2015
|
||
|
Microsoft Visual Studio C++ 2013
|
||
|
Embarcadero C++Builder
|
||
|
Intel C++ Compiler for Windows
|
||
|
GNU GCC as the MinGW configuration
|
||
|
Comeau Computing C/C++ |
||
|
GNU GCC |
||
|
Clang LLVM |
||
|
GNU GCC |
||
|
Unix, Linux, Cygwin, Windows Bash, etc. |
||
|
GNU GCC
|
||
|
Clang LLVM
|
||
|
Intel C++ (oneAPI) for Linux
|
||
|
SGI MIPSpro C++
|
||
|
Compaq C++ Compiler for True64 UNIX
|
||
|
QNX Neutrino
|
||
|
IBM VisualAge C++
|
||
|
PGI Compilers
|
||
|
Pathscale C++
|
||
|
Comeau Computing C/C++
|
||
|
Borland C++
|
||
|
HP-UX aCC
|
||
|
Sun Workshop 6 C++
|
The built executables are placed in the src/engine
directory.
The build.sh
script supports additional invocation options used to
control the the build and custom compilers:
build.sh [--option|--option=x] [toolset]
--help
-
Shows some help information, including these options.
--verbose
-
Show messages about what this script is doing.
--debug
-
Builds debugging versions of the executable. The default is to build an optimized executable.
--guess-toolset
-
Print the toolset we can detect for building. This is used by external scripts, like the Boost Libraries main bootstrap script.
--cxx=CXX
-
The compiler exec to use instead of the detected compiler exec.
--cxxflags=CXXFLAGS
-
The compiler flags to use in addition to the flags for the detected compiler.
12.2. Language
B2
has an interpreted, procedural language. Statements in b2
are
rule (procedure) definitions, rule invocations, flow-of-control
structures, variable assignments, and sundry language support.
12.2.1. Lexical Features
B2
treats its input files as whitespace-separated tokens, with two
exceptions: double quotes (") can enclose whitespace to embed it into a
token, and everything between the matching curly braces (\{}) in the
definition of a rule action is treated as a single string. A backslash
(\) can escape a double quote, or any single whitespace character.
B2
requires whitespace (blanks, tabs, or newlines) to surround all
tokens, including the colon (:) and semicolon (;) tokens.
B2
keywords (an mentioned in this document) are reserved and generally
must be quoted with double quotes (") to be used as arbitrary tokens,
such as variable or target names.
Comments start with the #
character and extend until the end of line.
And block comments start with #|
and extend until the next |#
.
12.2.2. Targets
The essential b2
data entity is a target. Build targets are files to
be updated. Source targets are the files used in updating built targets.
Built targets and source targets are collectively referred to as file
targets, and frequently built targets are source targets for other built
targets. Pseudo-targets are symbols representing dependencies on other
targets, but which are not themselves associated with any real file.
A file target’s identifier is generally the file’s name, which can be
absolutely rooted, relative to the directory of b2`s invocation, or
simply local (no directory). Most often it is the last case, and the
actual file path is bound using the `$(SEARCH)
and $(LOCATE)
special
variables. See SEARCH and
LOCATE Variables below. A local filename is optionally qualified with
grist, a string value used to assure uniqueness. A file target with an
identifier of the form file(member) is a library member (usually an
ar
(1) archive on Unix).
Binding Detection
Whenever a target is bound to a location in the filesystem, Boost Jam
will look for a variable called BINDRULE
(first "on" the target being
bound, then in the global module). If non-empty, $(BINDRULE[1])
names
a rule which is called with the name of the target and the path it is
being bound to. The signature of the rule named by $(BINDRULE[1])
should match the following:
rule bind-rule ( target : path )
This facility is useful for correct header file scanning, since many
compilers will search for #include
files first in the directory
containing the file doing the #include
directive. $(BINDRULE)
can be
used to make a record of that directory.
12.2.3. Rules
The basic b2
language entity is called a rule. A rule is defined in
two parts: the procedure and the actions. The procedure is a body of jam
statements to be run when the rule is invoked; the actions are the OS
shell commands to execute when updating the built targets of the rule.
Rules can return values, which can be expanded into a list with "[ rule args … ]". A rule’s value is the value of its last statement, though only the following statements have values: 'if' (value of the leg chosen), 'switch' (value of the case chosen), set (value of the resulting variable), and 'return' (value of its arguments).
The b2
statements for defining and invoking rules are as follows:
Define a rule’s procedure, replacing any previous definition.
rule rulename { statements }
Define a rule’s updating actions, replacing any previous definition.
actions [ modifiers ] rulename { commands }
Invoke a rule.
rulename field1 : field2 : ... : fieldN ;
Invoke a rule under the influence of target’s specific variables..
on target rulename field1 : field2 : ... : fieldN ;
Used as an argument, expands to the return value of the rule invoked.
[ rulename field1 : field2 : ... : fieldN ]
[ on target rulename field1 : field2 : ... : fieldN ]
A rule is invoked with values in field1 through fieldN. They may be
referenced in the procedure’s statements as $(1)
through $(N)
(9
max), and the first two only may be referenced in the action’s
commands as $(1)
and $(2)
. $(<)
and $(>)
are synonymous with
$(1)
and $(2)
.
Rules fall into two categories: updating rules (with actions), and pure
procedure rules (without actions). Updating rules treat arguments $(1)
and $(2)
as built targets and sources, respectively, while pure
procedure rules can take arbitrary arguments.
When an updating rule is invoked, its updating actions are added to
those associated with its built targets ($(1)
) before the rule’s
procedure is run. Later, to build the targets in the updating phase,
commands are passed to the OS command shell, with $(1)
and $(2)
replaced by bound versions of the target names. See Binding above.
Rule invocation may be indirected through a variable:
$(var) field1 : field2 : ... : fieldN ;
on target $(var) field1 : field2 : ... : fieldN ;
[ $(var) field1 : field2 : ... : fieldN ]
[ on target $(var) field1 : field2 : ... : fieldN ]
The variable’s value names the rule (or rules) to be invoked. A rule is
invoked for each element in the list of $(var)`s values. The fields
`field1 : field2 : …
are passed as arguments for each invocation For the [
… ] forms, the return value is the concatenation of the return values
for all of the invocations.
Action Modifiers
The following action modifiers are understood:
actions bind vars
-
$(vars)
will be replaced with bound values. actions existing
-
$(>)
includes only source targets currently existing. actions ignore
-
The return status of the commands is ignored.
actions piecemeal
-
commands are repeatedly invoked with a subset of
$(>)
small enough to fit in the command buffer on this OS. actions quietly
-
The action is not echoed to the standard output.
actions together
-
The
$(>)
from multiple invocations of the same action on the same built target are glommed together. actions updated
-
$(>)
includes only source targets themselves marked for updating.
Argument lists
You can describe the arguments accepted by a rule, and refer to them by name within the rule. For example, the following prints "I’m sorry, Dave" to the console:
rule report ( pronoun index ? : state : names + )
{
local he.suffix she.suffix it.suffix = s ;
local I.suffix = m ;
local they.suffix you.suffix = re ;
ECHO $(pronoun)'$($(pronoun).suffix) $(state), $(names[$(index)]) ;
}
report I 2 : sorry : Joe Dave Pete ;
Each name in a list of formal arguments (separated by :
in the rule
declaration) is bound to a single element of the corresponding actual
argument unless followed by one of these modifiers:
| Symbol | Semantics of preceding symbol |
|---|---|
|
optional |
|
Bind to zero or more unbound elements of the actual argument. When
|
|
Bind to one or more unbound elements of the actual argument. |
The actual and formal arguments are checked for inconsistencies, which
cause b2
to exit with an error code:
### argument error
# rule report ( pronoun index ? : state : names + )
# called with: ( I 2 foo : sorry : Joe Dave Pete )
# extra argument foo
### argument error
# rule report ( pronoun index ? : state : names + )
# called with: ( I 2 : sorry )
# missing argument names
If you omit the list of formal arguments, all checking is bypassed as in "classic" Jam. Argument lists drastically improve the reliability and readability of your rules, however, and are strongly recommended for any new Jam code you write.
12.2.4. Built-in Rules
B2
has a growing set of built-in rules, all of which are pure
procedure rules without updating actions. They are in three groups: the
first builds the dependency graph; the second modifies it; and the third
are just utility rules.
Dependency Building
DEPENDS
rule DEPENDS ( targets1 * : targets2 * )
Builds a direct dependency: makes each of targets1 depend on each of targets2. Generally, targets1 will be rebuilt if targets2 are themselves rebuilt or are newer than targets1.
INCLUDES
rule INCLUDES ( targets1 * : targets2 * )
Builds a sibling dependency: makes any target that depends on any of targets1 also depend on each of targets2. This reflects the dependencies that arise when one source file includes another: the object built from the source file depends both on the original and included source file, but the two sources files don’t depend on each other. For example:
DEPENDS foo.o : foo.c ;
INCLUDES foo.c : foo.h ;
foo.o
depends on foo.c
and foo.h
in this example.
Modifying Binding
The six rules ALWAYS
, LEAVES
, NOCARE
, NOTFILE
, NOUPDATE
, and
TEMPORARY
modify the dependency graph so that b2
treats the targets
differently during its target binding phase. See Binding above.
Normally, b2
updates a target if it is missing, if its filesystem
modification time is older than any of its dependencies (recursively),
or if any of its dependencies are being updated. This basic behavior can
be changed by invoking the following rules:
ALWAYS
rule ALWAYS ( targets * )
Causes targets to be rebuilt regardless of whether they are up-to-date
(they must still be in the dependency graph). This is used for the clean
and uninstall targets, as they have no dependencies and would otherwise
appear never to need building. It is best applied to targets that are
also NOTFILE
targets, but it can also be used to force a real file to
be updated as well.
LEAVES
rule LEAVES ( targets * )
Makes each of targets depend only on its leaf sources, and not on any intermediate targets. This makes it immune to its dependencies being updated, as the "leaf" dependencies are those without their own dependencies and without updating actions. This allows a target to be updated only if original source files change.
NOCARE
rule NOCARE ( targets * )
Causes b2
to ignore targets that neither can be found nor have
updating actions to build them. Normally for such targets b2
issues a
warning and then skips other targets that depend on these missing
targets. The HdrRule
in Jambase
uses NOCARE
on the header file
names found during header file scanning, to let b2
know that the
included files may not exist. For example, if an #include
is within an
#ifdef
, the included file may not actually be around.
|
⚠
|
For targets with build actions: if their build actions exit with a nonzero return code, dependent targets will still be built. |
NOTFILE
rule NOTFILE ( targets * )
Marks targets as pseudo-targets and not real files. No timestamp is
checked, and so the actions on such a target are only executed if the
target’s dependencies are updated, or if the target is also marked with
ALWAYS
. The default b2
target all
is a pseudo-target In
Jambase
, NOTFILE
is used to define several addition convenient
pseudo-targets
NOUPDATE
rule NOUPDATE ( targets * )
Causes the timestamps on targets to be ignored. This has two effects:
first, once the target has been created it will never be updated;
second, manually updating target will not cause other targets to be
updated. In Jambase
, for example, this rule is applied to directories
by the MkDir
rule, because MkDir
only cares that the target
directory exists, not when it has last been updated.
TEMPORARY
rule TEMPORARY ( targets * )
Marks targets as temporary, allowing them to be removed after other
targets that depend upon them have been updated. If a TEMPORARY
target
is missing, b2
uses the timestamp of the target’s parent. Jambase
uses TEMPORARY
to mark object files that are archived in a library
after they are built, so that they can be deleted after they are
archived.
FAIL_EXPECTED
rule FAIL_EXPECTED ( targets * )
For handling targets whose build actions are expected to fail (e.g. when
testing that assertions or compile-time type checking work properly),
Boost Jam supplies the FAIL_EXPECTED
rule in the same style as
NOCARE
, et. al. During target updating, the return code of the build
actions for arguments to FAIL_EXPECTED
is inverted: if it fails,
building of dependent targets continues as though it succeeded. If it
succeeds, dependent targets are skipped.
RMOLD
rule RMOLD ( targets * )
B2
removes any target files that may exist on disk when the rule used
to build those targets fails. However, targets whose dependencies fail
to build are not removed by default. The RMOLD
rule causes its
arguments to be removed if any of their dependencies fail to build.
ISFILE
rule ISFILE ( targets * )
ISFILE
marks targets as required to be files. This changes the way
b2
searches for the target such that it ignores matches for file
system items that are not files, like directories. This makes it
possible to avoid #include "exception"
matching if one happens to have
a directory named exception in the header search path.
|
⚠
|
This is currently not fully implemented. |
Utility
The two rules ECHO
and EXIT
are utility rules, used only in `b2`s
parsing phase.
EXIT
rule EXIT ( message * : result-value ? )
Blurts out the message to stdout and then exits with a failure status if no result-value is given, otherwise it exits with the given result-value.
Echo
, echo
, Exit
, and exit
are accepted as aliases for
ECHO
and EXIT
, since it is hard to tell that these are built-in
rules and not part of the language, like include
.
GLOB
The GLOB
rule does filename globing
rule GLOB ( directories * : patterns * : downcase-opt ? )
Using the same wildcards as for the patterns in the switch statement. It
is invoked by being used as an argument to a rule invocation inside of
"[ ]". For example: FILES = [ GLOB dir1 dir2 : *.c *.h ]
sets FILES
to
the list of C source
and header files in dir1
and dir2
. The resulting filenames are the
full pathnames, including the directory, but the pattern is applied only
to the file name without the directory.
If downcase-opt is supplied, filenames are converted to all-lowercase before matching against the pattern; you can use this to do case-insensitive matching using lowercase patterns. The paths returned will still have mixed case if the OS supplies them. On Windows NT and Cygwin, and OpenVMS, filenames are always down-cased before matching.
GLOB_ARCHIVE
The GLOB_ARCHIVE
rule does name globing of object archive members.
rule GLOB_ARCHIVE ( archives * : member-patterns * : downcase-opt ? : symbol-patterns ? )
Similarly to GLOB
, this rule is used to match names of member files in
an archive (static object library). List of successfully matched members
is returned or null otherwise. The resulting member names are qualified
with pathname of the containing archive in the form
archive-path(member-name)
. Member patterns are for matching member
name only; when no wildcards specified — an exact match is assumed.
Member names generally correspond to object file names and as such are
platform-specific — use of platform-defined object suffix in the
matching patterns can allow for portability.
If downcase-opt is supplied, the member names are converted to all-lowercase before matching against the pattern; you can use this to do case-insensitive matching using lowercase patterns. The paths returned will still have mixed case if the OS supplies them. On Windows NT, Cygwin, and OpenVMS, filenames are always down-cased before matching.
Additionally, members can be matched with symbol/function patterns on supported platforms (currently, OpenVMS only). In this case, members containing the matching symbols are returned. Member and symbol patterns are applied as OR conditions, with member patterns taking precedence. On unsupported platforms, null is returned when any symbol patterns are specified.
MATCH
The MATCH
rule does pattern matching.
rule MATCH ( regexps + : list * )
Matches the egrep
(1) style regular expressions regexps against the
strings in list. The result is a list of matching ()
subexpressions
for each string in list, and for each regular expression in regexps.
BACKTRACE
rule BACKTRACE ( )
Returns a list of quadruples: filename line module rulename…, describing each shallower level of the call stack. This rule can be used to generate useful diagnostic messages from Jam rules.
UPDATE
rule UPDATE ( targets * )
Classic jam treats any non-option element of command line as a name of
target to be updated. This prevented more sophisticated handling of
command line. This is now enabled again but with additional changes to
the UPDATE
rule to allow for the flexibility of changing the list of
targets to update. The UPDATE rule has two effects:
-
It clears the list of targets to update, and
-
Causes the specified targets to be updated.
If no target was specified with the UPDATE
rule, no targets will be
updated. To support changing of the update list in more useful ways, the
rule also returns the targets previously in the update list. This makes
it possible to add targets as such:
local previous-updates = [ UPDATE ] ;
UPDATE $(previous-updates) a-new-target ;
W32_GETREG
rule W32_GETREG ( path : data ? )
Defined only for win32 platform. It reads the registry of Windows. 'path' is the location of the information, and 'data' is the name of the value which we want to get. If 'data' is omitted, the default value of 'path' will be returned. The 'path' value must conform to MS key path format and must be prefixed with one of the predefined root keys. As usual,
-
HKLM
is equivalent toHKEY_LOCAL_MACHINE
. -
HKCU
is equivalent toHKEY_CURRENT_USER
. -
HKCR
is equivalent toHKEY_CLASSES_ROOT
.
Other predefined root keys are not supported.
Currently supported data types : REG_DWORD
, REG_SZ
,
REG_EXPAND_SZ
, REG_MULTI_SZ
. The data with REG_DWORD
type
will be turned into a string, REG_MULTI_SZ
into a list of strings,
and for those with REG_EXPAND_SZ
type environment variables in it
will be replaced with their defined values. The data with REG_SZ
type and other unsupported types will be put into a string without
modification. If it can’t receive the value of the data, it just return
an empty list. For example,
local PSDK-location =
[ W32_GETREG HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MicrosoftSDK\\Directories : "Install Dir" ] ;
W32_GETREGNAMES
rule W32_GETREGNAMES ( path : result-type )
Defined only for win32 platform. It reads the registry of Windows.
'path' is the location of the information, and 'result-type' is
either subkeys
or values
. For more information on 'path'
format and constraints, please see W32_GETREG
.
Depending on 'result-type', the rule returns one of the following:
subkeys
-
Names of all direct sub-keys of 'path'.
values
-
Names of values contained in registry key given by 'path'. The "default" value of the key appears in the returned list only if its value has been set in the registry.
If 'result-type' is not recognized, or requested data cannot be retrieved, the rule returns an empty list. Example:
local key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths" ;
local subkeys = [ W32_GETREGNAMES "$(key)" : subkeys ] ;
for local subkey in $(subkeys)
{
local values = [ W32_GETREGNAMES "$(key)\\$(subkey)" : values ] ;
for local value in $(values)
{
local data = [ W32_GETREG "$(key)\\$(subkey)" : "$(value)" ] ;
ECHO "Registry path: " $(key)\\$(subkey) ":" $(value) "=" $(data) ;
}
}
SHELL
rule SHELL ( command : * )
SHELL
executes command, and then returns the standard output of
command. SHELL
only works on platforms with a popen()
function in
the C library. On platforms without a working popen()
function,
SHELL
is implemented as a no-op. SHELL
works on Unix, MacOS X, and
most Windows compilers. SHELL
is a no-op on Metrowerks compilers under
Windows. There is a variable set of allowed options as additional
arguments:
exit-status
-
In addition to the output the result status of the executed command is returned as a second element of the result.
no-output
-
Don’t capture the output of the command. Instead an empty ("") string value is returned in place of the output.
strip-eol
-
Remove trailing end-of-line character from output, if any.
Because the Perforce/Jambase defines a SHELL
rule which hides the
builtin rule, COMMAND
can be used as an alias for SHELL
in such a
case.
SPLIT_BY_CHARACTERS
rule SPLIT_BY_CHARACTERS ( string : delimiters )
SPLIT_BY_CHARACTERS
splits the specified string on any delimiter
character present in delimiters and returns the resulting list.
PRECIOUS
rule PRECIOUS ( targets * )
The PRECIOUS
rule specifies that each of the targets passed as the
arguments should not be removed even if the command updating that target
fails.
PAD
rule PAD ( string : width )
If string is shorter than width characters, pads it with whitespace characters on the right, and returns the result. Otherwise, returns string unmodified.
FILE_OPEN
rule FILE_OPEN ( filename : mode )
The FILE_OPEN
rule opens the specified file and returns a file
descriptor if the mode parameter is either "w" or "r". Note that at
present, only the UPDATE_NOW
rule can use the resulting file
descriptor number. If the mode parameter is "t" this opens the file as a
text file and returns the contents as a single string.
UPDATE_NOW
rule UPDATE_NOW ( targets * : log ? : ignore-minus-n ? )
The UPDATE_NOW
caused the specified targets to be updated immediately.
If update was successful, non-empty string is returned. The log
parameter, if present, specifies a descriptor of a file where all output
from building is redirected. If the ignore-minus-n parameter is
specified, the targets are updated even if the -n
parameter is
specified on the command line.
12.2.5. Flow-of-Control
B2
has several simple flow-of-control statements:
for var in list { statements }
Executes statements for each element in list, setting the variable var to the element value.
if cond { statements }
[ else { statements } ]
Does the obvious; the else
clause is optional. cond is built of:
a
-
true if any a element is a non-zero-length string
a = b
-
list a matches list b string-for-string
a != b
-
list a does not match list b
a < b
-
a[i] string is less than b[i] string, where i is first mismatched element in lists a and b
a <= b
-
every a string is less than or equal to its b counterpart
a > b
-
a[i] string is greater than b[i] string, where i is first mismatched element
a >= b
-
every a string is greater than or equal to its b counterpart
a in b
-
true if all elements of a can be found in b, or if a has no elements
! cond
-
condition not true
cond && cond
-
conjunction
cond || cond
-
disjunction
( cond )
-
precedence grouping
include file ;
Causes b2
to read the named file. The file is bound like a regular
target (see Binding above) but unlike a regular target the include
file cannot be built.