Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/build/v2/doc/src/architecture.xml @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 24.8 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE appendix PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
3  "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
4
5  <appendix id="bbv2.arch">
6    <title>Boost.Build v2 architecture</title>
7
8  <sidebar>
9    <para>This document is work-in progress. Don't expect much from it
10      yet.</para>
11  </sidebar>
12 
13  <section id="bbv2.arch.overview">
14    <title>Overview</title>
15
16    <para>The Boost.Build code is structured in four different components:
17    "kernel", "util", "build" and "tools". The first two are relatively
18    uninteresting, so we'll focus on the remaining pair. The "build" component
19    provides classes necessary to declare targets, determine which properties
20    should be used for their building, and for creating the dependency
21    graph. The "tools" component provides user-visible functionality. It
22    mostly allows to declare specific kind of main targets, and declare
23    avaiable tools, which are then used when creating the dependency graph.
24    </para>
25   
26  </section>
27
28  <section id="bbv2.arch.build">
29    <title>The build layer</title>
30
31      <para>The build layer has just four main parts -- metatargets (abstract targets),
32        virtual targets, generators and properties.
33        <itemizedlist>
34          <listitem><para>Metatargets (see the "targets.jam" module) represent
35              all the user-defined entities which can be built. The "meta" prefix
36              signify that they don't really corrspond to files -- depending of
37              build request, they can produce different set of
38              files. Metatargets are created when Jamfiles are loaded. Each
39              metagarget has a <code>generate</code> method which is given a
40              property set and produces virtual targets for the passed properties.
41            </para></listitem>
42          <listitem><para>Virtual targets (see the "virtual-targets.jam"
43              module) correspond to the atomic things which can be updated --
44              most typically files.
45            </para></listitem>
46          <listitem><para>Properties are just (name, value) pairs, specified
47              by the user and describing how the targets should be
48              built. Properties are stored using the <code>property-set</code> class.
49              </para></listitem>
50          <listitem><para>Generators are the objects which encapsulate tools
51              -- they can take a list of source virtual targets and produce new
52              virtual targets from them.
53            </para></listitem>
54        </itemizedlist>
55      </para>
56
57      <para>The build process includes those steps:
58        <orderedlist>
59          <listitem><para>Top-level code calls the <code>generate</code>
60              method of a metatarget with some properties.  </para></listitem>
61
62
63          <listitem><para>The metatarget combines the requested properties
64              with requirements and passes the result, together with the list
65              of sources, to the <code>generators.construct</code>
66              function</para></listitem> 
67
68         
69          <listitem><para>A generator appropriate for the build properties is
70              selected and its <code>run</code> method is
71              called. The method returns a list of virtual targets
72            </para></listitem>
73
74          <listitem><para>The targets are returned to the top level code. They
75              are converted into bjam targets (via
76              <code>virtual-target.actualize</code>) and passed to bjam for building.
77            </para></listitem>
78        </orderedlist>
79      </para>
80
81      <section id="bbv2.arch.metatargets">
82        <title>Metatargets</title>
83
84        <para>There are several classes derived from "abstract-target". The
85          "main-target" class represents top-level main target, the "project-target"
86          acts like container for all main targets, and "basic-target" class is a
87          base class for all further target types.
88        </para>
89       
90        <para>Since each main target can have several alternatives, all top-level
91          target objects are just containers, referring to "real" main target
92          classes. The type is that container is "main-target". For example, given:
93<programlisting>
94alias a ;
95lib a : a.cpp : &lt;toolset&gt;gcc ;
96</programlisting>
97          we would have one-top level instance of "main-target-class", which will
98          contain one instance of "alias-target-class" and one instance of
99          "lib-target-class". The "generate" method of "main-target" decides
100          which of the alternative should be used, and call "generate" on the
101          corresponding instance.
102        </para>
103
104        <para>Each alternative is a instance of a class derived from
105          "basic-target". The "basic-target.generate" does several things that are
106          always should be done:
107          <itemizedlist>
108            <listitem>
109              <para>Determines what properties should be used for building the
110                target. This includes looking at requested properties, requirements,
111                and usage requirements of all sources.</para>
112            </listitem>
113            <listitem>
114              <para>Builds all sources</para>
115            </listitem>
116            <listitem>
117              <para>Computes the usage requirements which should be passes back.</para>
118            </listitem>
119          </itemizedlist>
120          For the real work of constructing virtual target, a new method
121          "construct" is called.
122        </para>
123
124        <para>The "construct" method can be implemented in any way by classes
125          derived from "basic-target", but one specific derived class plays the
126          central role -- "typed-target". That class holds the desired type of file
127          to be produces, and calls the generators modules to do the job.
128        </para>
129
130        <para>This means that a specific metatarget subclass may avoid using
131          generators at all. However, this is deprecated and we're trying to
132          eliminate all such subsclasses at the moment.
133        </para>
134
135        <para>Note that the <filename>build/targets.jam</filename> file contains
136            an UML diagram which might help.</para>
137
138      </section>
139
140      <section id="bbv2.arch.virtual">
141        <title>Virtual targets</title>
142
143        <para>Virtual targets correspond to the atomic things which can be
144          updated. Each virtual target can be assigned an updating action --
145          instance of the <code>action</code> class. The action class, in
146          turn, contains a list of source targets, properties, and a name of
147          bjam action block which should be executed.
148        </para>
149
150        <para>We try hard to never create equal instances of the
151          <code>virtual-target</code> class. Each code which creates virtual
152          targets passes them though the <code>virtual-target.register</code>
153          function, which detects if a target with the same name, sources, and
154          properties was created. In that case, existing target is returned.
155        </para>
156       
157        <para>When all virtual targets are produced, they are
158          "actualized". This means that the real file names are computed, and
159          the commands that should be run are generated. This is done by the
160          <code>virtual-target.actualize</code> method and the
161          <code>action.actualize</code> methods. The first is conceptually
162          simple, while the second need additional explanation. The commands
163          in bjam are generated in two-stage process. First, a rule with the
164          appropriate name (for example
165          "gcc.compile") is called and is given the names of targets. The rule
166          sets some variables, like "OPTIONS". After that, the command string
167          is taken, and variable are substitutes, so use of OPTIONS inside the
168          command string become the real compile options.
169        </para>
170
171        <para>Boost.Build added a third stage to simplify things. It's now
172          possible to automatically convert properties to appropriate assignments to
173          variables. For example, &lt;debug-symbols&gt;on would add "-g" to the
174          OPTIONS variable, without requiring to manually add this logic to
175          gcc.compile. This functionality is part of the "toolset" module.
176        </para>
177
178        <para>Note that the <filename>build/virtual-targets.jam</filename> file
179            contains an UML diagram which might help.</para>
180      </section>
181
182      <section id="bbv2.arch.properties">
183        <para>Above, we noted that metatargets are built with a set of
184          properties. That set is represented with the
185          <code>property-set</code> class. An important point is that handling
186          of property sets can get very expensive. For that reason, we make
187          sure that for each set of (name, value) pairs only one
188          <code>property-set</code> instance is created. The
189          <code>property-set</code> uses extensive caching for all operation,
190          so most work is avoided. The <code>property-set.create</code> is the
191          factory function which should be used to create instances of the
192          <code>property-set</code> class.
193        </para>
194      </section>
195     
196       
197  </section>
198
199  <section id="bbv2.arch.tools">
200    <title>The tools layer</title>
201
202    <para>Write me!</para>
203
204  </section>
205 
206    <section id="bbv2.arch.targets">
207      <title>Targets</title>
208
209  <para>NOTE: THIS SECTION IS NOT EXPECTED TO BE READ!
210        There are two user-visible kinds of targets in Boost.Build.
211  First are "abstract" &#x2014; they correspond to things declared
212  by user, for example, projects and executable files. The primary
213  thing about abstract target is that it's possible to request them
214  to be build with a particular values of some properties. Each
215  combination of properties may possible yield different set of
216  real file, so abstract target do not have a direct correspondence
217  with files.</para>
218
219  <para>File targets, on the contary, are associated with concrete
220  files. Dependency graphs for abstract targets with specific
221  properties are constructed from file targets. User has no was to
222  create file targets, however it can specify rules that detect
223  file type for sources, and also rules for transforming between
224  file targets of different types. That information is used in
225  constructing dependency graph, as desribed in the "next section".
226  [ link? ] <emphasis role="bold">Note:</emphasis>File targets are not
227  the same as targets in Jam sense; the latter are created from
228  file targets at the latest possible moment. <emphasis role="bold">Note:</emphasis>"File
229  target" is a proposed name for what we call virtual targets. It
230  it more understandable by users, but has one problem: virtual
231  targets can potentially be "phony", and not correspond to any
232  file.</para>
233
234    <section id="bbv2.arch.depends">
235      <title>Dependency scanning</title>
236
237  <para>Dependency scanning is the process of finding implicit
238  dependencies, like "#include" statements in C++. The requirements
239  for right dependency scanning mechanism are:</para>
240
241  <itemizedlist>
242    <listitem>
243      <simpara>
244        Support for different scanning algorithms. C++ and XML have
245    quite different syntax for includes and rules for looking up
246    included files.
247      </simpara>
248    </listitem>
249
250    <listitem>
251      <simpara>
252        Ability to scan the same file several times. For example,
253    single C++ file can be compiled with different include
254    paths.
255      </simpara>
256    </listitem>
257
258    <listitem>
259      <simpara>
260        Proper detection of dependencies on generated files.
261      </simpara>
262    </listitem>
263
264    <listitem>
265      <simpara>
266        Proper detection of dependencies from generated file.
267      </simpara>
268    </listitem>
269  </itemizedlist>
270
271      <section>
272        <title>Support for different scanning algorithms</title>
273
274  <para>Different scanning algorithm are encapsulated by objects
275  called "scanners". Please see the documentation for "scanner"
276  module for more details.</para>
277
278      </section>
279
280      <section>
281        <title>Ability to scan the same file several times</title>
282
283  <para>As said above, it's possible to compile a C++ file twice, with
284  different include paths. Therefore, include dependencies for
285  those compilations can be different. The problem is that bjam
286  does not allow several scans of the same target.</para>
287
288  <para>The solution in Boost.Build is straigtforward. When a virtual
289  target is converted to bjam target (via
290  <literal>virtual-target.actualize</literal> method), we specify the scanner
291  object to be used. The actualize method will create different
292  bjam targets for different scanners.</para>
293
294  <para>All targets with specific scanner are made dependent on target
295  without scanner, which target is always created. This is done in
296  case the target is updated. The updating action will be
297  associated with target without scanner, but if sources for that
298  action are touched, all targets &#x2014; with scanner and without
299  should be considered outdated.</para>
300
301  <para>For example, assume that "a.cpp" is compiled by two compilers
302  with different include path. It's also copied into some install
303  location. In turn, it's produced from "a.verbatim". The
304  dependency graph will look like:</para>
305
306<programlisting>
307a.o (&lt;toolset&gt;gcc)  &lt;--(compile)-- a.cpp (scanner1) ----+
308a.o (&lt;toolset&gt;msvc) &lt;--(compile)-- a.cpp (scanner2) ----|
309a.cpp (installed copy)    &lt;--(copy) ----------------------- a.cpp (no scanner)
310                                                                 ^
311                                                                 |
312                       a.verbose --------------------------------+
313</programlisting>
314
315      </section>
316      <section>
317        <title>Proper detection of dependencies on generated files.</title>
318
319  <para>This requirement breaks down to the following ones.</para>
320
321  <orderedlist>
322    <listitem>
323      <simpara>
324        If when compiling "a.cpp" there's include of "a.h", the
325    "dir" directory is in include path, and a target called "a.h"
326    will be generated to "dir", then bjam should discover the
327    include, and create "a.h" before compiling "a.cpp".
328      </simpara>
329    </listitem>
330
331    <listitem>
332      <simpara>
333      Since almost always Boost.Build generates targets to a
334    "bin" directory, it should be supported as well. I.e. in the
335    scanario above, Jamfile in "dir" might create a main target,
336    which generates "a.h". The file will be generated to "dir/bin"
337    directory, but we still have to recornize the dependency.
338      </simpara>
339    </listitem>
340  </orderedlist>
341
342  <para>The first requirement means that when determining what "a.h"
343  means, when found in "a.cpp", we have to iterate over all
344  directories in include paths, checking for each one:</para>
345
346  <orderedlist>
347    <listitem>
348      <simpara>
349        If there's file "a.h" in that directory, or
350      </simpara>
351    </listitem>
352
353    <listitem>
354      <simpara>
355        If there's a target called "a.h", which will be generated
356    to that directory.
357      </simpara>
358    </listitem>
359  </orderedlist>
360
361  <para>Classic Jam has built-in facilities for point (1) above, but
362  that's not enough. It's hard to implement the right semantic
363  without builtin support. For example, we could try to check if
364  there's targer called "a.h" somewhere in dependency graph, and
365  add a dependency to it. The problem is that without search in
366  include path, the semantic may be incorrect. For example, one can
367  have an action which generated some "dummy" header, for system
368  which don't have the native one. Naturally, we don't want to
369  depend on that generated header on platforms where native one is
370  included.</para>
371
372  <para>There are two design choices for builtin support. Suppose we
373  have files a.cpp and b.cpp, and each one includes header.h,
374  generated by some action. Dependency graph created by classic jam
375  would look like:</para>
376
377<programlisting>
378a.cpp -----&gt; &lt;scanner1&gt;header.h  [search path: d1, d2, d3]
379
380
381                  &lt;d2&gt;header.h  --------&gt; header.y
382                  [generated in d2]
383           
384b.cpp -----&gt; &lt;scanner2&gt;header.h [ search path: d1, d2, d4]
385</programlisting>
386
387    <para>
388In this case, Jam thinks all header.h target are not
389realated. The right dependency graph might be:
390
391<programlisting>
392a.cpp ----
393          \
394           \     
395            &gt;----&gt;  &lt;d2&gt;header.h  --------&gt; header.y
396           /       [generated in d2]
397          /
398b.cpp ----
399</programlisting>
400
401or
402
403<programlisting>
404a.cpp -----&gt; &lt;scanner1&gt;header.h  [search path: d1, d2, d3]
405                          |
406                       (includes)
407                          V
408                  &lt;d2&gt;header.h  --------&gt; header.y
409                  [generated in d2]
410                          ^
411                      (includes) 
412                          |
413b.cpp -----&gt; &lt;scanner2&gt;header.h [ search path: d1, d2, d4]
414</programlisting>
415        </para>
416
417        <para>
418The first alternative was used for some time. The problem
419however is: what include paths should be used when scanning
420header.h? The second alternative was suggested by Matt Armstrong.
421It has similiar effect: add targets which depend on
422&lt;scanner1&gt;header.h will also depend on &lt;d2&gt;header.h.
423But now we have two different target with two different scanners,
424and those targets can be scanned independently. The problem of
425first alternative is avoided, so the second alternative is
426implemented now.
427        </para>
428
429  <para>The second sub-requirements is that targets generated to "bin"
430  directory are handled as well. Boost.Build implements
431  semi-automatic approach. When compiling C++ files the process
432  is:</para>
433
434  <orderedlist>
435    <listitem>
436      <simpara>
437        The main target to which compiled file belongs is found.
438      </simpara>
439    </listitem>
440
441    <listitem>
442      <simpara>
443        All other main targets that the found one depends on are
444    found. Those include main target which are used as sources, or
445    present as values of "dependency" features.
446      </simpara>
447    </listitem>
448
449    <listitem>
450      <simpara>
451        All directories where files belonging to those main target
452    will be generated are added to the include path.
453      </simpara>
454    </listitem>
455  </orderedlist>
456
457  <para>After this is done, dependencies are found by the approach
458  explained previously.</para>
459
460  <para>Note that if a target uses generated headers from other main
461  target, that main target should be explicitly specified as
462  dependency property. It would be better to lift this requirement,
463  but it seems not very problematic in practice.</para>
464
465  <para>For target types other than C++, adding of include paths must
466  be implemented anew.</para>
467
468      </section>
469      <section>
470        <title>Proper detection of dependencies from generated files</title>
471
472  <para>Suppose file "a.cpp" includes "a.h" and both are generated by
473  some action. Note that classic jam has two stages. In first stage
474  dependency graph graph is build and actions which should be run
475  are determined. In second stage the actions are executed.
476  Initially, neither file exists, so the include is not found. As
477  the result, jam might attempt to compile a.cpp before creating
478  a.h, and compilation will fail.</para>
479
480  <para>The solution in Boost.Jam is to perform additional dependency
481  scans after targets are updated. This break separation between
482  build stages in jam &#x2014; which some people consider a good
483  thing &#x2014; but I'm not aware of any better solution.</para>
484
485  <para>In order to understand the rest of this section, you better
486  read some details about jam dependency scanning, available
487  <ulink url=
488  "http://public.perforce.com:8080/@md=d&amp;cd=//public/jam/src/&amp;ra=s&amp;c=kVu@//2614?ac=10">
489  at this link</ulink>.</para>
490
491  <para>Whenever a target is updated, Boost.Jam rescans it for
492  includes. Consider this graph, created before any actions are
493  run.</para>
494
495<programlisting>
496A -------&gt; C ----&gt; C.pro
497     /
498B --/         C-includes   ---&gt; D
499</programlisting>
500
501        <para>
502Both A and B have dependency on C and C-includes (the latter
503dependency is not shown). Say during building we've tried to create
504A, then tried to create C and successfully created C.
505        </para>
506
507  <para>In that case, the set of includes in C might well have
508  changed. We do not bother to detect precisely which includes were
509  added or removed. Instead we create another internal node
510  C-includes-2. Then we determine what actions should be run to
511  update the target. In fact this mean that we perform logic of
512  first stage while already executing stage.</para>
513
514  <para>After actions for C-includes-2 are determined, we add
515  C-includes-2 to the list of A's dependents, and stage 2 proceeds
516  as usual. Unfortunately, we can't do the same with target B,
517  since when it's not visited, C target does not know B depends on
518  it. So, we add a flag to C which tells and it was rescanned. When
519  visiting B target, the flag is notices and C-includes-2 will be
520  added to the list of B's dependencies.</para>
521
522  <para>Note also that internal nodes are sometimes updated too.
523  Consider this dependency graph:</para>
524
525<programlisting>
526a.o ---&gt; a.cpp
527            a.cpp-includes --&gt;  a.h (scanned)
528                                   a.h-includes ------&gt; a.h (generated)
529                                                                 |
530                                                                 |
531            a.pro &lt;-------------------------------------------+
532</programlisting>
533
534  <para>Here, out handling of generated headers come into play. Say
535  that a.h exists but is out of date with respect to "a.pro", then
536  "a.h (generated)" and "a.h-includes" will be marking for
537  updating, but "a.h (scanned)" won't be marked. We have to rescan
538  "a.h" file after it's created, but since "a.h (generated)" has no
539  scanner associated with it, it's only possible to rescan "a.h"
540  after "a.h-includes" target was updated.</para>
541
542  <para>Tbe above consideration lead to decision that we'll rescan a
543  target whenever it's updated, no matter if this target is
544  internal or not.</para>
545
546  <warning>
547    <para>
548    The remainder of this document is not indended to be read at
549    all. This will be rearranged in future.
550    </para>
551  </warning>
552
553        <section>
554          <title>File targets</title>
555 
556          <para>
557  As described above, file targets corresponds
558  to files that Boost.Build manages. User's may be concerned about
559  file targets in three ways: when declaring file target types,
560  when declaring transformations between types, and when
561  determining where file target will be placed. File targets can
562  also be connected with actions, that determine how the target is
563  created. Both file targets and actions are implemented in the
564  <literal>virtual-target</literal> module.
565          </para>
566
567            <section> 
568              <title>Types</title>
569             
570              <para>A file target can be given a file, which determines
571  what transformations can be applied to the file. The
572  <literal>type.register</literal> rule declares new types. File type can
573  also be assigned a scanner, which is used to find implicit
574  dependencies. See "dependency scanning" [ link? ] below.</para>
575            </section>
576          </section>
577
578          <section>
579            <title>Target paths</title>
580
581  <para>To distinguish targets build with different properties, they
582  are put in different directories. Rules for determining target
583  paths are given below:</para>
584
585  <orderedlist>
586    <listitem>
587      <simpara>
588        All targets are placed under directory corresponding to the
589    project where they are defined.
590      </simpara>
591        </listitem>
592
593    <listitem>
594      <simpara>
595        Each non free, non incidental property cause an additional
596    element to be added to the target path. That element has the
597    form <literal>&lt;feature-name&gt;-&lt;feature-value&gt;</literal> for
598    ordinary features and <literal>&lt;feature-value&gt;</literal> for
599    implicit ones. [Note about composite features].
600      </simpara>
601        </listitem>
602
603    <listitem>
604      <simpara>
605        If the set of free, non incidental properties is different
606    from the set of free, non incidental properties for the project
607    in which the main target that uses the target is defined, a
608    part of the form <literal>main_target-&lt;name&gt;</literal> is added to
609    the target path. <emphasis role="bold">Note:</emphasis>It would be nice to completely
610    track free features also, but this appears to be complex and
611    not extremely needed.
612      </simpara>
613        </listitem>
614  </orderedlist>
615
616  <para>For example, we might have these paths:</para>
617
618<programlisting>
619debug/optimization-off
620debug/main-target-a
621</programlisting>
622
623          </section>
624        </section>
625      </section>
626    </section>
627  </appendix>
628
629<!--
630     Local Variables:
631     mode: xml
632     sgml-indent-data: t     
633     sgml-parent-document: ("userman.xml" "chapter")
634     sgml-set-face: t
635     End:
636-->
Note: See TracBrowser for help on using the repository browser.