]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/doc/src/tutorial.xml
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / tools / build / doc / src / tutorial.xml
CommitLineData
7c673cae
FG
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE chapter PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
3 "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
4
5<?psgml nofill screen programlisting literallayout?>
6
7<chapter id="bbv2.tutorial">
8 <title>Tutorial</title>
9
10<!-- You can't launch into this stuff without describing how to configure -->
11<!-- Boost.Build... unless of course you think it's likely to work with -->
12<!-- no configuration. But even if you do you have to tell people how to -->
13<!-- configure their installation in case it doesn't work. -->
14<!--
15 VP: need also mention the examples which correspond to specific
16 sections.
17-->
18
19 <para>
20 This section will guide you though the most basic features of Boost.Build.
21 We will start with the &#x201C;Hello, world&#x201D; example, learn how
22 to use libraries, and finish with testing and installing features.
23 </para>
24
25 <section id="bbv2.tutorial.hello">
26 <title>Hello, world</title>
27
28 <para>
29 The simplest project that Boost.Build can construct is stored in
30 <filename>example/hello/</filename> directory. The project is described by
31 a file called <filename>Jamroot</filename> that contains:
32
33<programlisting language="jam">
34exe hello : hello.cpp ;
35</programlisting>
36
37 Even with this simple setup, you can do some interesting things. First of
38 all, just invoking <command>b2</command> will build the <filename>hello
39 </filename> executable by compiling and linking <filename>hello.cpp
40 </filename>. By default, the debug variant is built. Now, to build the release
41 variant of <filename>hello</filename>, invoke
42
43<screen>
44b2 release
45</screen>
46
47 Note that the debug and release variants are created in different directories,
48 so you can switch between variants or even build multiple variants at
49 once, without any unnecessary recompilation. Let us extend the example by
50 adding another line to our project's <filename>Jamroot</filename>:
51
52<programlisting language="jam">
53exe hello2 : hello.cpp ;
54</programlisting>
55
56 Now let us build both the debug and release variants of our project again:
57
58<screen>
59b2 debug release
60</screen>
61
62 Note that two variants of <filename>hello2</filename> are linked. Since we
63 have already built both variants of <filename>hello</filename>, hello.cpp
64 will not be recompiled; instead the existing object files will just be
65 linked into the corresponding variants of <filename>hello2</filename>. Now
66 let us remove all the built products:
67
68<screen>
69b2 --clean debug release
70</screen>
71
72 It is also possible to build or clean specific targets. The following two
73 commands, respectively, build or clean only the debug version of
74 <filename>hello2</filename>.
75
76<screen>
77b2 hello2
78b2 --clean hello2
79</screen>
80 </para>
81 </section>
82
83 <section id="bbv2.tutorial.properties">
84 <title>Properties</title>
85
86 <para>
87 To represent aspects of target configuration such as
88 debug and release variants, or single- and multi-threaded
89 builds portably, Boost.Build uses <firstterm>features</firstterm> with
90 associated <firstterm>values</firstterm>. For
91 example, the <code>debug-symbols</code> feature can have a value of <code>on</code> or
92 <code>off</code>. A <firstterm>property</firstterm> is just a (feature,
93 value) pair. When a user initiates a build, Boost.Build
94 automatically translates the requested properties into appropriate
95 command-line flags for invoking toolset components like compilers
96 and linkers.
97 </para>
98
99 <para>
100 There are many built-in features that can be combined to
101 produce arbitrary build configurations. The following command
102 builds the project's <code>release</code> variant with inlining
103 disabled and debug symbols enabled:
104<screen>
105b2 release inlining=off debug-symbols=on
106</screen>
107 </para>
108
109 <para>
110 Properties on the command-line are specified with the syntax:
111
112<screen>
113<replaceable>feature-name</replaceable>=<replaceable>feature-value</replaceable>
114</screen>
115 </para>
116
117 <para>
118 The <option>release</option> and <option>debug</option> that we have seen
119 in <command>b2</command> invocations are just a shorthand way to specify
120 values of the <varname>variant</varname> feature. For example, the
121 command above could also have been written this way:
122
123 <screen>
124b2 variant=release inlining=off debug-symbols=on
125 </screen>
126 </para>
127
128 <para>
129 <varname>variant</varname> is so commonly-used that it has been given
130 special status as an <firstterm>implicit</firstterm> feature&#x2014;
131 Boost.Build will deduce its identity just from the name of one of its
132 values.
133 </para>
134
135 <para>
136 A complete description of features can be found in <xref linkend="bbv2.reference.features"/>.
137 </para>
138
139 <section id="bbv2.tutorial.properties.requirements">
140 <title>Build Requests and Target Requirements</title>
141
142 <para>
143 The set of properties specified on the command line constitutes
144 a <firstterm>build request</firstterm>&#x2014;a description of
145 the desired properties for building the requested targets (or,
146 if no targets were explicitly requested, the project in the
147 current directory). The <emphasis>actual</emphasis>
148 properties used for building targets are typically a
149 combination of the build request and properties derived from
150 the project's <filename>Jamroot</filename> (and its other
151 Jamfiles, as described in <xref
152 linkend="bbv2.tutorial.hierarchy"/>). For example, the
153 locations of <code>#include</code>d header files are normally
154 not specified on the command-line, but described in
155 Jamfiles as <firstterm>target
156 requirements</firstterm> and automatically combined with the
157 build request for those targets. Multithread-enabled
158 compilation is another example of a typical target
159 requirement. The Jamfile fragment below
160 illustrates how these requirements might be specified.
161 </para>
162
163<programlisting language="jam">
164exe hello
165 : hello.cpp
166 : &lt;include&gt;boost &lt;threading&gt;multi
167 ;
168</programlisting>
169
170 <para>
171 When <filename>hello</filename> is built, the two requirements specified
172 above will always be present. If the build request given on the
173 <command>b2</command> command-line explictly contradicts a target's
174 requirements, the target requirements usually override (or, in the case
175 of &#x201C;free&rdquo;&#x201D; features like
176 <varname>&lt;include&gt;</varname>,
177 <footnote>
178 <para>
179 See <xref linkend="bbv2.reference.features.attributes"/>
180 </para>
181 </footnote>
182 augment) the build request.
183 </para>
184
185 <tip>
186 <para>
187 The value of the <varname>&lt;include&gt;</varname> feature is
188 relative to the location of <filename>Jamroot</filename> where it is
189 used.
190 </para>
191 </tip>
192 </section>
193
194 <section id="bbv2.tutorial.properties.project_attributes">
195 <title>Project Attributes</title>
196
197 <para>
198 If we want the same requirements for our other target,
199 <filename>hello2</filename>, we could simply duplicate them. However,
200 as projects grow, that approach leads to a great deal of repeated
201 boilerplate in Jamfiles.
202
203 Fortunately, there's a better way. Each project can specify a set of
204 <firstterm>attributes</firstterm>, including requirements:
205
206<programlisting language="jam">
207project
208 : requirements &lt;include&gt;/home/ghost/Work/boost &lt;threading&gt;multi
209 ;
210
211exe hello : hello.cpp ;
212exe hello2 : hello.cpp ;</programlisting>
213
214 The effect would be as if we specified the same requirement for both
215 <filename>hello</filename> and <filename>hello2</filename>.
216 </para>
217 </section>
218 </section>
219
220 <section id="bbv2.tutorial.hierarchy">
221 <title>Project Hierarchies</title>
222
223 <para>
224 So far we have only considered examples with one project, with
225 one user-written Boost.Jam file, <filename>Jamroot</filename>. A typical
226 large codebase would be composed of many projects organized into a tree.
227 The top of the tree is called the <firstterm>project root</firstterm>.
228 Every subproject is defined by a file called <filename>Jamfile</filename>
229 in a descendant directory of the project root. The parent project of a
230 subproject is defined by the nearest <filename>Jamfile</filename> or
231 <filename>Jamroot</filename> file in an ancestor directory. For example,
232 in the following directory layout:
233
234<screen>
235top/
236 |
237 +-- Jamroot
238 |
239 +-- app/
240 | |
241 | +-- Jamfile
242 | `-- app.cpp
243 |
244 `-- util/
245 |
246 +-- foo/
247 . |
248 . +-- Jamfile
249 . `-- bar.cpp
250</screen>
251
252 the project root is <filename>top/</filename>. The projects in
253 <filename>top/app/</filename> and <filename>top/util/foo/</filename> are
254 immediate children of the root project.
255
256 <note>
257 <para>
258 When we refer to a &#x201C;Jamfile,&#x201D; set in normal
259 type, we mean a file called either
260 <filename>Jamfile</filename> or
261 <filename>Jamroot</filename>. When we need to be more
262 specific, the filename will be set as
263 &#x201C;<filename>Jamfile</filename>&#x201D; or
264 &#x201C;<filename>Jamroot</filename>.&#x201D;
265 </para>
266 </note>
267 </para>
268
269 <para>
270 Projects inherit all attributes (such as requirements)
271 from their parents. Inherited requirements are combined with
272 any requirements specified by the subproject.
273 For example, if <filename>top/Jamroot</filename> has
274
275<programlisting language="jam">
276&lt;include&gt;/home/ghost/local
277</programlisting>
278
279 in its requirements, then all of its subprojects will have it
280 in their requirements, too. Of course, any project can add
281 include paths to those specified by its parents. <footnote>
282 <para>Many
283 features will be overridden,
284 rather than added-to, in subprojects. See <xref
285 linkend="bbv2.reference.features.attributes"/> for more
286 information</para>
287 </footnote>
288 More details can be found in
289 <xref linkend= "bbv2.overview.projects"/>.
290 </para>
291
292 <para>
293 Invoking <command>b2</command> without explicitly specifying
294 any targets on the command line builds the project rooted in the
295 current directory. Building a project does not automatically
296 cause its subprojects to be built unless the parent project's
297 Jamfile explicitly requests it. In our example,
298 <filename>top/Jamroot</filename> might contain:
299
300<programlisting language="jam">
301build-project app ;
302</programlisting>
303
304 which would cause the project in <filename>top/app/</filename>
305 to be built whenever the project in <filename>top/</filename> is
306 built. However, targets in <filename>top/util/foo/</filename>
307 will be built only if they are needed by targets in
308 <filename>top/</filename> or <filename>top/app/</filename>.
309 </para>
310 </section>
311
312 <section id="bbv2.tutorial.libs">
313 <title>Dependent Targets</title>
314
315 <para>
316 When building a target <filename>X</filename> that depends on first
317 building another target <filename>Y</filename> (such as a
318 library that must be linked with <firstterm>X</firstterm>),
319 <filename>Y</filename> is called a
320 <firstterm>dependency</firstterm> of <filename>X</filename> and
321 <filename>X</filename> is termed a
322 <firstterm>dependent</firstterm> of <filename>Y</filename>.
323 </para>
324
325 <para>To get a feeling of target dependencies, let's continue the
326 above example and see how <filename>top/app/Jamfile</filename> can
327 use libraries from <filename>top/util/foo</filename>. If
328 <filename>top/util/foo/Jamfile</filename> contains
329
330<programlisting language="jam">
331lib bar : bar.cpp ;
332</programlisting>
333
334 then to use this library in <filename>top/app/Jamfile</filename>, we can
335 write:
336
337<programlisting language="jam">
338exe app : app.cpp ../util/foo//bar ;
339</programlisting>
340
341 While <code>app.cpp</code> refers to a regular source file,
342 <code>../util/foo//bar</code> is a reference to another target:
343 a library <filename>bar</filename> declared in the Jamfile at
344 <filename>../util/foo</filename>.
345 </para>
346
347 <tip>
348 <para>Some other build system have special syntax for listing dependent
349 libraries, for example <varname>LIBS</varname> variable. In Boost.Build,
350 you just add the library to the list of sources.
351 </para>
352 </tip>
353
354 <para>Suppose we build <filename>app</filename> with:
355 <screen>
356b2 app optimization=full define=USE_ASM
357 </screen>
358 Which properties will be used to build <code>foo</code>? The answer is
359 that some features are
360 <firstterm>propagated</firstterm>&#x2014;Boost.Build attempts to use
361 dependencies with the same value of propagated features. The
362 <varname>&lt;optimization&gt;</varname> feature is propagated, so both
363 <filename>app</filename> and <filename>foo</filename> will be compiled
364 with full optimization. But <varname>&lt;define&gt;</varname> is not
365 propagated: its value will be added as-is to the compiler flags for
366 <filename>a.cpp</filename>, but won't affect <filename>foo</filename>.
367 </para>
368
369
370 <para>
371 Let's improve this project further. The library probably has some headers
372 that must be used when compiling <filename>app.cpp</filename>. We could
373 manually add the necessary <code>#include</code> paths to
374 <filename>app</filename>'s requirements as values of the
375 <varname>&lt;include&gt; </varname> feature, but then this work will be
376 repeated for all programs that use <filename>foo</filename>. A better
377 solution is to modify <filename>util/foo/Jamfile</filename> in this way:
378
379 <programlisting language="jam">
380project
381 : usage-requirements &lt;include&gt;.
382 ;
383
384lib foo : foo.cpp ;</programlisting>
385
386 Usage requirements are applied not to the target being declared but to its
387 dependents. In this case, <literal>&lt;include&gt;.</literal> will be
388 applied to all targets that directly depend on <filename>foo</filename>.
389 </para>
390
391 <para>
392 Another improvement is using symbolic identifiers to refer to the library,
393 as opposed to <filename>Jamfile</filename> location. In a large project, a
394 library can be used by many targets, and if they all use <filename>Jamfile
395 </filename> location, a change in directory organization entails much
396 work. The solution is to use project ids&#x2014;symbolic names not tied to
397 directory layout. First, we need to assign a project id by adding this
398 code to <filename>Jamroot</filename>:
399 </para>
400
401 <programlisting language="jam">
402use-project /library-example/foo : util/foo ;</programlisting>
403
404 <para>
405 Second, we modify <filename>app/Jamfile</filename> to use the project id:
406 <programlisting>
407exe app : app.cpp /library-example/foo//bar ;</programlisting>
408
409 The <filename>/library-example/foo//bar</filename> syntax is used to refer
410 to the target <filename>bar</filename> in the project with id <filename>
411 /library-example/foo</filename>. We've achieved our goal&#x2014;if the
412 library is moved to a different directory, only <filename>Jamroot
413 </filename> must be modified. Note that project ids are global&#x2014;two
414 Jamfiles are not allowed to assign the same project id to different
415 directories.
416 </para>
417
418 <tip>
419 <para>If you want all applications in some project to link to a certain
420 library, you can avoid having to specify directly the sources of
421 every target by using the <varname>&lt;library&gt;</varname> property.
422 For example, if <filename>/boost/filesystem//fs</filename> should be
423 linked to all applications in your project, you can add
424 <code>&lt;library&gt;/boost/filesystem//fs</code> to the project's
425 requirements, like this:
426 </para>
427
428 <programlisting language="jam">
429project
430 : requirements &lt;library&gt;/boost/filesystem//fs
431 ;</programlisting>
432 </tip>
433 </section>
434
435 <section id="bbv2.tutorial.linkage">
436 <title>Static and shared libraries</title>
437
438 <para>
439 Libraries can be either <emphasis>static</emphasis>, which means they are
440 included in executable files that use them, or <emphasis>shared</emphasis>
441 (a.k.a. <emphasis>dynamic</emphasis>), which are only referred to from
442 executables, and must be available at run time. Boost.Build can create and
443 use both kinds.
444 </para>
445
446 <para>
447 The kind of library produced from a <code>lib</code> target is determined
448 by the value of the <varname>link</varname> feature. Default value is
449 <literal>shared</literal>, and to build a static library, the value should
450 be <literal>static</literal>. You can request a static build either on the
451 command line:
452 <programlisting>b2 link=static</programlisting>
453 or in the library's requirements:
454 <programlisting language="jam">lib l : l.cpp : &lt;link&gt;static ;</programlisting>
455 </para>
456
457 <para>
458 We can also use the <varname>&lt;link&gt;</varname> property to express
459 linking requirements on a per-target basis. For example, if a particular
460 executable can be correctly built only with the static version of a
461 library, we can qualify the executable's <link
462 linkend="bbv2.reference.targets.references">target reference</link> to the
463 library as follows:
464
465<!-- There has been no earlier indication that target references can contain
466 properties. You can't assume that the reader will recognize that strange
467 incantation as a target reference, or that she'll know what it means. You
468 also can't assume that hyperlinks will help the reader, because she may be
469 working from a printout, as I was.
470 VP: to be addressed when this section is moved. See comment below.
471-->
472
473 <programlisting language="jam">
474exe important : main.cpp helpers/&lt;link&gt;static ;</programlisting>
475
476 No matter what arguments are specified on the <command>b2</command>
477 command line, <filename>important</filename> will only be linked with the
478 static version of <filename>helpers</filename>.
479 </para>
480
481 <para>
482 Specifying properties in target references is especially useful if you use
483 a library defined in some other project (one you can't change) but you
484 still want static (or dynamic) linking to that library in all cases. If
485 that library is used by many targets, you <emphasis>could</emphasis> use
486 target references everywhere:
487
488 <programlisting language="jam">
489exe e1 : e1.cpp /other_project//bar/&lt;link&gt;static ;
490exe e10 : e10.cpp /other_project//bar/&lt;link&gt;static ;</programlisting>
491
492 but that's far from being convenient. A better approach is to introduce a
493 level of indirection. Create a local <type>alias</type> target that refers
494 to the static (or dynamic) version of <filename>foo</filename>:
495
496 <programlisting>
497alias foo : /other_project//bar/&lt;link&gt;static ;
498exe e1 : e1.cpp foo ;
499exe e10 : e10.cpp foo ;</programlisting>
500
501 The <link linkend="bbv2.tasks.alias">alias</link> rule is specifically
502 used to rename a reference to a target and possibly change the
503 properties.
504
505 <!-- You should introduce the alias rule in an earlier section, before
506 describing how it applies to this specific use-case, and the
507 foregoing sentence should go there.
508 VP: we've agreed that this section should be moved further in the
509 docs, since it's more like advanced reading. When I move it, I'll
510 make sure 'alias' is already mentioned.
511 -->
512 </para>
513
514 <tip>
515 <para>
516 When one library uses another, you put the second library in the source
517 list of the first. For example:
518 <programlisting language="jam">
519lib utils : utils.cpp /boost/filesystem//fs ;
520lib core : core.cpp utils ;
521exe app : app.cpp core ;</programlisting>
522 This works no matter what kind of linking is used. When <filename>core
523 </filename> is built as a shared library, links <filename>utils
524 </filename> directly into it. Static libraries can't link to other
525 libraries, so when <filename>core</filename> is built as a static
526 library, its dependency on <filename>utils</filename> is passed along to
527 <filename>core</filename>'s dependents, causing <filename>app</filename>
528 to be linked with both <filename>core</filename> and <filename>utils
529 </filename>.
530 </para>
531 </tip>
532
533 <note>
534 <para>
535 (Note for non-UNIX system). Typically, shared libraries must be
536 installed to a directory in the dynamic linker's search path. Otherwise,
537 applications that use shared libraries can't be started. On Windows, the
538 dynamic linker's search path is given by the <envar>PATH</envar>
539 environment variable. This restriction is lifted when you use
540 Boost.Build testing facilities&#x2014;the <envar>PATH</envar> variable
541 will be automatically adjusted before running the executable.
542 <!-- Need ref here to 'testing facilities' -->
543 </para>
544 </note>
545 </section>
546
547 <section id="bbv2.tutorial.conditions">
548 <title>Conditions and alternatives</title>
549
550 <para>
551 Sometimes, particular relationships need to be maintained among a target's
552 build properties. For example, you might want to set specific <code>
553 #define</code> when a library is built as shared, or when a target's
554 <code>release</code> variant is built. This can be achieved using
555 <firstterm>conditional requirements</firstterm>.
556
557 <programlisting language="jam">
558lib network : network.cpp
559 : <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NETWORK_LIB_SHARED</emphasis>
560 &lt;variant&gt;release:&lt;define&gt;EXTRA_FAST
561 ;</programlisting>
562
563 In the example above, whenever <filename>network</filename> is built with
564 <code language="jam">&lt;link&gt;shared</code>, <code language="jam">&lt;define&gt;NETWORK_LIB_SHARED
565 </code> will be in its properties, too. Also, whenever its release variant
566 is built, <code>&lt;define&gt;EXTRA_FAST</code> will appear in its
567 properties.
568 </para>
569
570 <para>
571 Sometimes the ways a target is built are so different that describing them
572 using conditional requirements would be hard. For example, imagine that a
573 library actually uses different source files depending on the toolset used
574 to build it. We can express this situation using <firstterm>target
575 alternatives</firstterm>:
576 <programlisting language="jam">
577lib demangler : dummy_demangler.cpp ; # alternative 1
578lib demangler : demangler_gcc.cpp : &lt;toolset&gt;gcc ; # alternative 2
579lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3</programlisting>
580 When building <filename>demangler</filename>, Boost.Build will compare
581 requirements for each alternative with build properties to find the best
582 match. For example, when building with <code language="jam">&lt;toolset&gt;gcc</code>
583 alternative 2, will be selected, and when building with
584 <code language="jam">&lt;toolset&gt;msvc</code> alternative 3 will be selected. In all
585 other cases, the most generic alternative 1 will be built.
586 </para>
587 </section>
588
589 <section id="bbv2.tutorial.prebuilt">
590 <title>Prebuilt targets</title>
591
592 <para>
593 To link to libraries whose build instructions aren't given in a Jamfile,
594 you need to create <code>lib</code> targets with an appropriate
595 <varname>file</varname> property. Target alternatives can be used to
596 associate multiple library files with a single conceptual target. For
597 example:
598 <programlisting language="jam">
599# util/lib2/Jamfile
600lib lib2
601 :
602 : &lt;file&gt;lib2_release.a &lt;variant&gt;release
603 ;
604
605lib lib2
606 :
607 : &lt;file&gt;lib2_debug.a &lt;variant&gt;debug
608 ;</programlisting>
609
610 This example defines two alternatives for <filename>lib2</filename>, and
611 for each one names a prebuilt file. Naturally, there are no sources.
612 Instead, the <varname>&lt;file&gt;</varname> feature is used to specify
613 the file name.
614 </para>
615
616 <para>
617 Once a prebuilt target has been declared, it can be used just like any
618 other target:
619
620 <programlisting language="jam">
621exe app : app.cpp ../util/lib2//lib2 ;</programlisting>
622
623 As with any target, the alternative selected depends on the properties
624 propagated from <filename>lib2</filename>'s dependents. If we build the
625 release and debug versions of <filename>app</filename> it will be linked
626 with <filename>lib2_release.a</filename> and <filename>lib2_debug.a
627 </filename>, respectively.
628 </para>
629
630 <para>
631 System libraries&#x2014;those that are automatically found by the toolset
632 by searching through some set of predetermined paths&#x2014;should be
633 declared almost like regular ones:
634
635 <programlisting language="jam">
636lib pythonlib : : &lt;name&gt;python22 ;</programlisting>
637
638 We again don't specify any sources, but give a <varname>name</varname>
639 that should be passed to the compiler. If the gcc toolset were used to
640 link an executable target to <filename>pythonlib</filename>,
641 <option>-lpython22</option> would appear in the command line (other
642 compilers may use different options).
643 </para>
644
645 <para>
646 We can also specify where the toolset should look for the library:
647
648 <programlisting language="jam">
649lib pythonlib : : &lt;name&gt;python22 &lt;search&gt;/opt/lib ;</programlisting>
650
651 And, of course, target alternatives can be used in the usual way:
652
653 <programlisting language="jam">
654lib pythonlib : : &lt;name&gt;python22 &lt;variant&gt;release ;
655lib pythonlib : : &lt;name&gt;python22_d &lt;variant&gt;debug ;</programlisting>
656 </para>
657
658 <para>
659 A more advanced use of prebuilt targets is described in <xref linkend=
660 "bbv2.recipies.site-config"/>.
661 </para>
662 </section>
663</chapter>
664
665<!--
666 Local Variables:
667 mode: nxml
668 sgml-indent-data:t
669 sgml-parent-document:("userman.xml" "chapter")
670 sgml-set-face: t
671 sgml-omittag:nil
672 sgml-shorttag:nil
673 sgml-namecase-general:t
674 sgml-general-insert-case:lower
675 sgml-minimize-attributes:nil
676 sgml-always-quote-attributes:t
677 sgml-indent-step:2
678 sgml-exposed-tags:nil
679 sgml-local-catalogs:nil
680 sgml-local-ecat-files:nil
681 End:
682-->