mirror of
https://github.com/boostorg/build.git
synced 2026-02-16 01:12:13 +00:00
224 lines
9.2 KiB
HTML
224 lines
9.2 KiB
HTML
<!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>
|
|
|