From b379061eb7addcac8b3040fa4b63ea457af90a95 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 7 Oct 2004 15:25:05 +0000 Subject: [PATCH] tools/build/v2/doc/architecture.html File removed. It's pretty old and will only confuse users. tools/build/v2/doc/extending.html File removed, all content is in BoostBook already. [SVN r25609] --- v2/doc/architecture.html | 366 --------------------------------------- v2/doc/extending.html | 154 ---------------- 2 files changed, 520 deletions(-) delete mode 100644 v2/doc/architecture.html delete mode 100644 v2/doc/extending.html 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 @@ - - - - - - - - - - Boost.Build v2 architecture - - - - - - -

- -

Boost.Build v2 architecture
-

-
- -
-

This document is work-in progress. Don't expect much from it - yet.

-
- -
-
Dependency scanning
-
-
- -

Targets

- -

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

- -

Dependency scanning is the process of finding implicit dependencies, - like "#include" statements in C++. The requirements for right dependency - scanning mechanism are:

- - - -

Support for different scanning algorithms

- -

Different scanning algorithm are encapsulated by objects called - "scanners". Please see the documentation for "scanner" module for more - details.

- -

Ability to scan the same file several times

- -

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 --------------------------------+
-   
-
- -

Proper detection of dependencies on generated files.

- -

This requirement breaks down to the following ones.

- -
    -
  1. If when compiling "a.cpp" there's include of "a.h", the "dir" - directory is in include path, and a target called "a.h" will be - generated to "dir", then bjam should discover the include, and create - "a.h" before compiling "a.cpp".
  2. - -
  3. Since almost always Boost.Build generates targets to a "bin" - directory, it should be supported as well. I.e. in the scanario above, - Jamfile in "dir" might create a main target, which generates "a.h". The - file will be generated to "dir/bin" directory, but we still have to - recornize the dependency.
  4. -
- -

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:

- -
    -
  1. If there's file "a.h" in that directory, or
  2. - -
  3. If there's a target called "a.h", which will be generated to that - directory.
  4. -
- -

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:

- -
    -
  1. The main target to which compiled file belongs is found.
  2. - -
  3. All other main targets that the found one depends on are found. - Those include main target which are used as sources, or present as - values of "dependency" features.
  4. - -
  5. All directories where files belonging to those main target will be - generated are added to the include path.
  6. -
- -

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.

- -

Proper detection of dependencies from generated files

- -

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.

- -
- The remainder of this document is not indended to be read at all. This - will be rearranged in future. -
- -

File targets

- As described above, file targets corresponds to files that Boost.Build - manages. User's may be concerned about file targets in three ways: when - declaring file target types, when declaring transformations between - types, and when determining where file target will be placed. File - targets can also be connected with actions, that determine how the target - is created. Both file targets and actions are implemented in the - virtual-target module. - -
Types
- A file target can be given a file, which determines what transformations - can be applied to the file. The type.register rule declares new - types. File type can also be assigned a scanner, which is used to find - implicit dependencies. See dependency - scanning below. - -

Target paths

- -

To distinguish targets build with different properties, they are put - in different directories. Rules for determining target paths are given - below:

- -
    -
  1. All targets are placed under directory corresponding to the project - where they are defined.
  2. - -
  3. Each non free, non incidental property cause an additional element - to be added to the target path. That element has the form - <feature-name>-<feature-value> for ordinary - features and <feature-value> for implicit ones. [Note - about composite features].
  4. - -
  5. If the set of free, non incidental properties is different from the - set of free, non incidental properties for the project in which the - main target that uses the target is defined, a part of the form - main_target-<name> is added to the target path. - Note:It would be nice to completely track free features also, - but this appears to be complex and not extremely needed.
  6. -
- -

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 @@ - - - - - - - - - - Boost.Build v2 extender manual - - - - - - -

- -

Boost.Build v2 extender manual
-

-
- -
-
Introduction
- -
Target types
- -
Tools
- -
Main target rules
- -
Scanners
-
-
- -

Introduction

- -

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:

- -
    -
  1. Write the template of the code to be generated, leaving - placeholders at the points which will change
  2. - -
  3. Access the template in your application and replace placeholders - with appropriate text.
  4. - -
  5. Write the result.
  6. -
- -

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.

- -

Target types

- -

Tools

- -

Main target rules

- -

Scanners

-
- -

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.

- - - -