From ba6fef8dfeefb97f3ab0588d7fbd2a21611d0bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jurko=20Gospodneti=C4=87?= Date: Sun, 24 Aug 2008 20:19:31 +0000 Subject: [PATCH] Refactored the Boost Build faq.xml documentation a bit. Minor wording changes. [SVN r48354] --- v2/doc/src/faq.xml | 548 +++++++++++++++++++++++++-------------------- 1 file changed, 303 insertions(+), 245 deletions(-) diff --git a/v2/doc/src/faq.xml b/v2/doc/src/faq.xml index 4172479c1..65435001b 100644 --- a/v2/doc/src/faq.xml +++ b/v2/doc/src/faq.xml @@ -2,191 +2,232 @@ - - Frequently Asked Questions + + Frequently Asked Questions -
- - How do I get the current value of feature in Jamfile? - +
+ + How do I get the current value of feature in Jamfile? + - - This is not possible, since Jamfile does not have "current" value of any - feature, be it toolset, build variant or anything else. For a single invocation of - bjam, any given main target can be built with several property sets. - For example, user can request two build variants on the command line. Or one library - is built as shared when used from one application, and as static when used from another. - Obviously, Jamfile is read only once, so generally, there's no single value of a feature - you can access in Jamfile. - + + This is not possible, since Jamfile does not have "current" value of any + feature, be it toolset, build variant or anything else. For a single + invocation of bjam, any given main target can be + built with several property sets. For example, user can request two build + variants on the command line. Or one library is built as shared when used + from one application, and as static when used from another. Each Jamfile + is read only once so generally there is no single value of a feature you + can access in Jamfile. + - A feature has a specific value only when building a target, and there are two ways how you - can use that value: - - Use conditional requirements or indirect conditional requirements. See - . - - Define a custom generator and a custom main target type. The custom generator can do arbitrary processing - or properties. See the extender manual. - - + + A feature has a specific value only when building a target, and there are + two ways you can use that value: + -
+ + + + Use conditional requirements or indirect conditional requirements. See + . + + + + Define a custom generator and a custom main target type. The custom + generator can do arbitrary processing or properties. See the extender manual. + + +
-
- - I'm getting "Duplicate name of actual target" error. What - does it mean? - - - - The most likely case is that you're trying to - compile the same file twice, with almost the same, - but differing properties. For example: +
+ + I am getting a "Duplicate name of actual target" error. What does that + mean? + + + The most likely case is that you are trying to compile the same file + twice, with almost the same, but differing properties. For example: exe a : a.cpp : <include>/usr/local/include ; exe b : a.cpp ; - - + - The above snippet requires two different compilations - of 'a.cpp', which differ only in 'include' property. - Since the 'include' property is free, Boost.Build - can't generate two objects files into different directories. - On the other hand, it's dangerous to compile the file only - once -- maybe you really want to compile with different - includes. + The above snippet requires two different compilations of + a.cpp, which differ only in their include + property. Since the include feature is declared as + free Boost.Build does not create a separate build + directory for each of its values and those two builds would both produce + object files generated in the same build directory. Ignoring this and + compiling the file only once would be dangerous as different includes + could potentially cause completely different code to be compiled. - To solve this issue, you need to decide if file should - be compiled once or twice. + To solve this issue, you need to decide if the file should be compiled + once or twice. + - - Two compile file only once, make sure that properties - are the same: - + + + To compile the file only once, make sure that properties are the same + for both target requests: exe a : a.cpp : <include>/usr/local/include ; exe b : a.cpp : <include>/usr/local/include ; - - - - If changing the properties is not desirable, for example - if 'a' and 'b' target have other sources which need - specific properties, separate 'a.cpp' into it's own target: - + + or: -obj a_obj : a.cpp : <include>/usr/local/include ; -exe a : a_obj ; - - - - To compile file twice, you can make the object file local - to the main target: - +alias a-with-include : a.cpp : <include>/usr/local/include ; +exe a : a-with-include ; +exe b : a-with-include ; + + or if you want the includes property not to affect + how any other sources added for the built a & + b executables would be compiled: - exe a : [ obj a_obj : a.cpp ] : <include>/usr/local/include ; +obj a-obj : a.cpp : <include>/usr/local/include ; +exe a : a-obj ; +exe b : a-obj ; + + + + Note that in both of these cases the include + property will be applied only for building these object files and not + any other sources that might be added for targets a & + b. + + + + + + To compile the file twice, you can tell Boost.Build to compile it to + two separate object files like so: + + obj a_obj : a.cpp : <include>/usr/local/include ; + obj b_obj : a.cpp ; + exe a : a_obj ; + exe b : b_obj ; + + or you can make the object file targets local to the main target: + + exe a : [ obj a_obj : a.cpp : <include>/usr/local/include ] ; exe b : [ obj a_obj : a.cpp ] ; - + + which will cause Boost.Build to actually change the generated object + file names a bit for you and thus avoid any conflicts. + + + Note that in both of these cases the include + property will be applied only for building these object files and not + any other sources that might be added for targets a & + b. + + + - + + A good question is why Boost.Build can not use some of the above + approaches automatically. The problem is that such magic would only help + in half of the cases, while in the other half it would be silently doing + the wrong thing. It is simpler and safer to ask the user to clarify his + intention in such cases. + +
- - A good question is why Boost.Build can't use some of the above - approaches automatically. The problem is that such magic would - require additional implementation complexities and would only - help in half of the cases, while in other half we'd be silently - doing the wrong thing. It's simpler and safe to ask user to - clarify his intention in such cases. - - -
- -
- + <section id="bbv2.faq.envar"> + <title> Accessing environment variables - + - + Many users would like to use environment variables in Jamfiles, for - example, to control location of external libraries. In many cases you - better declare those external libraries in the site-config.jam file, as - documented in the recipes - section. However, if the users already have the environment variables set - up, it's not convenient to ask them to set up site-config.jam files as - well, and using environment variables might be reasonable. + example, to control the location of external libraries. In many cases it + is better to declare those external libraries in the site-config.jam file, + as documented in the recipes + section. However, if the users already have the environment + variables set up, it may not be convenient for them to set up their + site-config.jam files as well and using the environment variables might be + reasonable. - In Boost.Build V2, each Jamfile is a separate namespace, and the - variables defined in environment is imported into the global - namespace. Therefore, to access environment variable from Jamfile, you'd - need the following code: + + Boost.Jam automatically imports all environment variables into its + built-in .ENVIRON module so user can read them from there directly or by + using the helper os.environ rule. For example: + +import os ; +local unga-unga = [ os.environ UNGA_UNGA ] ; +ECHO $(unga-unga) ; + + or a bit more realistic: import os ; local SOME_LIBRARY_PATH = [ os.environ SOME_LIBRARY_PATH ] ; exe a : a.cpp : <include>$(SOME_LIBRARY_PATH) ; -
- -
- - How to control properties order? - - - For internal reasons, Boost.Build sorts all the properties - alphabetically. This means that if you write: - -exe a : a.cpp : <include>b <include>a ; - - then the command line with first mention the "a" include directory, and - then "b", even though they are specified in the opposite order. In most - cases, the user doesn't care. But sometimes the order of includes, or - other properties, is important. For example, if one uses both the C++ - Boost library and the "boost-sandbox" (libraries in development), then - include path for boost-sandbox must come first, because some headers may - override ones in C++ Boost. For such cases, a special syntax is - provided: - -exe a : a.cpp : <include>a&&b ; - - - - The && symbols separate values of an - property, and specify that the order of the values should be preserved. You - are advised to use this feature only when the order of properties really - matters, and not as a convenient shortcut. Using it everywhere might - negatively affect performance. - -
- How to control the library order on Unix? + How to control properties order? - On the Unix-like operating systems, the order in which static - libraries are specified when invoking the linker is important, because by - default, the linker uses one pass though the libraries list. Passing the - libraries in the incorrect order will lead to a link error. Further, this - behaviour is often used to make one library override symbols from - another. So, sometimes it's necessary to force specific order of - libraries. + + For internal reasons, Boost.Build sorts all the properties alphabetically. + This means that if you write: + +exe a : a.cpp : <include>b <include>a ; + + then the command line with first mention the a include + directory, and then b, even though they are specified in the + opposite order. In most cases, the user does not care. But sometimes the + order of includes, or other properties, is important. For such cases, a + special syntax is provided: + +exe a : a.cpp : <include>a&&b ; + - Boost.Build tries to automatically compute the right order. The - primary rule is that if library a "uses" library b, then library a will - appear on the command line before library b. Library a is considered to - use b is b is present either in the sources of a or in its - requirements. To explicitly specify the use relationship one can use the - <use> feature. For example, both of the following lines will cause - a to appear before b on the command line: + + The && symbols separate property values and specify + that their order should be preserved. You are advised to use this feature + only when the order of properties really matters and not as a convenient + shortcut. Using it everywhere might negatively affect performance. + +
+ +
+ + How to control the library linking order on Unix? + + + + On Unix-like operating systems, the order in which static libraries are + specified when invoking the linker is important, because by default, the + linker uses one pass though the libraries list. Passing the libraries in + the incorrect order will lead to a link error. Further, this behaviour is + often used to make one library override symbols from another. So, + sometimes it is necessary to force specific library linking order. + + + + Boost.Build tries to automatically compute the right order. The primary + rule is that if library a "uses" library b, then + library a will appear on the command line before library + b. Library a is considered to use b + if b is present either in the a library's + sources or its usage is listed in its requirements. To explicitly specify + the use relationship one can use the + <use> feature. For example, both of the following + lines will cause a to appear before b on the + command line: lib a : a.cpp b ; lib a : a.cpp : <use>b ; @@ -201,14 +242,15 @@ lib png : : <use>z ; exe viewer : viewer png z ; -
- Can I get output of external program as a variable in a Jamfile? + <title> + Can I get capture external program output in a Boost.Jam variable? - The SHELL builtin can be used for the purpose: + + The SHELL builtin rule may be used for this purpose: local gtk_includes = [ SHELL "gtk-config --cflags" ] ; @@ -216,7 +258,8 @@ local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
- How to get the project root (a.k.a. Jamroot.jam) location? + <title> + How to get the project root (a.k.a. Jamroot) location? @@ -230,18 +273,20 @@ path-constant TOP : . ;
- How to change compilation flags for one file? + <title> + How to change compilation flags for one file? - If one file must be compiled with special options, you need to - explicitly declare an obj target for that file and then use - that target in your exe or lib target: + + If one file must be compiled with special options, you need to explicitly + declare an obj target for that file and then use that target + in your exe or lib target: exe a : a.cpp b ; obj b : b.cpp : <optimization>off ; Of course you can use other properties, for example to specify specific - compiler options: + C/C++ compiler options: exe a : a.cpp b ; obj b : b.cpp : <cflags>-g ; @@ -252,149 +297,162 @@ obj b : b.cpp : <cflags>-g ; exe a : a.cpp b ; obj b : b.cpp : <variant>release:<optimization>off ; -
- Why are the <code>dll-path</code> and - <code>hardcode-dll-paths</code> properties useful? + <title> + Why are the <literal>dll-path</literal> and <literal>hardcode-dll-paths + </literal> properties useful? - - (This entry is specific to Unix system.)Before answering the - questions, let's recall a few points about shared libraries. Shared - libraries can be used by several applications, or other libraries, - without physically including the library in the application. This can - greatly decrease the total size of applications. It's also possible to - upgrade a shared library when the application is already - installed. Finally, shared linking can be faster. - - - However, the shared library must be found when the application is - started. The dynamic linker will search in a system-defined list of - paths, load the library and resolve the symbols. Which means that you - should either change the system-defined list, given by the - LD_LIBRARY_PATH environment variable, or install the - libraries to a system location. This can be inconvenient when - developing, since the libraries are not yet ready to be installed, and - cluttering system paths is undesirable. Luckily, on Unix there's another - way. - - - An executable can include a list of additional library paths, which - will be searched before system paths. This is excellent for development, - because the build system knows the paths to all libraries and can include - them in executables. That's done when the hardcode-dll-paths - feature has the true value, which is the - default. When the executables should be installed, the story is - different. + + + This entry is specific to Unix systems. + + + + Before answering the questions, let us recall a few points about shared + libraries. Shared libraries can be used by several applications, or other + libraries, without physically including the library in the application + which can greatly decrease the total application size. It is also possible + to upgrade a shared library when the application is already installed. - Obviously, installed executable should not hardcode paths to your - development tree. (The stage rule explicitly disables the - hardcode-dll-paths feature for that reason.) However, you - can use the dll-path feature to add explicit paths + However, in order for application depending on shared libraries to be + started the OS may need to find the shared library when the application is + started. The dynamic linker will search in a system-defined list of paths, + load the library and resolve the symbols. Which means that you should + either change the system-defined list, given by the LD_LIBRARY_PATH + environment variable, or install the libraries to a system + location. This can be inconvenient when developing, since the libraries + are not yet ready to be installed, and cluttering system paths may be + undesirable. Luckily, on Unix there is another way. + + + + An executable can include a list of additional library paths, which will + be searched before system paths. This is excellent for development because + the build system knows the paths to all libraries and can include them in + the executables. That is done when the hardcode-dll-paths + feature has the true value, which is the + default. When the executables should be installed, the story is different. + + + + Obviously, installed executable should not contain hardcoded paths to your + development tree. (The install rule explicitly disables the + hardcode-dll-paths feature for that reason.) However, + you can use the dll-path feature to add explicit paths manually. For example: -stage installed : application : <dll-path>/usr/lib/snake - <location>/usr/bin ; +install installed : application : <dll-path>/usr/lib/snake + <location>/usr/bin ; - will allow the application to find libraries placed to - /usr/lib/snake. + will allow the application to find libraries placed in the + /usr/lib/snake directory. - If you install libraries to a nonstandard location and add an - explicit path, you get more control over libraries which will be used. A - library of the same name in a system location will not be inadvertently - used. If you install libraries to a system location and do not add any - paths, the system administrator will have more control. Each library can - be individually upgraded, and all applications will use the new library. + + If you install libraries to a nonstandard location and add an explicit + path, you get more control over libraries which will be used. A library of + the same name in a system location will not be inadvertently used. If you + install libraries to a system location and do not add any paths, the + system administrator will have more control. Each library can be + individually upgraded, and all applications will use the new library. - Which approach is best depends on your situation. If the libraries - are relatively standalone and can be used by third party applications, - they should be installed in the system location. If you have lots of - libraries which can be used only by your application, it makes sense to - install it to a nonstandard directory and add an explicit path, like the - example above shows. Please also note that guidelines for different - systems differ in this respect. The Debian guidelines prohibit any - additional search paths, and Solaris guidelines suggest that they should + + Which approach is best depends on your situation. If the libraries are + relatively standalone and can be used by third party applications, they + should be installed in the system location. If you have lots of libraries + which can be used only by your application, it makes sense to install them + to a nonstandard directory and add an explicit path, like the example + above shows. Please also note that guidelines for different systems differ + in this respect. For example, the Debian GNU guidelines prohibit any + additional search paths while Solaris guidelines suggest that they should always be used. -
Targets in site-config.jam - It is desirable to declare standard libraries available on a - given system. Putting target declaration in Jamfile is not really - good, since locations of the libraries can vary. The solution is - to declare the targets in site-config.jam: + + It is desirable to declare standard libraries available on a given system. + Putting target declaration in a specific project's Jamfile is not really + good, since locations of the libraries can vary between different + development machines and then such declarations would need to be + duplicated in different projects. The solution is to declare the targets + in Boost.Build's site-config.jam configuration file: project site-config ; lib zlib : : <name>z ; + - Recall that both site-config.jam and - user-config.jam are projects, and everything - you can do in a Jamfile you can do in those files. So, you declare - a project id and a target. Now, one can write: + + Recall that both site-config.jam and + user-config.jam are projects, and everything you can + do in a Jamfile you can do in those files as well. So, you declare a + project id and a target. Now, one can write: exe hello : hello.cpp /site-config//zlib ; - in any Jamfile. - + in any Jamfile. +
Header-only libraries - In modern C++, libraries often consist of just header files, without - any source files to compile. To use such libraries, you need to add proper - includes and, maybe, defines, to your project. But with large number of - external libraries it becomes problematic to remember which libraries are - header only, and which are "real" ones. However, with Boost.Build a - header-only library can be declared as Boost.Build target and all - dependents can use such library without remebering if it's header-only or not. - - - Header-only libraries are declared using the alias rule, - that specifies only usage requirements, for example: - -alias mylib - : # no sources - : # no build requirements - : # no default build - : <include>whatever - ; - - The includes specified in usage requirements of mylib are - automatically added to build properties of all dependents. The dependents - need not care if mylib is header-only or not, and it's possible - to later make mylib into a regular compiled library. + + In modern C++, libraries often consist of just header files, without any + source files to compile. To use such libraries, you need to add proper + includes and possibly defines to your project. But with a large number of + external libraries it becomes problematic to remember which libraries are + header only, and which ones you have to link to. However, with Boost.Build + a header-only library can be declared as Boost.Build target and all + dependents can use such library without having to remeber whether it is a + header-only library or not. - If you already have proper usage requirements declared for project where - header-only library is defined, you don't need to duplicate them for + Header-only libraries may be declared using the alias rule, + specifying their include path as a part of its usage requirements, for + example: + +alias my-lib + : # no sources + : # no build requirements + : # no default build + : <include>whatever ; + + The includes specified in usage requirements of my-lib are + automatically added to all of its dependants' build properties. The + dependants need not care if my-lib is a header-only or not, + and it is possible to later make my-lib into a regular + compiled library without having to that its dependants' declarations. + + + + If you already have proper usage requirements declared for a project where + a header-only library is defined, you do not need to duplicate them for the alias target: project my : usage-requirements <include>whatever ; alias mylib ; - + -
+
- -
\ No newline at end of file +-->