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:
@@ -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 $(<) : [ SEARCH_FOR_TARGET $(>) : $(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
223
doc/architecture.html
Normal 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 -----> <scanner1>header.h [search path: d1, d2, d3]
|
||||
|
||||
|
||||
<d2>header.h --------> header.y
|
||||
[generated in d2]
|
||||
|
||||
b.cpp -----> <scanner2>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 ----
|
||||
\
|
||||
\
|
||||
>----> <d2>header.h --------> header.y
|
||||
/ [generated in d2]
|
||||
/
|
||||
b.cpp ----
|
||||
</pre>
|
||||
or
|
||||
<pre>
|
||||
a.cpp -----> <scanner1>header.h [search path: d1, d2, d3]
|
||||
|
|
||||
(includes)
|
||||
V
|
||||
<d2>header.h --------> header.y
|
||||
[generated in d2]
|
||||
^
|
||||
(includes)
|
||||
|
|
||||
b.cpp -----> <scanner2>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 — which some people consider a good thing — 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&cd=//public/jam/src/&ra=s&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 -------> C ----> C.pro
|
||||
/
|
||||
B --/ C-includes ---> 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>© 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>
|
||||
|
||||
Reference in New Issue
Block a user