2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-01 08:22:15 +00:00

Move some stuff from user manual to architecture document.

[SVN r18899]
This commit is contained in:
Vladimir Prus
2003-07-01 06:34:43 +00:00
parent 4b6f3babbb
commit 04d450bab5
2 changed files with 243 additions and 118 deletions

View File

@@ -22,12 +22,12 @@
div.alert { color: red }
table { align: center; border: thin; }
</style>
</style>
</head>
<!-- Things yet to document:
- build request, build request expansion and directly requested targets
- conditional properties
-->
- build request, build request expansion and directly requested targets
- conditional properties
-->
<body>
<p><a href="../../index.htm"><img class="banner" height="86" width="277"
@@ -138,12 +138,12 @@
<tt>bjam</tt> there. A simple application will be built. You can also
play with other projects in <tt>examples-v2</tt>.
<!-- This part should not go into intoduction docs, but we need to place
it somewhere.
<p>It is slighly better way is to copy <tt>new/user-config.jam</tt>
into one of the locations where it can be found (given in <a href=
"#config_files_location">this table</a>). This prevent you from
accidentally overwriting your config when updating.</p> -->
it somewhere.
<p>It is slighly better way is to copy <tt>new/user-config.jam</tt>
into one of the locations where it can be found (given in <a href=
"#config_files_location">this table</a>). This prevent you from
accidentally overwriting your config when updating.</p> -->
</li>
</ol>
@@ -1461,17 +1461,17 @@ borland/runtime-link=static,dynamic
<li>It allows to have main target names with slashes.
<!-- The motivation for which is:
So, to summarize:
1. The project which extract tarfile may extract all possible kinds of
targets, and it's reasonable to use them directly from other project.
2. The rule for unpacking tar is inplemented in terms of "patch-file", for
maintainability, and therefore, must use main target name which contains
slashes?
3. Using sub-Jamfile in "foo" to declare extracted file "foo/b" is not an
option, because you should not change existing tree
So, to summarize:
1. The project which extract tarfile may extract all possible kinds of
targets, and it's reasonable to use them directly from other project.
2. The rule for unpacking tar is inplemented in terms of "patch-file", for
maintainability, and therefore, must use main target name which contains
slashes?
3. Using sub-Jamfile in "foo" to declare extracted file "foo/b" is not an
option, because you should not change existing tree
That makes good rationale for why main target must contain names.
-->
That makes good rationale for why main target must contain names.
-->
</li>
</ul>
@@ -1708,104 +1708,6 @@ borland/runtime-link=static,dynamic
special name and the found target list is stored. Later, when properties,
requested type, and source type are the same, the store target list is
retrieved and cloned, with appropriate change in names.
<h4 id="dependency_scanning">Dependency scanning</h4>
<p>Dependency scanning is the process of finding implicit dependencies
due to "include" statements and similar things. It has to take into
account two things:</p>
<ul>
<li>Whether includes in a particular file need to be taken into account
depends on actions that use that file. For example, if the action is
"copy file", then includes should be ignored. Another example is when a
file is compiled with two different include paths on different
toolsets.</li>
<li>It is possible to include generated header. In which case, it may
not yet exist at the time when we scan dependencies.</li>
</ul>
<p>Dependency scanning is implemented by objects called scanners. See
documentation for the "scanner" module to detail.</p>
<p>Regarding the first problem, we really have no choice. We can't treat
the same actual target differently depending on from where it is used.
Therefore, when handling of includes differers depending on actions, we
have to duplicate targets and assign different properties to it.</p>
<p>For the reason, when actualizing a virtual target we optionally pass
the needed scanner to the "virtual-target.actualize" method. When no
scanner is passed, a new actual target is created, with it's dependencies
and updating actions set accordingly. When a particular scanner is
specified, a new actual target is created. That target will depend on
target created without scanner. In effect, this will allow to use
different scanners for the same file.</p>
<h5>Generated headers</h5>
Let me explain what I find the right semantic, first without any
subvariants. We have a target "a.cpp" which includes "a_parser.h", we
have to search through all include directories, checking:
<ol>
<li>If there's such file there, or</li>
<li>If there's a target of the same name, bound to that dir via
LOCATE_TARGET.</li>
</ol>
Jam allows to do 1 via SEARCH variable, but that's not enough. Why can't
we do simpler: first check if there's target of the same name? I.e.
including of "a_parser.h" will already pick generated "a_parser.h",
regardless of search paths? Hmm... just because there's no reason to
assume that. For example, one can have an action which generated some
"dummy" header, for system which don't have the native one. Naturally, we
don't want to depend on that generated headers. To implement proposed
semantic we'd need a new builtin. We can do this in Jam code, but really,
this belongs to core. Using GLOB and jam code would just duplicate
existing binding functionality and be inefficient. New builtin will
accept a name of new target and a list of directories. It will perform
the search as explained above and return either the name of exising
target that it found, or create a new target with that name that it was
passed. So, we'd write something like
<blockquote>
<pre>
INCLUDES $(&lt;) : [ SEARCH_FOR_TARGET $(&gt;) : $(SEARCH_PATH) ] ;
</pre>
</blockquote>
What shall we do when using subvariants. For user, subvariants must be
more or less transparent. If without subvariant a header was generated to
a certain directory, everything must work. Suppose that file a.cpp
belongs to a dependency graph of main target a. Include paths are
<blockquote>
<pre>
"/usr/include" "/home/t" "."
</pre>
</blockquote>
We start by finding all places where headers that are part of a's
dependency graph are generated. We insert those places to the include
paths, immediately after ".". For example, we might end with:
<blockquote>
<pre>
"/usr/include" "/home/t" "." "build"
</pre>
</blockquote>
As a result:
<ol>
<li>File "a.cpp" will be correctly compiled. Note that it's already
necessary to adjust paths to ensure this. We'll have to add target
paths for all generated headers, because determining the exact set of
additional include path for each source -- i.e the set of headers that
it uses --- will be hard.</li>
<li>With the proposed SEARCH_FOR_TARGET rule, dependency on generated
header will work magically --- it would find the "a_parser.h" target
bound via LOCATE_TARGET to "build" and we'll call INCLUDE on that found
target, instread of creating a completely unrelated one.</li>
</ol>
<hr>
<p class="revision">Last modified: June 16, 2003</p>

223
doc/architecture.html Normal file
View File

@@ -0,0 +1,223 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1st April 2002), see www.w3.org">
<!--tidy options: -i -wrap 78 -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../boost.css">
<title>Boost.Build v2 user manual</title>
<style type="text/css">
hr { color: black }
p.revision { text-align: right; font-style: italic }
pre.code { margin-left: 2em }
pre.output { margin-left: 2em }
img.banner { border: 0; float: left }
h1 { text-align: right }
br.clear { clear: left }
div.alert { color: red }
table { align: center; border: thin; }
</style>
</head>
<!-- Things yet to document:
- build request, build request expansion and directly requested targets
- conditional properties
-->
<body>
<p><a href="../../index.htm"><img class="banner" height="86" width="277"
alt="C++ Boost" src="c++boost.gif"></a></p>
<h1>Boost.Build v2 architecture<br class="clear">
</h1>
<hr>
<dl class="page-index">
<dt><a href="#dependencies">Dependency scanning</a></dt>
</dl>
<hr>
<h2 id="dependency_scanning">Dependency scanning</h2>
<p>Dependency scanning is the process of finding implicit dependencies
due to "include" statements and similar things. It has to take into
account two things:</p>
<ul>
<li>Whether includes in a particular file need to be taken into account
depends on actions that use that file. For example, if the action is
"copy file", then includes should be ignored. Another example is when a
file is compiled with two different include paths on different
toolsets.</li>
<li>It is possible to include generated header. In which case, it may
not yet exist at the time when we scan dependencies.</li>
</ul>
<p>Dependency scanning is implemented by objects called scanners. See
documentation for the "scanner" module to detail.</p>
<p>Regarding the first problem, we really have no choice. We can't treat
the same actual target differently depending on from where it is used.
Therefore, when handling of includes differers depending on actions, we
have to duplicate targets and assign different properties to it.</p>
<p>For the reason, when actualizing a virtual target we optionally pass
the needed scanner to the "virtual-target.actualize" method. When no
scanner is passed, a new actual target is created, with it's dependencies
and updating actions set accordingly. When a particular scanner is
specified, a new actual target is created. That target will depend on
target created without scanner. In effect, this will allow to use
different scanners for the same file.</p>
<h3>Generated sources</h3>
Let me explain what I find the right semantic, first without any
subvariants. We have a target "a.cpp" which includes "a_parser.h", we
have to search through all include directories, checking:
<ol>
<li>If there's such file there, or</li>
<li>If there's a target of the same name, bound to that dir via LOCATE
variable.</li>
</ol>
Jam allows to do 1 via SEARCH variable, but that's not enough. Why can't
we do simpler: first check if there's target of the same name? I.e.
including of "a_parser.h" will already pick generated "a_parser.h",
regardless of search paths? Hmm... just because there's no reason to
assume that. For example, one can have an action which generated some
"dummy" header, for system which don't have the native one. Naturally, we
don't want to depend on that generated headers. To implement proposed
semantic we'd need builtin support.
<p>There are two design choices. Suppose we have files a.cpp and b.cpp,
and each one includes header.h, generated by some action. Dependency
graph created by classic jam would look like:</p>
<pre>
a.cpp -----&gt; &lt;scanner1&gt;header.h [search path: d1, d2, d3]
&lt;d2&gt;header.h --------&gt; header.y
[generated in d2]
b.cpp -----&gt; &lt;scanner2&gt;header.h [ search path: d1, d2, d4]
</pre>
In this case, Jam thinks all header.h target are not realated. The right
dependency graph might be:
<pre>
a.cpp ----
\
\
&gt;----&gt; &lt;d2&gt;header.h --------&gt; header.y
/ [generated in d2]
/
b.cpp ----
</pre>
or
<pre>
a.cpp -----&gt; &lt;scanner1&gt;header.h [search path: d1, d2, d3]
|
(includes)
V
&lt;d2&gt;header.h --------&gt; header.y
[generated in d2]
^
(includes)
|
b.cpp -----&gt; &lt;scanner2&gt;header.h [ search path: d1, d2, d4]
</pre>
The first alternative was use for some time. The problem however is: what
include paths should be used when scanning header.h? Originally, two
different sets of include paths were used. The second alternative does
not have this problem, so it's implemented now.
<h3>Includes between generated sources</h3>
<p>Suppose file "a.cpp" includes "a.h" and both are generated by some
action. Initially, neither file exists, so when classic jam constructs
dependency graph, the include is not found. As the result, jam might
attempt to compile a.cpp before creating a.h, and compilation will
fail.</p>
<p>The solution in Boost.Jam is to perform additional dependency scans
after targets are updated. This break separation between build stages in
jam &mdash; which some people consider a good thing &mdash; but I'm not
aware of any better solution.</p>
<p>In order to understand the rest of this section, you better read some
details about jam dependency scanning, available <a href=
"http://public.perforce.com:8080/@md=d&amp;cd=//public/jam/src/&amp;ra=s&amp;c=kVu@//2614?ac=10">
at this link</a>.</p>
<p>Whenever a target is updated, Boost.Jam rescans it for includes.
Consider this graph, created before any actions are run.</p>
<pre>
A -------&gt; C ----&gt; C.pro
/
B --/ C-includes ---&gt; D
</pre>
Both A and B have dependency on C and C-includes (the latter is not
shown). Say during building we've tried to create A, then tried to create
C and successfully created C. The B node wasn't seen yet. The C target is
rescanned, which creates new internal node. If we had those includes from
the start, we'd add this node to the list of A dependencies and B
dependencies. As it stands, we need to add it now.
<p>We determine what should be done with C-includes-2, add C-includes-2
to A's dependencies, and build the target. Unfortunately, we cannot do
the same with B, since we don't know that B is parent of C until we visit
B. So we add a special flag to C telling that it was rescanned. When we
process B, we'll add new dependency node to B's dependencies. this point
of time the target is requested by some parents. So parents were not yet
visited. Both visited and unvisited parents have What shall we do when
using subvariants. For user, subvariants must be more or less
transparent. If without subvariant a header was generated to a certain
directory, everything must work. Suppose that file a.cpp belongs to a
dependency graph of main target a. Include paths are</p>
<blockquote>
<pre>
"/usr/include" "/home/t" "."
</pre>
</blockquote>
We start by finding all places where headers that are part of a's
dependency graph are generated. We insert those places to the include
paths, immediately after ".". For example, we might end with:
<blockquote>
<pre>
"/usr/include" "/home/t" "." "build"
</pre>
</blockquote>
As a result:
<ol>
<li>File "a.cpp" will be correctly compiled. Note that it's already
necessary to adjust paths to ensure this. We'll have to add target
paths for all generated headers, because determining the exact set of
additional include path for each source -- i.e the set of headers that
it uses --- will be hard.</li>
<li>With the proposed SEARCH_FOR_TARGET rule, dependency on generated
header will work magically --- it would find the "a_parser.h" target
bound via LOCATE_TARGET to "build" and we'll call INCLUDE on that found
target, instread of creating a completely unrelated one.</li>
</ol>
<hr>
<p class="revision">Last modified: June 30, 2003</p>
<p>&copy; Copyright Vladimir Prus 2002-2003. Permission to copy, use,
modify, sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided ``as
is'' without express or implied warranty, and with no claim as to its
suitability for any purpose.</p>
<!-- sf logo -->
</body>
</html>