diff --git a/v2/doc/src/tutorial.xml b/v2/doc/src/tutorial.xml index 175e1f27e..8eee49a50 100644 --- a/v2/doc/src/tutorial.xml +++ b/v2/doc/src/tutorial.xml @@ -11,6 +11,10 @@ +
Hello, world @@ -26,9 +30,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 hello executable by compiling and - linking hello.cpp. Now, to build the + linking hello.cpp. By default, debug variant + is built. Now, to build the release variant of hello, invoke @@ -45,12 +50,8 @@ bjam release exe hello2 : hello.cpp ; - Now we can build both the debug and release variants of our - project: - - - - + Now let us build both the debug and release variants of our project + again: bjam debug release @@ -71,9 +72,6 @@ bjam --clean debug release following two commands, respectively, build or clean only the debug version of hello2. - - bjam hello2 bjam --clean hello2 @@ -131,8 +129,6 @@ bjam variant=release inlining=off debug-symbols=on A complete description of features can be found in . - - @@ -140,12 +136,12 @@ bjam variant=release inlining=off debug-symbols=on Build Requests and Target Requirements - The set of properties specified in the command line constitute + The set of properties specified on the command line constitute a 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 used for building targets is typically a + properties used for building targets are typically a combination of the build request and properties derived from the project's Jamroot (and its other Jamfiles, as described in exe hello : hello.cpp - : <include>/home/ghost/Work/boost <threading>multi + : <include>boost <threading>multi ; - - When hello is built, the two - requirements specified above will normally always be present. + requirements specified above will 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”” features like <include>, + the target requirements usually override (or, in the case of + “free”” features like + <include>, See - augments) the target requirements. - - - - - - - + + augments) the build request. + + The value of the <include> feature is + relative to the location of Jamroot where it's + used. + + +
Project Attributes @@ -243,15 +230,12 @@ exe hello2 : hello.cpp ; Jamroot file in an ancestor directory. For example, in the following directory layout: - - - top/ | +-- Jamroot | - +-- src/ + +-- app/ | | | +-- Jamfile | `-- app.cpp @@ -264,12 +248,10 @@ top/ . `-- bar.cpp - - the project root is top/. Because there is no Jamfile in top/util/, the projects in - top/src/ and + top/app/ and top/util/foo/ are immediate children of the root project. @@ -318,28 +300,19 @@ top/ top/Jamroot might contain: -build-project src ; +build-project app ; - which would cause the project in top/src/ + which would cause the project in top/app/ to be built whenever the project in top/ is built. However, targets in top/util/foo/ will be built only if they are needed by targets in - top/ or top/src/. + top/ or top/app/.
- Libraries and Dependent Targets - - TODO: need to make this - section consistent with "examples-v2/libraries". - - + Dependent Targets Targets that are “needed” by other targets are called @@ -349,15 +322,16 @@ build-project src ; To get a feeling of target dependencies, let's continue the - above example and see how src/Jamfile can - use libraries from util/foo. If - util/foo/Jamfile contains + above example and see how top/app/Jamfile can + use libraries from top/util/foo. If + top/util/foo/Jamfile contains lib bar : bar.cpp ; - then to use this library in src/Jamfile, we can write: + then to use this library in top/app/Jamfile, we can + write: exe app : app.cpp ../util/foo//bar ; @@ -366,41 +340,43 @@ 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 - ../util/foo. When linking the - 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: + ../util/foo. + - -bjam app optimization=full cxxflags=-w-8080 - + + Some other build system have special syntax for listing dependent + libraries, for example LIBS variable. In Boost.Build, + you just add the library to the list of sources. + + - + Suppose we build app with: + +bjam app optimization=full define=USE_ASM + + Which properties will be used to build foo? The answer is + that some features are + 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 <define> is not + propagated: its value will be added as-is to the compiler flags for + a.cpp, but won't affect foo. + - Which properties must be used to build foo? The - answer is that some properties are - 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> 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 + + Let's improve this project further. + 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 + <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 : usage-requirements <include>. @@ -412,362 +388,186 @@ lib foo : foo.cpp ; 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 . + targets that directly depend on 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: - + Another improvement is using symbolic identifiers to refer to + the library, as opposed to Jamfile location. + In a large project, a library can be used by many targets, and if + they all use Jamfile location, + a change in directory organization entails much work. + The solution is to use project ids—symbolic names + not tied to directory layout. First, we need to assign a project id by + adding this code to + Jamroot: + +use-project /library-example/foo : util/foo ; + + Second, we modify app/Jamfile to use the + project id: -project foo - : usage-requirements <include>. - ; +exe app : app.cpp /library-example/foo//bar ; - - - Second, we use the project id to refer to the library in - src/Jamfile: - - -exe app : app.cpp /foo//bar ; - - - - - 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 the following line to - top/Jamroot: - - -use-project /foo : util/foo ; - - - 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. +The /library-example/foo//bar syntax is used + to refer to the target bar in + the project with id /library-example/foo. + We've achieved our goal—if the library is moved to a different + directory, only Jamroot must be modified. + Note that project ids are global—two Jamfiles are not + allowed to assign the same project id to different directories. + -
-
- Library dependencies - - 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: - - -lib utils : utils.cpp /boost/filesystem//fs ; -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 - 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. - - - If you want all applications in some project to link + + 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 the project's requirements, like this: - + project : requirements <source>/boost/filesystem//fs ; - - - -
+ + + +
Static and shared libaries - While the - previous section explained how to create and use libraries, it - omitted one important detail. - - Libraries can be either - static, which means they are included in executable - 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 - 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 applications that use it might start to behave differently. + Libraries can be either + static, which means they are included in executable + 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 create and use both kinds. - - Static libraries do not suffer from these problems, but - 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, 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. - - - - 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 - - + + The kind of library produced from a lib target is + determined by the value of the link feature. Default + value is shared, and to build static library, the value + should be static. You can either requiest static build + on the command line: + bjam link=static - + + or in the library's requirements: + +lib l : l.cpp : <link>static ; + + - 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: + + 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: + as I was. + VP: to be addressed when this section is moved. See comment + below. +--> - -exe important : main.cpp helpers/<link>static ; - + +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. - + No matter what arguments are specified on the bjam + command-line, important will only be linked with + the static version of helpers. + + + Specifying properties in target references is especially useful if you + 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. If that library is used by many targets, + you could use target references + everywhere: - - - 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 ; - - - - - - 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 ; - +exe e10 : e10.cpp /other_project//bar/<link>static ; - 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: + 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 ; exe e1 : e1.cpp foo ; -exe e10 : e10.cpp foo ; - +exe e10 : e10.cpp foo ; - The alias - rule is specifically used to rename a reference to a target and possibly - change the properties. - - + The alias + rule is specifically used to rename a reference to a target and possibly + change the properties. + + + + + + + When one library uses another, you put the second library is + the source list of the first. For example: + +lib utils : utils.cpp /boost/filesystem//fs ; +lib core : core.cpp utils ; +exe app : app.cpp core ; + This works no matter what kind of linking is used. When + core is built as a shared library, it is linked + directly into utils. Static libraries can't + link to other libraries, so when core is built + as a static library, its dependency on utils is passed along to + core's dependents, causing + app to be linked with both + core and utils." + + + + + (Note for non-UNIX system). Typically, shared libraries must be + installed to a directory in the dynamic linker's search + path. Otherwise, applications that use shared libraries can't be + started. On Windows, the dynamic linker's search path is given by the + PATH environment variable. This restriction is lifted + when you use Boost.Build testing facilities—the + PATH variable will be automatically adjusted before + running executable. + + + -
Conditions and alternatives - - - 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 a conditional + Sometimes, particular relationships need to be maintained + among a target's build properties. This can be achieved with + 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 @@ -788,7 +588,7 @@ lib network : network.cpp it. We can express this situation using target alternatives: -lib demangler : dummy_demangler.cpp ; # alternative 1 +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 @@ -797,36 +597,19 @@ lib demangler : demangler_msvc.cpp : <toolset>msvc ; # alternative 3 will use a source file specific to the toolset. Otherwise, it will use a generic source file, dummy_demangler.cpp. -
-
Prebuilt targets - 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. The Jamfile in util/lib2 can contain: - - + To link to libraries whose build instructions aren't given in a Jamfile, + you need to create lib targets with an appropriate + file property. Target alternatives can be used to + associate multiple library files with a single conceptual target. For + example: # util/lib2/Jamfile lib lib2 @@ -840,12 +623,10 @@ lib lib2 ; - 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. + This example 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: @@ -854,7 +635,7 @@ lib lib2 exe app : app.cpp ../util/lib2//lib2 ; - As with any library target, the alternative selected depends on the + As with any 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. @@ -895,12 +676,8 @@ lib pythonlib : : <name>python22_d <variant>debug ; A more advanced use of prebuilt targets is described in . - - - - + linkend="bbv2.recipies.site-config"/>. +