diff --git a/v2/doc/architecture.html b/v2/doc/architecture.html deleted file mode 100644 index 02f9d5f37..000000000 --- a/v2/doc/architecture.html +++ /dev/null @@ -1,366 +0,0 @@ - - - -
- - - - - -This document is work-in progress. Don't expect much from it - yet.
-There are two user-visible kinds of targets in Boost.Build. First are - "abstract" — they correspond to things declared by user, for - example, projects and executable files. The primary thing about abstract - target is that it's possible to request them to be build with a - particular values of some properties. Each combination of properties may - possible yield different set of real file, so abstract target do not have - a direct correspondence with files.
- -File targets, on the contary, are associated with concrete files. - Dependency graphs for abstract targets with specific properties are - constructed from file targets. User has no was to create file targets, - however it can specify rules that detect file type for sources, and also - rules for transforming between file targets of different types. That - information is used in constructing dependency graph, as desribed in the - next section. Note:File targets are not - the same as targets in Jam sense; the latter are created from file - targets at the latest possible moment. Note:"File target" is a - proposed name for what we call virtual targets. It it more understandable - by users, but has one problem: virtual targets can potentially be - "phony", and not correspond to any file.
- -Dependency scanning is the process of finding implicit dependencies, - like "#include" statements in C++. The requirements for right dependency - scanning mechanism are:
- -Different scanning algorithm are encapsulated by objects called - "scanners". Please see the documentation for "scanner" module for more - details.
- -As said above, it's possible to compile a C++ file twice, with - different include paths. Therefore, include dependencies for those - compilations can be different. The problem is that bjam does not allow - several scans of the same target.
- -The solution in Boost.Build is straigtforward. When a virtual target - is converted to bjam target (via virtual-target.actualize - method), we specify the scanner object to be used. The actualize method - will create different bjam targets for different scanners.
- -All targets with specific scanner are made dependent on target without - scanner, which target is always created. This is done in case the target - is updated. The updating action will be associated with target without - scanner, but if sources for that action are touched, all targets — - with scanner and without should be considered outdated.
- -For example, assume that "a.cpp" is compiled by two compilers with - different include path. It's also copied into some install location. In - turn, it's produced from "a.verbatim". The dependency graph will look - like:
-- a.o (<toolset>gcc) <--(compile)-- a.cpp (scanner1) ----+ - a.o (<toolset>msvc) <--(compile)-- a.cpp (scanner2) ----| - a.cpp (installed copy) <--(copy) ----------------------- a.cpp (no scanner) - ^ - | - a.verbose --------------------------------+ - -- -
This requirement breaks down to the following ones.
- -The first requirement means that when determining what "a.h" means, - when found in "a.cpp", we have to iterate over all directories in include - paths, checking for each one:
- -Classic Jam has built-in facilities for point (1) above, but that's - not enough. It's hard to implement the right semantic without builtin - support. For example, we could try to check if there's targer called - "a.h" somewhere in dependency graph, and add a dependency to it. The - problem is that without search in include path, the semantic may be - incorrect. 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 header on platforms where native - one is included.
- -There are two design choices for builtin support. 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:
-- 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 used for some time. The problem however is: - what include paths should be used when scanning header.h? The second - alternative was suggested by Matt Armstrong. It has similiar effect: add - targets which depend on <scanner1>header.h will also depend on - <d2>header.h. But now we have two different target with two - different scanners, and those targets can be scanned independently. The - problem of first alternative is avoided, so the second alternative is - implemented now. - -
The second sub-requirements is that targets generated to "bin" - directory are handled as well. Boost.Build implements semi-automatic - approach. When compiling C++ files the process is:
- -After this is done, dependencies are found by the approach explained - previously.
- -Note that if a target uses generated headers from other main target, - that main target should be explicitly specified as dependency property. - It would be better to lift this requirement, but it seems not very - problematic in practice.
- -For target types other than C++, adding of include paths must be - implemented anew.
- -Suppose file "a.cpp" includes "a.h" and both are generated by some - action. Note that classic jam has two stages. In first stage dependency - graph graph is build and actions which should be run are determined. In - second stage the actions are executed. Initially, neither file exists, so - 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.
-- A -------> C ----> C.pro - / - B --/ C-includes ---> D - -- Both A and B have dependency on C and C-includes (the latter dependency - is not shown). Say during building we've tried to create A, then tried to - create C and successfully created C. - -
In that case, the set of includes in C might well have changed. We do - not bother to detect precisely which includes were added or removed. - Instead we create another internal node C-includes-2. Then we determine - what actions should be run to update the target. In fact this mean that - we perform logic of first stage while already executing stage.
- -After actions for C-includes-2 are determined, we add C-includes-2 to - the list of A's dependents, and stage 2 proceeds as usual. Unfortunately, - we can't do the same with target B, since when it's not visited, C target - does not know B depends on it. So, we add a flag to C which tells and it - was rescanned. When visiting B target, the flag is notices and - C-includes-2 will be added to the list of B's dependencies.
- -Note also that internal nodes are sometimes updated too. Consider this - dependency graph:
-- a.o ---> a.cpp - a.cpp-includes --> a.h (scanned) - a.h-includes ------> a.h (generated) - | - | - a.pro <-------------------------------------------+ -- -
Here, out handling of generated headers come into play. Say that a.h - exists but is out of date with respect to "a.pro", then "a.h (generated)" - and "a.h-includes" will be marking for updating, but "a.h (scanned)" - won't be marked. We have to rescan "a.h" file after it's created, but - since "a.h (generated)" has no scanner associated with it, it's only - possible to rescan "a.h" after "a.h-includes" target was updated.
- -Tbe above consideration lead to decision that we'll rescan a target - whenever it's updated, no matter if this target is internal or not.
- -To distinguish targets build with different properties, they are put - in different directories. Rules for determining target paths are given - below:
- -For example, we might have these paths:
-- debug/optimization-off - debug/main-target-a - --
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.
- - - - diff --git a/v2/doc/extending.html b/v2/doc/extending.html deleted file mode 100644 index 02d8ffb8c..000000000 --- a/v2/doc/extending.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - -This document explains how to extend Boost.Build to accomodate your - local requirements. Let's start with quite simple, but realistic - example.
- -Say you're writing an application which generates C++ code. If you - ever did this, you know that it's not nice. Embedding large portions of - C++ code in string literals is very awkward. A much better solution - is:
- -It's quite easy to archive. You write special verbatim files, which - are just C++, except that the very first line of the file gives a name of - variable that should be generated. A simple tool is created which takes - verbatim file and creates a cpp file with a single char* variable, which - name is taken from the first line of verbatim file, and which value is - properly quoted content of the verbatim file.
- -Let's see what Boost.Build can do.
- -First off, Boost.Build has no idea about "verbatim files". So, you - must register a new type. The following code does it:
-- import type ; - type.register VERBATIM : verbatim ; - -- -
The first parameter to 'type.register' gives the name of declared - type. By convention, it's uppercase. The second parameter is suffix for - this type. So, if Boost.Build sees "code.verbatim" in the list of - sources, it knows that it's of type VERBATIM.
- -Lastly, you need a tool to convert verbatim files to C++. Say you've - sketched such a tool in Python. Then, you have to inform Boost.Build - about the tool. The Boost.Build concept which represents a tool is - generator.
- -First, you say that generator 'inline-file' is able to convert - VERBATIM type into C++:
-- import generators ; - generators.register-standard verbatim.inline-file : VERBATIM : CPP ; - -- -
Second, you must specify the commands to be run to actually perform - convertion:
-
- actions inline-file
- {
- "./inline-file.py" $(<) $(>)
- }
-
-
-
-
- Now, we're ready to tie it all together. Put all the code above in - file "verbatim.jam", add "import verbatim ;" to "project-root.jam", and - it's possible to write the following in Jamfile:
-- exe codegen : codegen.cpp class_template.verbatim usage.verbatim ; - -- The verbatim files will be automatically converted into C++ and linked - it. - -
The complete code is available in example/customization - directory.
- -Last modified: Jule 3, 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.
- - - -