mirror of
https://github.com/boostorg/build.git
synced 2026-02-02 08:42:13 +00:00
671 lines
24 KiB
XML
671 lines
24 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
|
|
|
|
<?psgml nofill screen programlisting literallayout?>
|
|
|
|
<chapter id="bbv2.tutorial" status="draft">
|
|
<title>Tutorial</title>
|
|
|
|
<section id="bbv2.tutorial.hello">
|
|
<title>Hello, world</title>
|
|
|
|
<para>The simplest project that Boost.Build can construct is
|
|
stored in <filename>example/hello/</filename> directory. The
|
|
project is described by a file
|
|
called <filename>Jamfile</filename> that contains:
|
|
|
|
<programlisting>
|
|
exe hello : hello.cpp ;
|
|
</programlisting>
|
|
|
|
Even with this simple setup, you can do some interesting
|
|
things. First of all, just invoking <command>bjam</command> will
|
|
build the debug variant of the <command>hello</command>
|
|
executable by compiling and
|
|
linking <filename>hello.cpp</filename>. Now, to build the
|
|
release variant of <command>hello</command>, invoke
|
|
|
|
<screen>
|
|
bjam release
|
|
</screen>
|
|
|
|
Note that debug and release variants are created in different
|
|
directories, so you can switch between variants or even build
|
|
multiple variants at once, without any unneccessary
|
|
recompilation. Let's extend the example by adding another line
|
|
to our project's <filename>Jamfile</filename>:
|
|
|
|
<programlisting>
|
|
exe hello2 : hello.cpp ;
|
|
</programlisting>
|
|
|
|
Now we can build both the debug and release variants of our
|
|
project:
|
|
|
|
<screen>
|
|
bjam debug release
|
|
</screen>
|
|
|
|
Note that two variants of <command>hello2</command> are linked.
|
|
Since we have already built both variants
|
|
of <command>hello</command>, hello.cpp won't be recompiled;
|
|
instead the existing object files will just be linked into the
|
|
corresponding variants of <command>hello2</command>. Now
|
|
let's remove all the built products:
|
|
|
|
<screen>
|
|
bjam --clean debug release
|
|
</screen>
|
|
|
|
It's also possible to build or clean specific targets. The
|
|
following two commands, respectively, build or clean only the
|
|
debug version of <command>hello2</command>.
|
|
|
|
<screen>
|
|
bjam hello2
|
|
bjam --clean hello2
|
|
</screen>
|
|
</para>
|
|
|
|
</section>
|
|
<section id="bbv2.tutorial.properties">
|
|
<title>Properties</title>
|
|
|
|
<para>
|
|
To portably represent aspects of target configuration such as
|
|
debug and release variants, or single- and multi-threaded
|
|
builds, Boost.Build uses <firstterm>features</firstterm> with
|
|
associated <firstterm>values</firstterm>. For
|
|
example, the "debug-symbols" feature can have a value of "on" or
|
|
"off". A <firstterm>property</firstterm> 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
|
|
and linkers.</para>
|
|
|
|
<para>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
|
|
disabled and debug symbols enabled:
|
|
|
|
<screen>
|
|
bjam release inlining=off debug-symbols=on
|
|
</screen>
|
|
</para>
|
|
|
|
<para>Properties on the command-line are specified with the syntax:
|
|
|
|
<screen>
|
|
<replaceable>feature-name</replaceable>=<replaceable>feature-value</replaceable>
|
|
</screen>
|
|
</para>
|
|
|
|
<para>The "release" and "debug" that we've seen
|
|
in <command>bjam</command> invocations are just a shorthand way to
|
|
specify values of the "variant" feature. For example, the command
|
|
above could also have been written this way:
|
|
|
|
<screen>
|
|
bjam variant=release inlining=off debug-symbols=on
|
|
</screen>
|
|
</para>
|
|
|
|
<para> "variant" is so commonly-used that it has been given
|
|
special status as an <firstterm>implicit</firstterm> feature
|
|
— Boost.Build will deduce the its identity just from the name
|
|
of one of its values.
|
|
</para>
|
|
|
|
<para>
|
|
A complete description of features can be found
|
|
<link linkend="bbv2.reference.features">here</link>.
|
|
</para>
|
|
|
|
|
|
<section id="bbv2.tutorial.properties.requirements">
|
|
<title>Build Requests and Target Requirements</title>
|
|
|
|
<para>
|
|
The set of properties specified in the command line constitute a
|
|
<firstterm>build request</firstterm> — 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 <emphasis>actual</emphasis> properties
|
|
used for building targets is typically a combination of the
|
|
build request and properties derived from the
|
|
project's <filename>Jamfile</filename>s. For example, the
|
|
locations of <code>#include</code>d header files are normally
|
|
not specified on the command-line, but described
|
|
in <filename>Jamfile</filename>s as <firstterm>target
|
|
requirements</firstterm> and automatically combined with the
|
|
build request for those targets. Multithread-enabled
|
|
compilation is another example of a typical target requirement.
|
|
The <filename>Jamfile</filename> fragment below illustrates how
|
|
these requirements might be specified.
|
|
</para>
|
|
|
|
<programlisting>
|
|
exe hello
|
|
: hello.cpp
|
|
: <include>/home/ghost/Work/boost <threading>multi
|
|
;
|
|
</programlisting>
|
|
|
|
<para>
|
|
When <filename>hello</filename> is built, the two
|
|
requirements specified above will normally always be present.
|
|
If the build request given on the <command>bjam</command>
|
|
command-line explictly contradicts a target's requirements,
|
|
the command-line usually overrides (or, in the case of
|
|
"free" feautures like <code><include></code>
|
|
<footnote>See <xref
|
|
linkend="bbv2.reference.features.attributes"/></footnote>,
|
|
augments) the target requirements. However, when a
|
|
contradiction of a target's requrements involves certain
|
|
<firstterm>link-incompatible</firstterm> features, the target
|
|
will be skipped. See <xref linkend=
|
|
"bbv2.reference.variants.compat"/> for more information.
|
|
</para>
|
|
|
|
</section>
|
|
<section id="bbv2.tutorial.properties.project_attributes">
|
|
<title>Project Attributes</title>
|
|
|
|
<para>
|
|
If we want the same requirements for our other
|
|
target, <filename>hello2</filename>, we could simply duplicate
|
|
them. However, as projects grow, that approach leads to a great
|
|
deal of repeated boilerplate in Jamfiles.
|
|
|
|
Fortunately, there's a better way. Each project (i.e. each
|
|
<filename>Jamfile</filename>), can specify a set of <firstterm>attributes</firstterm>,
|
|
including requirements:
|
|
|
|
<programlisting>
|
|
project
|
|
: requirements <include>/home/ghost/Work/boost <threading>multi
|
|
;
|
|
|
|
exe hello : hello.cpp ;
|
|
exe hello2 : hello.cpp ;
|
|
</programlisting>
|
|
|
|
The effect would be as if we specified the same requirement for
|
|
both <command>hello</command> and <command>hello2</command>.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="bbv2.tutorial.hierarchy">
|
|
<title>Project Hierarchies</title>
|
|
|
|
<para>So far we've only considered examples with one project
|
|
(i.e. with one <filename>Jamfile</filename>). A typical large
|
|
software project would be composed of sub-projects organized
|
|
into a tree. The top of the tree is called the
|
|
<firstterm>project root</firstterm>. Besides a
|
|
<filename>Jamfile</filename>, the project root directory
|
|
contains a file called <filename>project-root.jam</filename>. Every other
|
|
<filename>Jamfile</filename> in the project has a single parent
|
|
project, rooted in the nearest parent directory containing a
|
|
<filename>Jamfile</filename>. For example, in the following
|
|
directory layout:
|
|
|
|
<screen>
|
|
top/
|
|
|
|
|
+-- Jamfile
|
|
+-- project-root.jam
|
|
|
|
|
+-- src/
|
|
| |
|
|
| +-- Jamfile
|
|
| `-- app.cpp
|
|
|
|
|
`-- util/
|
|
|
|
|
+-- foo/
|
|
. |
|
|
. +-- Jamfile
|
|
. `-- bar.cpp
|
|
</screen>
|
|
|
|
<!-- "lib/lib1/lib1" changed to "util/foo/bar" to avoid confusion -->
|
|
|
|
the project root is <filename>top/</filename>. Because there is
|
|
no <filename>Jamfile</filename> in
|
|
<filename>top/util/</filename>, the projects in
|
|
<filename>top/src/</filename> and
|
|
<filename>top/util/foo/</filename> are immediate children of the
|
|
root project.
|
|
</para>
|
|
|
|
<para>
|
|
Projects inherit all attributes (such as requirements)
|
|
from their parents. Inherited requirements are combined with
|
|
any requirements specified by the sub-project.
|
|
For example, if <filename>top/Jamfile</filename> has
|
|
|
|
<programlisting>
|
|
<include>/home/ghost/local
|
|
</programlisting>
|
|
|
|
in its requirements, then all of its sub-projects will have it
|
|
in their requirements, too. Of course, any project can add
|
|
additional includes. <footnote>Many features will be overridden,
|
|
rather than added-to, in sub-projects. See <xref
|
|
linkend="bbv2.reference.features.attributes"/> for more
|
|
information</footnote> More details can be found in the section
|
|
on <link linkend= "bbv2.advanced.projects">projects</link>.
|
|
</para>
|
|
|
|
<para>
|
|
Invoking <command>bjam</command> without explicitly specifying
|
|
any targets on the command-line builds the project rooted in the
|
|
current directory. Building a project does not automatically
|
|
cause its sub-projects to be built unless the parent project's
|
|
<filename>Jamfile</filename> explicitly requests it. In our
|
|
example, <filename>top/Jamfile</filename> might contain:
|
|
|
|
<programlisting>
|
|
build-project src ;
|
|
</programlisting>
|
|
|
|
which would cause the project in <filename>top/src/</filename>
|
|
to be built whenever the project in <filename>top/</filename> is
|
|
built. However, targets in <filename>top/util/foo/</filename>
|
|
will be built only if they are needed by targets in
|
|
<filename>top/</filename> or <filename>top/src/</filename>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="bbv2.tutorial.libs">
|
|
<title>Libraries and Dependent Targets</title>
|
|
|
|
<comment>TODO: need to make this
|
|
section consistent with "examples-v2/libraries".</comment>
|
|
|
|
<para>
|
|
Targets that are "needed" by other targets are called
|
|
<firstterm>dependencies</firstterm> of those other targets. The
|
|
targets that need the other targets are called
|
|
<firstterm>dependent</firstterm> targets.
|
|
</para>
|
|
|
|
<para>To get a feeling of target dependencies, let's continue the
|
|
above example and see how <filename>src/Jamfile</filename> can
|
|
use libraries from <filename>util/foo</filename>. Assume
|
|
util/foo/Jamfile contains:
|
|
|
|
<programlisting>
|
|
lib bar : bar.cpp ;
|
|
</programlisting>
|
|
|
|
Then, to use this library in <filename>src/Jamfile</filename>, we can write:
|
|
|
|
<programlisting>
|
|
exe app : app.cpp ../util/foo//bar ;
|
|
</programlisting>
|
|
|
|
While <code>app.cpp</code> refers to a regular source file,
|
|
<code>../util/foo//bar</code> is a reference to another target:
|
|
a library "bar" declared in the <filename>Jamfile</filename> at
|
|
<filename>../util/foo</filename>. When linking the
|
|
<command>app</command> executable, the appropriate version of
|
|
<code>bar</code> will be built and linked in. What do we mean by
|
|
"appropriate"? For example, suppose we build "app" with:
|
|
|
|
<screen>
|
|
bjam app optimization=full cxxflags=-w-8080
|
|
</screen>
|
|
|
|
Which properties must be used to build <code>foo</code>? The
|
|
answer is that some properties are
|
|
<firstterm>propagated</firstterm> — 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:
|
|
|
|
<programlisting>
|
|
project
|
|
: usage-requirements <include>.
|
|
;
|
|
|
|
lib foo : foo.cpp ;
|
|
</programlisting>
|
|
|
|
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 <command>bjam</command>s invocation
|
|
directory. For
|
|
example, if building from project root, the final compiler's
|
|
command line will contain <option>-Ilib/foo</option>.
|
|
</para>
|
|
|
|
<para>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:</para>
|
|
|
|
<programlisting>
|
|
project foo
|
|
: usage-requirements <include>.
|
|
;
|
|
</programlisting>
|
|
|
|
<para>
|
|
Second, we use the project id to refer to the library in
|
|
src/Jamfile:
|
|
|
|
<programlisting>
|
|
exe app : app.cpp /foo//bar ;
|
|
</programlisting>
|
|
|
|
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:
|
|
|
|
<programlisting>
|
|
use-project /foo : util/foo ;
|
|
</programlisting>
|
|
|
|
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.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="bbv2.tutorial.depends">
|
|
<title>Library dependencies</title>
|
|
|
|
<para>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.
|
|
Expressing these dependencies is straightforward:</para>
|
|
|
|
<programlisting>
|
|
lib utils : utils.cpp /boost/filesystem//fs ;
|
|
lib core : core.cpp utils ;
|
|
exe app : app.cpp core ;
|
|
</programlisting>
|
|
|
|
<para>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".</para>
|
|
|
|
<para>So, the net result is that the above code will work for both
|
|
static linking and for shared linking.</para>
|
|
|
|
<para>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"
|
|
should be linked to all applications in your project, you can add
|
|
<source>/boost/filesystem//fs to requirements of the
|
|
project, like this:</para>
|
|
|
|
<programlisting>
|
|
project
|
|
: requirements <source>/boost/filesystem//fs
|
|
;
|
|
</programlisting>
|
|
</section>
|
|
|
|
<section id="bbv2.tutorial.linkage">
|
|
<title>Static and shared libaries</title>
|
|
|
|
<para>While the
|
|
previous section explained how to create and use libraries, it
|
|
omitted one important detail. Libraries can be either
|
|
<emphasis>static</emphasis>, which means they are included in executable
|
|
files which use them, or <emphasis>shared</emphasis> (a.k.a.
|
|
<emphasis>dynamic</emphasis>), 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 application which use it might start to behave differently.
|
|
</para>
|
|
|
|
<para>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
|
|
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
|
|
library to a different location, which makes this option suitable
|
|
only for debug builds. Further, only gcc compiler supports this
|
|
option.</para>
|
|
|
|
<para>Building a library statically is easy. You'd need to change
|
|
the value of <link> feature from it's deafault value
|
|
<literal>shared</literal>, to <literal>static</literal>. So, to build everything as
|
|
static libraries, you'd say</para>
|
|
|
|
<screen>
|
|
bjam link=static
|
|
</screen>
|
|
|
|
<para>
|
|
on the command line. The linking mode can be fine-tuned on
|
|
per-target basis.
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Suppose your library can be only build statically. This is
|
|
easily achieved using requirements:
|
|
|
|
<programlisting>
|
|
lib l : l.cpp : <link>static ;
|
|
</programlisting>
|
|
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
What if library can be both static and shared, but when
|
|
using it in specific executable, you want it static?
|
|
<link linkend="bbv2.advanced.targets.references">Target
|
|
references</link> are here to help:
|
|
|
|
<programlisting>
|
|
exe important : main.cpp helpers/<link>static ;
|
|
</programlisting>
|
|
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
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:
|
|
|
|
<programlisting>
|
|
exe e1 : e1.cpp /other_project//bar/<link>static ;
|
|
exe e10 : e10.cpp /other_project//bar/<link>static ;
|
|
</programlisting>
|
|
|
|
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 <filename>foo</filename>. Here's the
|
|
solution:
|
|
|
|
<programlisting>
|
|
alias foo : /other_project//bar/<link>static ;
|
|
exe e1 : e1.cpp foo ;
|
|
exe e10 : e10.cpp foo ;
|
|
</programlisting>
|
|
|
|
Note that the <link linkend="bbv2.builtins.alias">alias</link>
|
|
rule is specifically used for rename a reference to a target and possibly
|
|
change the properties.
|
|
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="bbv2.tutorial.conditions">
|
|
<title>Conditions and alternatives</title>
|
|
|
|
<para>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
|
|
depending on properties.
|
|
</para>
|
|
|
|
<para>The first mechanism is called <firstterm>conditinal
|
|
requirement</firstterm>. 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.
|
|
<programlisting>
|
|
lib network : network.cpp
|
|
: <link>shared:<define>NEWORK_LIB_SHARED
|
|
<variant>release:<define>EXTRA_FAST
|
|
;
|
|
</programlisting>
|
|
This will have exactly the effect we wanted: whenever <link>shared
|
|
is in properties, <define>NEWORK_LIB_SHARED will be in properties
|
|
as well.
|
|
</para>
|
|
|
|
<para>
|
|
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 <firstterm>target alternatives</firstterm>:
|
|
<programlisting>
|
|
lib demangler : dummy_demangler.cpp ;
|
|
lib demangler : demangler_gcc.cpp : <toolset>gcc ;
|
|
lib demangler : demangler_msvc.cpp : <toolset>msvc ;
|
|
</programlisting>
|
|
The proper alternative will be automatically selected.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
<section id="bbv2.tutorial.prebuilt">
|
|
<title>Prebuilt targets</title>
|
|
|
|
<para>
|
|
We've just learned how to use libraries which 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:
|
|
|
|
<programlisting>
|
|
lib lib2
|
|
:
|
|
: <file>lib2_release.a <variant>release
|
|
;
|
|
|
|
lib lib2
|
|
:
|
|
: <file>lib2_debug.a <variant>debug
|
|
;
|
|
</programlisting>
|
|
|
|
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:
|
|
|
|
<programlisting>
|
|
exe app : app.cpp ../util/lib2//lib2 ;
|
|
</programlisting>
|
|
|
|
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:
|
|
|
|
<programlisting>
|
|
lib zlib : : <name>z ;
|
|
</programlisting>
|
|
|
|
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:
|
|
|
|
<programlisting>
|
|
lib zlib : : <name>z <search>/opt/lib ;
|
|
</programlisting>
|
|
|
|
And, of course, two variants can be used:
|
|
|
|
<programlisting>
|
|
lib zlib : : <name>z <variant>release ;
|
|
lib zlib : : <name>z_d <variant>debug ;
|
|
</programlisting>
|
|
|
|
Of course, you'll probably never in your life need debug
|
|
version of zlib, but for other libraries this is quite reasonable.
|
|
</para>
|
|
|
|
<para>More advanced use of prebuilt target is described in <ulink
|
|
url="doc/recipes.html#site_config_targets">recipes</ulink>.</para>
|
|
|
|
</section>
|
|
|
|
</chapter>
|
|
|
|
<!--
|
|
Local Variables:
|
|
mode: xml
|
|
sgml-indent-data:t
|
|
sgml-parent-document:("userman.xml" "chapter")
|
|
sgml-set-face: t
|
|
sgml-omittag:nil
|
|
sgml-shorttag:nil
|
|
sgml-namecase-general:t
|
|
sgml-general-insert-case:lower
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:2
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
-->
|