From: Vladimir Prus (ghost_at_[hidden])
Date: 2003-03-26 02:39:56
as promised, I'm trying to describe how all those requirements and usage
requirements work. I first describe the meaning of putting library as
source/requirements/usage requirements, as Ali asked.
I then attach a document which describes how main target is build. This
involves getting usage requirements from sources and computing usage
requirements to be propagated upward (to the dependents (aka clients) of the
build library). The latter document will eventually end up in V2 docs. For
our current discussion the last section and "determining final build
properties" section are relevant.
I hope we can arrive at a spec which will satisfy everyone after several
Effect of putting library 'b' in source/requirement of 'a'
1. as a source of
- of exe --- usage requirements of 'b' are added to
properties used to build 'a'. 'b' is linked in.
- of lib --- ditto on usage requirements. No linking
in happens, because it's not possible, in general.
2. as a <library> property in requirements
effect the same as in (1)
3. as a <library> property in usage requirements
- no effect on 'a' itself. However, all target
which use 'a' will get <library>b in their
build properties. Usage requirements from 'b'
will be also added, recursively. This is the same
for both exe and lib, except that you won't likely
to use 'exe' in some other target.
4. as a <uses/<dependency> property in requirements.
- for both exe and lib --- usage requirements of 'b' are
added to properties used to build 'a'.
5. as a <uses/<dependency> property in usage requirements.
- target which uses 'a' will get <uses>b in build properties,
and 'b''s usage requirements as well.
- Volodya --------------Boundary-00=_KMICKNMVV6CUHMXZYCM5 Content-Type: text/html;
Content-Disposition: attachment; filename="build_process.html"
<title>Build process for a main target</title>
<h1>Build process for a main target</h1>
[Please refer to UML diagram in targets.jam to understand classes
Building a main target is a process which starts when building of main
target with specific properties is requested via call to
"main-target.generate" and ends when that method returns a list of
created virtual targets.
In short, the process is
<li>the "main-target" instance does first pass of modifying build
request. In particular, default build is applied.
<li>an alternative to use is selected and it's "generate" method is
<li>alternative further modifies properties, e.g. by applying requirements. It
also adds usage requirements of other main target the alternative uses.
<li>The 'basic-target.construct' method takes care of actually creating
<li>Usage requirements that must be assigned to the generated virtual targets
are determined and assigned.
<h2>Adjusting build request</h2>
<p>Main target (instance of "main-target" class) does the following
modifications of build request:
<li>Applying feature defaults,
<li>Adding directly requested free properties.
<p>The first step combines build request and the "default build"
attribute of main target.Each property in default build is added to the build request,
unless a value of the same feature is already specified. Default build
can contain two values of the same feature, meaning that in absense of
explicit value in build request several variant should be build. To achive
this, added default build was added, the result is expanded, which can
yield several property sets.
<tr><td>build request<td>default build<td>result
<tr><td>gcc<td>debug release<td>gcc/debug gcc/release
<p>The second step adds default values for features which are not yet
specified. For example, if build request specifies only "gcc",
the default "<link>shared" will be added.
<p>The third step is relevant only for directly requested target. We examine
all direct build requests, and for each one, find base properties and free
properties. If base properties are subset of the properties we're using now,
free properties are added. For example:
lib common : common.cpp ;
exe a : a.cpp common/<variant>release ;
exe b : b.cpp common/<variant>debug ;
<p>Here, during all builds, two variants of "common" will be
created. If user runs bjam as "bjam define=FOO", then direct build
request for "common" will be <define>FOO. Both release and
debug versions will be build with "FOO" defined.
<p>However, if user runs "bjam release define=FOO", then only
release version of "common" will be build with "FOO"
<h2>Selecting main target alternative</h2>
<p>After build request is adjusted, the resulting properties are used
to select a single alternative which will build the virtual targets.
The logic is in "main-target.select-alternative" method. It calls
the "basic-target.match-rank" method on all alternatives, and
selects the one which returned highest value. The value is equal to the
number of properties common to both build request and requirements of a
given alternative. Example:
lib a : a_win.cpp : <os>NT ;
lib a : a_relese.cpp : <variant>release ;
lib a : a_debug.cpp : <variant>debug ;
<p>When building "a" on Linux, with &<variant>release,
the first alternative can't be built at all and 'match-rank' will return empty
value, the match rank for the second alternative will be 1, and the match rank
for the third alternative will be 0. So, second alternative will be used.
<h2>Determining final build properties</h2>
<p>The selected alternative modifies properties further. First, <em>refined
properties</em> (or "rproperties" for short) are found (see
<li>properties are refined with requirements,
<li>conditional properties are evaluated,
<li>rule associated with features/properties are run
<p>After that, other main targer referred to from this one are build. This
includes sources which refer to other target and dependency properties from
rproperties. The build request for such main target is obtained by selecting
propagated properties from rproperties.
<p>The virtual targets generated for other main targets may have usage
requirements assigned to them. Those usage requirements are added to
rproperties, which gives final build properties.
<h2>Constructing the target</h2>
<p>The final build properties and the list of sources are passed to
"basic-target.construct" method, which must be defined in classes
derived from "basic-target". It will returns a list of virtual
targets. How it does so, is completely up to derived classes.
<h2>Applying usage requirements</h2>
<p>The usage requirements of main target alternative must be assigned to
the generated virtual target. The
"basic-target.set-usage-requirements" method takes care of this. The
algorithm consists of three steps:
<li>Conditional properties in usage requirements are evaluated. It is done in
context of rproperties — for example, if usage requirements are
<variant>debug:<define>FOO and rproperties contain
<variant>debug, then we'll get <define>FOO after evaluating
<li>Dependency properties are generated, using the same build request as when
<li>Usage requirements on generated dependency properties are added.
The obtained usage requiremets are assigned to virtual targets.
Boost-Build list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk