From ffbb9947de27817fa2990fafcb033c43f3b6adeb Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 28 Dec 2004 03:39:09 +0000 Subject: [PATCH] First edits for Volodya. [SVN r26590] --- doc/src/install.xml | 13 +- doc/src/tutorial.xml | 623 ++++++++++++++++++++++++++++++------------- 2 files changed, 443 insertions(+), 193 deletions(-) diff --git a/doc/src/install.xml b/doc/src/install.xml index c81d88b56..8a324d8b3 100644 --- a/doc/src/install.xml +++ b/doc/src/install.xml @@ -7,7 +7,18 @@ This section describes how to install Boost.Build from a - released source distribution. All paths are given relative to + released Boost source distribution. + + Note that packages prepared for + Unix/Linux systems usually make their own choices about where to + put things and even which parts of Boost to include. When we + say “released source distribution” we mean a + distribution of Boost as released on its SourceForge + project + page. + + +All paths are given relative to the Boost.Build v2 root directory, which is + + + +
Hello, world @@ -21,10 +26,10 @@ exe hello : hello.cpp ; Even with this simple setup, you can do some interesting things. First of all, just invoking bjam will - build the debug variant of the hello + build the debug variant of the hello> executable by compiling and linking hello.cpp. Now, to build the - release variant of hello, invoke + release variant of hello, invoke bjam release @@ -43,15 +48,19 @@ exe hello2 : hello.cpp ; Now we can build both the debug and release variants of our project: + + + + bjam debug release - Note that two variants of hello2 are linked. + Note that two variants of hello2 are linked. Since we have already built both variants - of hello, hello.cpp won't be recompiled; + of hello, hello.cpp won't be recompiled; instead the existing object files will just be linked into the - corresponding variants of hello2. Now + corresponding variants of hello2. Now let's remove all the built products: @@ -60,7 +69,10 @@ bjam --clean debug release It's also possible to build or clean specific targets. The following two commands, respectively, build or clean only the - debug version of hello2. + debug version of hello2. + + bjam hello2 @@ -77,8 +89,8 @@ bjam --clean hello2 debug and release variants, or single- and multi-threaded builds, Boost.Build uses features with associated values. For - example, the "debug-symbols" feature can have a value of "on" or - "off". A property is just a (feature, + example, the debug-symbols feature can have a value of on or + off. A property is just a (feature, value) pair. When a user initiates a build, Boost.Build automatically translates the requested properties into appropriate command-line flags for invoking toolset components like compilers @@ -86,7 +98,7 @@ bjam --clean hello2 There are many built-in features that can be combined to produce arbitrary build configurations. The following command - builds the project's "release" variant with inlining + builds the project's release variant with inlining disabled and debug symbols enabled: @@ -101,9 +113,9 @@ bjam release inlining=off debug-symbols=on - The "release" and "debug" that we've seen + The and that we've seen in bjam invocations are just a shorthand way to - specify values of the "variant" feature. For example, the command + specify values of the variant feature. For example, the command above could also have been written this way: @@ -111,15 +123,16 @@ bjam variant=release inlining=off debug-symbols=on - "variant" is so commonly-used that it has been given - special status as an implicit feature - — Boost.Build will deduce the its identity just from the name - of one of its values. + variant is so commonly-used that it has + been given special status as an implicit + feature—Boost.Build will deduce the its identity just + from the name of one of its values. - A complete description of features can be found - here. + A complete description of features can be found in . + + @@ -128,7 +141,7 @@ bjam variant=release inlining=off debug-symbols=on The set of properties specified in the command line constitute a - build request — a description of + build request—a description of the desired properties for building the requested targets (or, if no targets were explicitly requested, the project in the current directory). The actual properties @@ -152,16 +165,24 @@ exe hello ; + + When hello is built, the two requirements specified above will normally always be present. If the build request given on the bjam command-line explictly contradicts a target's requirements, the command-line usually overrides (or, in the case of - "free" feautures like <include> - See , - augments) the target requirements. + “free” features like <include>, + + +See + augments) the target requirements. + + + + + + +
@@ -195,7 +221,7 @@ exe hello2 : hello.cpp ; The effect would be as if we specified the same requirement for - both hello and hello2. + both hello and hello2.
@@ -205,7 +231,7 @@ exe hello2 : hello.cpp ; So far we've only considered examples with one project (i.e. with one Jamfile). A typical large - software project would be composed of sub-projects organized + codebase would be composed of many projects organized into a tree. The top of the tree is called the project root. Besides a Jamfile, the project root directory @@ -215,6 +241,9 @@ exe hello2 : hello.cpp ; Jamfile. For example, in the following directory layout: + + + top/ | @@ -256,11 +285,15 @@ top/ in its requirements, then all of its sub-projects will have it in their requirements, too. Of course, any project can add - additional includes. Many features will be overridden, + include paths to those specified by its parents. + Many + features will be overridden, rather than added-to, in sub-projects. See for more - information More details can be found in the section - on projects. + information + + More details can be found in + . @@ -286,11 +319,17 @@ build-project src ;
Libraries and Dependent Targets - TODO: need to make this - section consistent with "examples-v2/libraries". + TODO: need to make this + section consistent with "examples-v2/libraries". + + - Targets that are "needed" by other targets are called + Targets that are “needed” by other targets are called dependencies of those other targets. The targets that need the other targets are called dependent targets. @@ -313,30 +352,41 @@ exe app : app.cpp ../util/foo//bar ; While app.cpp refers to a regular source file, ../util/foo//bar is a reference to another target: - a library "bar" declared in the Jamfile at + a library bar declared in the Jamfile at ../util/foo. When linking the - app executable, the appropriate version of + app executable, the appropriate version of bar will be built and linked in. What do we mean by - "appropriate"? For example, suppose we build "app" with: + “appropriate”? For example, suppose we build app with: bjam app optimization=full cxxflags=-w-8080 + + Which properties must be used to build foo? The answer is that some properties are - propagated — Boost.Build attempts to + propagated—Boost.Build attempts to use dependencies with the same value of propagated features. The - <optimization> feature is propagated, so both "app" and - "foo" will be compiled with full optimization. But - <cxxflags> feature is not propagated: its value will be - added as-is to compiler flags for "a.cpp", but won't affect - "foo". There is still a couple of problems. First, the library - probably has some headers which must be used when compiling - "app.cpp". We could use requirements on "app" to add those - includes, but then this work will be repeated for all programs - which use "foo". A better solution is to modify - util/foo/Jamfilie in this way: + <optimization> feature is propagated, so both app and + foo will be compiled with full optimization. But + <cxxflags> is not propagated: its value will be + added as-is to the compiler flags for a.cpp, but won't affect + foo. There are still a couple of problems. First, the library + probably has some headers that must be used when compiling + app.cpp. We could manually add the neccessary + #include paths to app's + requirements as values of the + <include> feature, but then this work will be repeated for all programs + that use foo. A better solution is to modify + util/foo/Jamfile in this way: + + project @@ -346,24 +396,44 @@ project lib foo : foo.cpp ; - Usage requirements are requirements which are applied to - dependents. In this case, <include> will be applied to all - targets which use "foo" — i.e. targets which have "foo" - either in sources or in dependency properties. You'd need to - specify usage requirements only once, and programs which use "foo" - don't have to care about include paths any longer. Or course, the - path will be interpreted relatively to "util/foo" and will be - adjusted according to the bjams invocation - directory. For - example, if building from project root, the final compiler's + Usage requirements are applied not to the target being declared + but to its + dependents. In this case, <include>. will be applied to all + targets that use foo—i.e. targets that have foo + either in their sources or in their dependency properties. + + You'd need to + specify usage requirements only once, and programs that use foo + don't have to care about include paths any longer. + + Of course, the + path will be interpreted relatively to util/foo and will be + adjusted according to the bjam invocation + directory. + + For + example, if building from project root, the final compiler command line will contain . - The second problem is that we hardcode the path to library's - Jamfile. Imagine it's hardcoded in 20 different places and we - change the directory layout. The solution is to use project ids - — symbolic names, not tied to directory layout. First, we - assign a project id to Jamfile in util/foo: + + The second problem + is that we hardcode the path to library's Jamfile. Imagine it's + hardcoded in 20 different places and we change the directory + layout. The solution is to use project ids —symbolic names + not tied to directory layout. First, we assign a project id to the + project in util/foo: + project foo @@ -379,18 +449,38 @@ project foo exe app : app.cpp /foo//bar ; - The "/foo//bar" syntax is used to refer to target "foo" in - project with global id "/foo" (the slash is used to specify global - id). This way, users of "foo" do not depend on its location, only - on id, which is supposedly stable. The only thing left, it to make - sure that src/Jamfile knows the project id that it uses. We add to - top/Jamfile the following line: + + + The /foo//bar syntax is used to refer to the target bar in + + the project with global id /foo (the slash + is used to specify global id). + + This way, users of foo do not depend on its location, only + on id, which is supposedly stable. The only thing left is to make + sure that src/Jamfile knows the project id that it uses. We add to + top/Jamfile the following line: use-project /foo : util/foo ; - Now, all projects can refer to "foo" using the symbolic + Now, all projects can refer to foo using the symbolic name. If the library is moved somewhere, only a single line in the top-level Jamfile should be changed. @@ -399,10 +489,10 @@ use-project /foo : util/foo ;
Library dependencies - The previous example was simple. Often, there are long chains - of dependencies between libraries. The main application is a thin - wrapper on top of library with core logic, which uses library of - utility functions, which uses boost filesystem library. + The previous example was simple, but there are often long chains + of dependencies between libraries. For example, the main application might be a thin + wrapper on top of library with core logic, which uses another library of + utility functions, which in turn uses the boost filesystem library. Expressing these dependencies is straightforward: @@ -411,33 +501,72 @@ lib core : core.cpp utils ; exe app : app.cpp core ; + + So, what's the reason to even mention this case? First, because it's a bit more complex that it seems. When using shared linking, libraries are build just as written, and everything will work. However, what happens with static linking? It's not possible to include another library in static library. Boost.Build solves this problem by returning back library targets - which appear as sources for static libraries. In this case, if - everything is built statically, the "app" target will link not - only "core" library, but also "utils" and - "/boost/filesystem//fs". + that appear as sources for static libraries. In this case, if + everything is built statically, the app target will link not + only core library, but also utils and + /boost/filesystem//fs. So, the net result is that the above code will work for both static linking and for shared linking. - Sometimes, you want all applications in some project to link - to a certain library. Putting the library in sources of all - targets is possible, but verbose. You can do better by using the - <source> property. For example, if "/boost/filesystem//fs" + + If you want all applications in some project to link + to a certain library, you can avoid having to specify it directly the sources of every + target by using the + <source> property. For example, if /boost/filesystem//fs should be linked to all applications in your project, you can add - <source>/boost/filesystem//fs to requirements of the - project, like this: + <source>/boost/filesystem//fs to the project's requirements, like this: project : requirements <source>/boost/filesystem//fs ; + +
@@ -445,84 +574,122 @@ project While the previous section explained how to create and use libraries, it - omitted one important detail. Libraries can be either + omitted one important detail. + + Libraries can be either static, which means they are included in executable - files which use them, or shared (a.k.a. + files that use them, or shared (a.k.a. dynamic), which are only referred to from executables, and must be available at run time. Boost.Build can work with both - types. By default, all libraries are shared. This is much more + types. + + By default, all libraries are shared. This is much more efficient in build time and space. But the need to install all - libraries to some location is not always convenient, especially - for debug builds. Also, if the installed shared library changes, - all application which use it might start to behave differently. + libraries to some location + + is not always convenient, especially + for debug builds. + + Also, if the installed shared library changes, + all applications that use it might start to behave differently. Static libraries do not suffer from these problems, but - considerably increase the size of application. Before describing - static libraries, it's reasonable to give another, quite simple + can considerably increase the size of an application. Before describing + how to use static libraries, it's reasonable to give another, quite simple approach. If your project is built with - <hardcode-dll-paths>true property, then the application - will include the full paths for all shared libraries, eliminating - the above problems. Unfortunately, you no longer can move shared + <hardcode-dll-paths>true property, the application + will include the full paths to all shared libraries, eliminating + the above problems. + + Unfortunately, once that's done, you can no longer move that shared library to a different location, which makes this option suitable only for debug builds. Further, only gcc compiler supports this - option. + option. + + - Building a library statically is easy. You'd need to change - the value of <link> feature from it's deafault value - shared, to static. So, to build everything as - static libraries, you'd say + Building a library statically is easy; you just change + the value of <link> feature from it's default value + shared to static. So, to build everything as + static libraries, you'd say bjam link=static - - on the command line. The linking mode can be fine-tuned on - per-target basis. + on the command line. - - + + We can also use the <link> property + to express linking requirements on a per-target basis. + + For example, if a particular executable can be correctly built + only with the static version of a library, we can qualify the + executable's target + reference to the library as follows: + + + + +exe important : main.cpp helpers/<link>static ; + + +No matter what arguments are specified on the bjam +command-line, important will only be linked with +the static version of helpers. + + + + - Suppose your library can be only build statically. This is - easily achieved using requirements: + A library that can only be built statically (or + dynamically) can be described by putting the + <link> feature in its + requirements: lib l : l.cpp : <link>static ; - - - What if library can be both static and shared, but when - using it in specific executable, you want it static? - Target - references are here to help: - - -exe important : main.cpp helpers/<link>static ; - - - - - - - - What if the library is defined in some other project, which - you cannot change. But still, you want static linking to that - library in all cases. You can use target references everywhere: + If you need use a library defined in some other project + (one you can't change) but you still want static (or dynamic) linking + to that library in all cases, you + could use target references + everywhere: exe e1 : e1.cpp /other_project//bar/<link>static ; exe e10 : e10.cpp /other_project//bar/<link>static ; - but that's far from being convenient. Another way is to - introduce a level of indirection: create a local target, which will - refer to static version of foo. Here's the - solution: + but that's far from being convenient. A better approach is + to introduce a level of indirection. Create a local + alias target that refers to the static (or + dynamic) version of foo: alias foo : /other_project//bar/<link>static ; @@ -530,53 +697,95 @@ exe e1 : e1.cpp foo ; exe e10 : e10.cpp foo ; - Note that the alias - rule is specifically used for rename a reference to a target and possibly + The alias + rule is specifically used to rename a reference to a target and possibly change the properties. + + - - -
Conditions and alternatives - As we've just figured out, properties can significally affect the - way targets are built. The processing of the <link> feature is - built in the build system, and is quite complex. But there is a couple - of mechanisms which allow ordinary users to do different things + + + As we've just seen, properties can significally affect the + way targets are built. + + The processing of the <link> feature is + built in, and is quite complex, but + + there are a couple + of mechanisms that allow ordinary users to do different things depending on properties. + - The first mechanism is called conditinal - requirement. For example, you might want to set specific - defines when the library is build as shared, or you have your own define - to be used in release mode. Here's a piece of Jamfile. + + + The first mechanism is called a conditional + requirement. For example, you might want to set + specific #defines when a library is built as shared, + or when a target's release variant is built in + release mode. + lib network : network.cpp - : <link>shared:<define>NEWORK_LIB_SHARED - <variant>release:<define>EXTRA_FAST + : <link>shared:<define>NEWORK_LIB_SHARED + <variant>release:<define>EXTRA_FAST ; - This will have exactly the effect we wanted: whenever <link>shared - is in properties, <define>NEWORK_LIB_SHARED will be in properties - as well. + + In the example above, whenever network is + built with <link>shared, + <define>NEWORK_LIB_SHARED will be in its + properties, too. - Sometimes different variant of a target are so different, that - describing them using conditional requirements would be hard. Imagine - that a library has different sources on two supported toolsets, and - dummy implementation for all the other toolset. We can express this - situation using target alternatives: + Sometimes the ways a target is built are so different that + describing them using conditional requirements would be + hard. For example, imagine that a library actually uses + different source files depending on the toolset used to build + it. We can express this situation using target + alternatives: -lib demangler : dummy_demangler.cpp ; -lib demangler : demangler_gcc.cpp : <toolset>gcc ; -lib demangler : demangler_msvc.cpp : <toolset>msvc ; +lib demangler : dummy_demangler.cpp ; # alternative 1 +lib demangler : demangler_gcc.cpp : <toolset>gcc ; # alternative 2 +lib demangler : demangler_msvc.cpp : <toolset>msvc ; # alternative 3 - The proper alternative will be automatically selected. + In the example above, when built with gcc + or msvc, demangler + will use a source file specific to the toolset. Otherwise, it + will use a generic source file, + dummy_demangler.cpp. +
@@ -586,14 +795,26 @@ lib demangler : demangler_msvc.cpp : <toolset>msvc ; Prebuilt targets - We've just learned how to use libraries which are created by - Boost.Build. But some libraries are not. At the same time, those + We've just learned how to use libraries that are created by + Boost.Build. But some libraries are not. + + At the same time, those libraries can have different versions (release and debug, for example), that we should select depending on build properties. Prebuilt targets - provide a mechanism for that. Jamfile in util/lib2 can contain: + provide a mechanism for that. The Jamfile in util/lib2 can contain: + +# util/lib2/Jamfile lib lib2 : : <file>lib2_release.a <variant>release @@ -605,49 +826,67 @@ lib lib2 ; - This defines two alternatives for target "lib2", and for each - one names a prebuilt file. Naturally, there are no sources. - Instead, the <file> feature is used to specify the file name. - Which alternative is selected depends on properties of dependents. - If "app" binary should use "lib2", we can write: + This code + defines two alternatives for lib2, and for each + one names a prebuilt file. Naturally, there are no sources. + Instead, the <file> feature is used to + specify the file name. + + + Once a prebuilt target has been declared, it can be used just like any other target: exe app : app.cpp ../util/lib2//lib2 ; - If we build release version of "app", then it will be linked - with "lib2_release.a", and debug version will use "lib2_debug.a". - Another important kind of prebuilt targets are system libraries - — more specifically, libraries which are automatically found - by the compiler. E.g. gcc uses "-l" switch for that. Such libraries - should be declared almost like regular ones: + As with any library target, the alternative selected depends on the + properties propagated from lib2's dependents. + If we build the the release and debug versions of app will be linked + with lib2_release.a and lib2_debug.a, respectively. - -lib zlib : : <name>z ; - - - We again don't specify any sources, but give a name which - should be passed to the compiler. In this example, and for gcc - compiler, the "-lz" option will be added. Paths where library - should be searched can also be specified: - - -lib zlib : : <name>z <search>/opt/lib ; - - - And, of course, two variants can be used: - - -lib zlib : : <name>z <variant>release ; -lib zlib : : <name>z_d <variant>debug ; - - - Of course, you'll probably never in your life need debug - version of zlib, but for other libraries this is quite reasonable. - More advanced use of prebuilt target is described in a FAQ entry. + + System libraries—those that are automatically found by + the toolset by searching through some set of predetermined + paths—should be declared almost like regular ones: + + +lib pythonlib : : <name>python22 ; + + + We again don't specify any sources, but give a + name that should be passed to the + compiler. If the gcc toolset were used to link an executable + target to pythonlib, + would appear in the command line (other compilers may use + different options). + + + + We can also specify where the toolset should look for the library: + + +lib pythonlib : : <name>python22 <search>/opt/lib ; + + + And, of course, target alternatives can be used in the usual way: + + +lib pythonlib : : <name>python22 <variant>release ; +lib pythonlib : : <name>python22_d <variant>debug ; + + + + + A more advanced use of prebuilt targets is described in . + + + +
@@ -655,7 +894,7 @@ lib zlib : : <name>z_d <variant>debug ;