diff --git a/boost_build_v2.html b/boost_build_v2.html index b4878d3ce..0230df7c7 100644 --- a/boost_build_v2.html +++ b/boost_build_v2.html @@ -22,12 +22,12 @@ div.alert { color: red } table { align: center; border: thin; } - + + - build request, build request expansion and directly requested targets + - conditional properties + -->
It is slighly better way is to copy new/user-config.jam
+ into one of the locations where it can be found (given in this table). This prevent you from
+ accidentally overwriting your config when updating. Dependency scanning is the process of finding implicit dependencies
- due to "include" statements and similar things. It has to take into
- account two things: Dependency scanning is implemented by objects called scanners. See
- documentation for the "scanner" module to detail. 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. 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. Last modified: June 16, 2003 Dependency scanning is the process of finding implicit dependencies
+ due to "include" statements and similar things. It has to take into
+ account two things: Dependency scanning is implemented by objects called scanners. See
+ documentation for the "scanner" module to detail. 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. 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. 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: 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. 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. In order to understand the rest of this section, you better read some
+ details about jam dependency scanning, available
+ at this link. Whenever a target is updated, Boost.Jam rescans it for includes.
+ Consider this graph, created before any actions are run. 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 Last modified: June 30, 2003 © 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.bjam there. A simple application will be built. You can also
play with other projects in examples-v2.
+ it somewhere.
+
+
Dependency scanning
-
-
-
-
- Generated headers
- 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:
-
-
-
- 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
-
-
-
- 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
-
-
- INCLUDES $(<) : [ SEARCH_FOR_TARGET $(>) : $(SEARCH_PATH) ] ;
-
-
-
- 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:
-
-
- "/usr/include" "/home/t" "."
-
-
-
- As a result:
-
-
- "/usr/include" "/home/t" "." "build"
-
-
-
Boost.Build v2 architecture
+
+
+
+
+
+
+ Dependency scanning
+
+
+
+
+ Generated sources
+ 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:
+
+
+
+ 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.
+
+
+ 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]
+
+ In this case, Jam thinks all header.h target are not realated. The right
+ dependency graph might be:
+
+ a.cpp ----
+ \
+ \
+ >----> <d2>header.h --------> header.y
+ / [generated in d2]
+ /
+ b.cpp ----
+
+ or
+
+ 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]
+
+ 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.
+
+ Includes between generated sources
+
+
+ A -------> C ----> C.pro
+ /
+ B --/ C-includes ---> D
+
+
+ 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.
+
+
+
+ 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:
+
+
+ "/usr/include" "/home/t" "."
+
+
+
+ As a result:
+
+
+ "/usr/include" "/home/t" "." "build"
+
+
+
+
+
+