2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-16 01:12:13 +00:00
Files
build/v2/doc/src/faq.xml
2004-10-27 09:19:10 +00:00

350 lines
13 KiB
XML

<?xml version="1.0" standalone="yes"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<chapter id="bbv2.faq">
<title>Frequently Asked Questions</title>
<section>
<title>
I'm getting "Duplicate name of actual target" error. What
does it mean?
</title>
<para>
The most likely case is that you're trying to
compile the same file twice, with almost the same,
but differing properties. For example:
<programlisting>
exe a : a.cpp : &lt;include&gt;/usr/local/include ;
exe b : a.cpp ;
</programlisting>
</para>
<para>
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.
</para>
<para>
To solve this issue, you need to decide if file should
be compiled once or twice.</para>
<orderedlist>
<listitem>
<para>Two compile file only once, make sure that properties
are the same:
<programlisting>
exe a : a.cpp : &lt;include&gt;/usr/local/include ;
exe b : a.cpp : &lt;include&gt;/usr/local/include ;
</programlisting></para></listitem>
<listitem><para>
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:
<programlisting>
obj a_obj : a.cpp : &lt;include&gt;/usr/local/include ;
exe a : a_obj ;
</programlisting></para></listitem>
<listitem><para>
To compile file twice, you can make the object file local
to the main target:
<programlisting>
exe a : [ obj a_obj : a.cpp ] : &lt;include&gt;/usr/local/include ;
exe b : [ obj a_obj : a.cpp ] ;
</programlisting></para></listitem>
</orderedlist>
<para>
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.
</para>
</section>
<section>
<title>
Accessing environment variables
</title>
<para>
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 <link linkend="bbv2.recipies.site-config">recipes
section</link>. 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.
</para>
<para>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:
<programlisting>
import modules ;
local SOME_LIBRARY_PATH = [ modules.peek : SOME_LIBRARY_PATH ] ;
exe a : a.cpp : &lt;include&gt;$(SOME_LIBRARY_PATH) ;
</programlisting>
</para>
</section>
<section>
<title>
How to control properties order?
</title>
<para>For internal reasons, Boost.Build sorts all the properties
alphabetically. This means that if you write:
<programlisting>
exe a : a.cpp : &lt;include&gt;b &lt;include&gt;a ;
</programlisting>
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:
<programlisting>
exe a : a.cpp : &lt;include&gt;a&amp;&amp;b ;
</programlisting>
</para>
<para>The <code>&amp;&amp;</code> 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.
</para>
</section>
<section>
<title>
How to control the library order on Unix?
</title>
<para>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.
</para>
<para>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
&lt;use&gt; feature. For example, both of the following lines will cause
a to appear before b on the command line:
<programlisting>
lib a : a.cpp b ;
lib a : a.cpp : &lt;use&gt;b ;
</programlisting>
</para>
<para>
The same approach works for searched libraries, too:
<programlisting>
lib z ;
lib png : : &lt;use&gt;z ;
exe viewer : viewer png z ;
</programlisting>
</para>
</section>
<section>
<title>Can I get output of external program as a variable in a Jamfile?
</title>
<para>From time to time users ask how to run an external program and save
the result in Jamfile variable, something like:
<programlisting>
local gtk_includes = [ RUN_COMMAND gtk-config ] ;
</programlisting>
Unfortunately, this is not possible at the moment. However, if the
result of command invocation is to be used in a command to some tool,
and you're working on Unix, the following workaround is possible.
<programlisting>
alias gtk+-2.0 : : : :
&lt;cflags&gt;"`pkg-config --cflags gtk+-2.0`"
&lt;inkflags&gt;"`pkg-config --libs gtk+-2.0`"
;
</programlisting>
If you use the "gtk+-2.0" target in sources, then the properties
specified above will be added to the build properties and eventually
will appear in the command line. Unix command line shell processes
the backticks quoting by running the tool and using its output --
which is what's desired in that case. Thanks to Daniel James for
sharing this approach.
</para>
</section>
<section>
<title>How to get the project-root location?
</title>
<para>You might want to use the location of the project-root in your
Jamfiles. To do it, you'd need to declare path constant in your
project-root.jam:
<programlisting>
path-constant TOP : . ;
</programlisting>
After that, the <code>TOP</code> variable can be used in every Jamfile.
</para>
</section>
<section>
<title>How to change compilation flags for one file?
</title>
<para>If one file must be compiled with special options, you need to
explicitly declare an <code>obj</code> target for that file and then use
that target in your <code>exe</code> or <code>lib</code> target:
<programlisting>
exe a : a.cpp b ;
obj b : b.cpp : &lt;optimization&gt;off ;
</programlisting>
Of course you can use other properties, for example to specify specific
compiler options:
<programlisting>
exe a : a.cpp b ;
obj b : b.cpp : &lt;cflags&gt;-g ;
</programlisting>
You can also use <link linkend="bbv2.tutorial.conditions">conditional
properties</link> for finer control:
<programlisting>
exe a : a.cpp b ;
obj b : b.cpp : &lt;variant&gt;release:&lt;optimization&gt;off ;
</programlisting>
</para>
</section>
<section id="bbv2.faq.dll-path">
<title>Why are the <code>dll-path</code> and
<code>hardcode-dll-paths</code> properties useful?
</title>
<para>(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 phisycally 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.
</para>
<para>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
<envar>LD_LIBRARY_PATH</envar> 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.
</para>
<para>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 <code>hardcode-dll-paths</code>
feature has the <literal>true</literal> value, which is the
default. When the executables should be installed, the story is
different.
</para>
<para>
Obviously, installed executable should not hardcode paths to your
development tree. (The <code>stage</code> rule explicitly disables the
<code>hardcode-dll-paths</code> feature for that reason.) However, you
can use the <code>dll-path</code> feature to add explicit paths
manually. For example:
<programlisting>
stage installed : application : &lt;dll-path&gt;/usr/lib/snake
&lt;location&gt;/usr/bin ;
</programlisting>
will allow the application to find libraries placed to
<filename>/usr/lib/snake</filename>.
</para>
<para>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.
</para>
<para>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 our 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
always be used.
</para>
</section>
<section id="bbv2.recipies.site-config">
<title>Targets in site-config.jam</title>
<para>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 put the following to site-config.jam.</para>
<programlisting>
import project ;
project.initialize $(__name__) ;
project site-config ;
lib zlib : : &lt;name&gt;z ;
</programlisting>
<para>The second line allows this module to act as project. The
third line gives id to this project &#x2014; it really has no location
and cannot be used otherwise. The fourth line just declares a
target. Now, one can write:
<programlisting>
exe hello : hello.cpp /site-config//zlib ;
</programlisting>
in any Jamfile.</para>
</section>
</chapter>
<!--
Local Variables:
mode: xml
sgml-indent-data: t
sgml-parent-document: ("userman.xml" "chapter")
sgml-set-face: t
End:
-->