1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Tools and generators</title>
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.69.1">
<link rel="start" href="../../index.html" title="PartI.Boost.Build v2 User Manual">
<link rel="up" href="../extender.html" title="Chapter5.Extender Manual">
<link rel="prev" href="targets.html" title="Target types">
<link rel="next" href="features.html" title="Features">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../boost.png"></td></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="targets.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../extender.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="features.html"><img src="../../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="bbv2.extending.tools"></a>Tools and generators</h2></div></div></div>
<p>
This section will describe how Boost.Build can be extended to support
new tools.
</p>
<p>For each additional tool, a Boost.Build object called generator
must be created. That object has specific types of targets that it
accepts and produces. Using that information, Boost.Build is able
to automatically invoke the generator. For example, if you declare a
generator that takes a target of the type <code class="literal">D</code> and
produces a target of the type <code class="literal">OBJ</code>, when placing a
file with extention <code class="literal">.d</code> in a list of sources will
cause Boost.Build to invoke your generator, and then to link the
resulting object file into an application. (Of course, this requires
that you specify that the <code class="literal">.d</code> extension corresponds
to the <code class="literal">D</code> type.)
</p>
<p>Each generator should be an instance of a class derived from the
<code class="computeroutput">generator</code> class. In the simplest case, you don't need to
create a derived class, but simply create an instance of the
<code class="computeroutput">generator</code> class. Let's review the example we've seen in the
<a href="../extender.html#bbv2.extender.intro" title="Introduction">introduction</a>.
</p>
<pre class="programlisting">
import generators ;
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
actions inline-file
{
"./inline-file.py" $(<) $(>)
}
</pre>
<p>
</p>
<p>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 <code class="literal">CPP</code> with a source target of
type <code class="literal">VERBATIM</code> as the only source. But what command
will be used to actually generate the file? In bjam, 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.
</p>
<p>
There are two primary kinds of generators: standard and composing,
which are registered with the
<code class="computeroutput">generators.register-standard</code> and the
<code class="computeroutput">generators.register-composing</code> rules, respectively. For
example:
</p>
<pre class="programlisting">
generators.register-standard verbatim.inline-file : VERBATIM : CPP ;
generators.register-composing mex.mex : CPP LIB : MEX ;
</pre>
<p>
Standard generators take a <span class="emphasis"><em>single</em></span> source of type
<code class="computeroutput">VERBATIM</code> and produces a result. The second generator
takes any number of sources, which can have either the
<code class="computeroutput">CPP</code> or the <code class="computeroutput">LIB</code> type. Composing generators
are typically used for generating top-level target type. For example,
the first generator invoked when building an <code class="computeroutput">exe</code> target
is a composing generator corresponding to the proper linker.
</p>
<p>You should also know about two specific functions for registering
generators: <code class="computeroutput">generators.register-c-compiler</code> and
<code class="computeroutput">generators.register-linker</code>. The first sets up header
dependecy 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.
</p>
<p>(Need a note about UNIX)</p>
<h3>
<a name="id2577024"></a>Custom generator classes</h3>
<p>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:
</p>
<pre class="programlisting">
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 ] ;
</pre>
<p>
This generator will work exactly like the
<code class="computeroutput">verbatim.inline-file</code> generator we've defined above, but
it's possible to customize the behaviour by overriding methods of the
<code class="computeroutput">generator</code> class.
</p>
<p>There are two methods of interest. The <code class="computeroutput">run</code> 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
<code class="computeroutput">generated-targets</code> method is called when all sources are
converted to the right types to actually create the result.
</p>
<p>The <code class="computeroutput">generated-target</code>
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
<code class="computeroutput">generated-targets</code> method can find the list of
sources automatically:
</p>
<pre class="programlisting">
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 ] ;
</pre>
<p>
The <code class="computeroutput">generated-targets</code> method will be called with a single
source target of type <code class="literal">EXE</code>. The call to
<code class="computeroutput">virtual-target.traverse</code> 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.
</p>
<p>The <code class="computeroutput">run</code> method can be overriden 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:
</p>
<pre class="programlisting">
rule run ( project name ? : property-set : sources * : multiple ? )
{
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) ] ;
}
</pre>
<p>
First, we separate all source into python files, libraries and C++
sources. For each C++ source we create a separate Python extension by
calling <code class="computeroutput">generators.construct</code> and passing the C++ source
and the libraries. At this point, we also change the extension's name,
if necessary.
</p>
</div>
<table width="100%"><tr>
<td align="left"></td>
<td align="right"><small></small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="targets.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../extender.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="features.html"><img src="../../images/next.png" alt="Next"></a>
</div>
</body>
</html>
|