1#
2#   Copyright (c) 2005 Jo�o Abecasis
3#   Copyright (c) 2005 Vladimir Prus
4#   Copyright (c) 2006 Rene Rivera
5#
6#   Distributed under the Boost Software License, Version 1.0. (See
7#   accompanying file LICENSE_1_0.txt or copy at
8#   http://www.boost.org/LICENSE_1_0.txt)
9#
10
11# This toolset defines a generator to translate QuickBook to BoostBook. It can
12# be used to generate nice (!) user documentation in different formats
13# (pdf/html/...), from a single text file with simple markup.
14#
15# The toolset defines the QUICKBOOK type (file extension 'qbk') and
16# a QUICKBOOK to XML (BOOSTBOOK) generator.
17#
18#
19#   ===========================================================================
20#   Q & A
21#   ===========================================================================
22#
23#   If you don't know what this is all about, some Q & A will hopefully get you
24#   up to speed with QuickBook and this toolset.
25#
26#
27#   What is QuickBook ?
28#
29#       QuickBook is a WikiWiki style documentation tool geared towards C++
30#       documentation using simple rules and markup for simple formatting tasks.
31#       QuickBook extends the WikiWiki concept. Like the WikiWiki, QuickBook
32#       documents are simple text files. A single QuickBook document can
33#       generate a fully linked set of nice HTML and PostScript/PDF documents
34#       complete with images and syntax-colorized source code.
35#
36#
37#   Where can I get QuickBook ?
38#
39#       Quickbook can be found in Boost's repository, under the tools/quickbook
40#       directory it was added there on Jan 2005, some time after the release of
41#       Boost v1.32.0 and has been an integral part of the Boost distribution
42#       since v1.33.
43#
44#       Here's a link to the SVN repository:
45#           https://svn.boost.org/svn/boost/trunk/tools/quickbook
46#
47#       And to QuickBook's QuickBook-generated docs:
48#           http://www.boost.org/doc/libs/release/tools/quickbook/index.html
49#
50#
51#   How do I use QuickBook and this toolset in my projects ?
52#
53#       The minimal example is:
54#
55#           using boostbook ;
56#           import quickbook ;
57#
58#           boostbook my_docs : my_docs_source.qbk ;
59#
60#       where my_docs is a target name and my_docs_source.qbk is a QuickBook
61#       file. The documentation format to be generated is determined by the
62#       boostbook toolset. By default html documentation should be generated,
63#       but you should check BoostBook's docs to be sure.
64#
65#
66#   What do I need ?
67#
68#       You should start by setting up the BoostBook toolset. Please refer to
69#       boostbook.jam and the BoostBook documentation for information on how to
70#       do this.
71#
72#       A QuickBook executable is also needed. The toolset will generate this
73#       executable if it can find the QuickBook sources. The following
74#       directories will be searched:
75#
76#           BOOST_ROOT/tools/quickbook/
77#           BOOST_BUILD_PATH/../../quickbook/
78#
79#       (BOOST_ROOT and BOOST_BUILD_PATH are environment variables)
80#
81#       If QuickBook sources are not found the toolset will then try to use
82#       the shell command 'quickbook'.
83#
84#
85#   How do I provide a custom QuickBook executable ?
86#
87#       You may put the following in your user-config.jam or site-config.jam:
88#
89#           using quickbook : /path/to/quickbook ;
90#
91#       or, if 'quickbook' can be found in your PATH,
92#
93#           using quickbook : quickbook ;
94#
95#
96#   For convenience three alternatives are tried to get a QuickBook executable:
97#
98#       1.  If the user points us to the a QuickBook executable, that is used.
99#
100#       2.  Otherwise, we search for the QuickBook sources and compile QuickBook
101#           using the default toolset.
102#
103#       3.  As a last resort, we rely on the shell for finding 'quickbook'.
104#
105
106import boostbook ;
107import "class" : new ;
108import feature ;
109import generators ;
110import toolset ;
111import type ;
112import scanner ;
113import project ;
114import targets ;
115import build-system ;
116import path ;
117import common ;
118import errors ;
119
120# The one and only QUICKBOOK type!
121type.register QUICKBOOK : qbk ;
122
123# <quickbook-binary> shell command to run QuickBook
124# <quickbook-binary-dependencies> targets to build QuickBook from sources.
125feature.feature <quickbook-binary> : : free ;
126feature.feature <quickbook-binary-dependencies> : : free dependency ;
127feature.feature <quickbook-define> : : free ;
128feature.feature <quickbook-indent> : : free ;
129feature.feature <quickbook-line-width> : : free ;
130feature.feature <quickbook-strict-mode> : : free ;
131
132
133# quickbook-binary-generator handles generation of the QuickBook executable, by
134# marking it as a dependency for QuickBook docs.
135#
136# If the user supplied the QuickBook command that will be used.
137#
138# Otherwise we search some sensible places for the QuickBook sources and compile
139# from scratch using the default toolset.
140#
141# As a last resort we rely on the shell to find 'quickbook'.
142#
143class quickbook-binary-generator : generator
144{
145    import modules path targets quickbook ;
146
147    rule run ( project name ? : property-set : sources * : multiple ? )
148    {
149        quickbook.freeze-config ;
150        # QuickBook invocation command and dependencies.
151        local quickbook-binary = [ modules.peek quickbook : .quickbook-binary ] ;
152        local quickbook-binary-dependencies ;
153
154        if ! $(quickbook-binary)
155        {
156            # If the QuickBook source directory was found, mark its main target
157            # as a dependency for the current project. Otherwise, try to find
158            # 'quickbook' in user's PATH
159            local quickbook-dir = [ modules.peek quickbook : .quickbook-dir ] ;
160            if $(quickbook-dir)
161            {
162                # Get the main-target in QuickBook directory.
163                local quickbook-main-target = [ targets.resolve-reference $(quickbook-dir) : $(project) ] ;
164
165                # The first element are actual targets, the second are
166                # properties found in target-id. We do not care about these
167                # since we have passed the id ourselves.
168                quickbook-main-target =
169                    [ $(quickbook-main-target[1]).main-target quickbook ] ;
170
171                quickbook-binary-dependencies =
172                    [ $(quickbook-main-target).generate [ $(property-set).propagated ] ] ;
173
174                # Ignore usage-requirements returned as first element.
175                quickbook-binary-dependencies = $(quickbook-binary-dependencies[2-]) ;
176
177                # Some toolsets generate extra targets (e.g. RSP). We must mark
178                # all targets as dependencies for the project, but we will only
179                # use the EXE target for quickbook-to-boostbook translation.
180                for local target in $(quickbook-binary-dependencies)
181                {
182                    if [ $(target).type ] = EXE
183                    {
184                        quickbook-binary =
185                            [ path.native
186                                [ path.join
187                                    [ $(target).path ]
188                                    [ $(target).name ]
189                                ]
190                            ] ;
191                    }
192                }
193            }
194        }
195
196        # Add $(quickbook-binary-dependencies) as a dependency of the current
197        # project and set it as the <quickbook-binary> feature for the
198        # quickbook-to-boostbook rule, below.
199        property-set = [ $(property-set).add-raw
200            <dependency>$(quickbook-binary-dependencies)
201            <quickbook-binary>$(quickbook-binary)
202            <quickbook-binary-dependencies>$(quickbook-binary-dependencies)
203        ] ;
204
205        return [ generator.run $(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
206    }
207}
208
209
210# Define a scanner for tracking QBK include dependencies.
211#
212class qbk-scanner : common-scanner
213{
214    rule pattern ( )
215    {
216        return "\\[[ ]*include[ ]+([^]]+)\\]"
217        "\\[[ ]*include:[a-zA-Z0-9_]+[ ]+([^]]+)\\]"
218        "\\[[ ]*import[ ]+([^]]+)\\]" ;
219    }
220}
221
222
223scanner.register qbk-scanner : include ;
224
225type.set-scanner QUICKBOOK : qbk-scanner ;
226
227
228# Initialization of toolset.
229#
230# Parameters:
231#   command ?    -> path to QuickBook executable.
232#
233# When command is not supplied toolset will search for QuickBook directory and
234# compile the executable from source. If that fails we still search the path for
235# 'quickbook'.
236#
237rule init (
238        command ?   # path to the QuickBook executable.
239    )
240{
241    if $(command)
242    {
243        if $(.config-frozen)
244        {
245            errors.user-error "quickbook: configuration cannot be changed after it has been used." ;
246        }
247        .command = $(command) ;
248    }
249}
250
251rule freeze-config ( )
252{
253    if ! $(.config-frozen)
254    {
255        .config-frozen = true ;
256
257        # QuickBook invocation command and dependencies.
258
259        .quickbook-binary = $(.command) ;
260
261        if $(.quickbook-binary)
262        {
263            # Use user-supplied command.
264            .quickbook-binary = [ common.get-invocation-command quickbook : quickbook : $(.quickbook-binary) ] ;
265        }
266        else
267        {
268            # Search for QuickBook sources in sensible places, like
269            #   $(BOOST_ROOT)/tools/quickbook
270            #   $(BOOST_BUILD_PATH)/../../quickbook
271
272            # And build quickbook executable from sources.
273
274            local boost-root = [ modules.peek : BOOST_ROOT ] ;
275            local boost-build-path = [ build-system.location ] ;
276
277            if $(boost-root)
278            {
279                .quickbook-dir += [ path.join $(boost-root) tools ] ;
280            }
281
282            if $(boost-build-path)
283            {
284                .quickbook-dir += $(boost-build-path)/../.. ;
285            }
286
287            .quickbook-dir = [ path.glob $(.quickbook-dir) : quickbook ] ;
288
289            # If the QuickBook source directory was found, mark its main target
290            # as a dependency for the current project. Otherwise, try to find
291            # 'quickbook' in user's PATH
292            if $(.quickbook-dir)
293            {
294                .quickbook-dir = [ path.make $(.quickbook-dir[1]) ] ;
295            }
296            else
297            {
298                ECHO "QuickBook warning: The path to the quickbook executable was" ;
299                ECHO "  not provided. Additionally, couldn't find QuickBook" ;
300                ECHO "  sources searching in" ;
301                ECHO "    * BOOST_ROOT/tools/quickbook" ;
302                ECHO "    * BOOST_BUILD_PATH/../../quickbook" ;
303                ECHO "  Will now try to find a precompiled executable by searching" ;
304                ECHO "  the PATH for 'quickbook'." ;
305                ECHO "  To disable this warning in the future, or to completely" ;
306                ECHO "  avoid compilation of quickbook, you can explicitly set the" ;
307                ECHO "  path to a quickbook executable command in user-config.jam" ;
308                ECHO "  or site-config.jam with the call" ;
309                ECHO "    using quickbook : /path/to/quickbook ;" ;
310
311                # As a last resort, search for 'quickbook' command in path. Note
312                # that even if the 'quickbook' command is not found,
313                # get-invocation-command will still return 'quickbook' and might
314                # generate an error while generating the virtual-target.
315
316                .quickbook-binary = [ common.get-invocation-command quickbook : quickbook ] ;
317            }
318        }
319    }
320}
321
322
323generators.register [ new quickbook-binary-generator quickbook.quickbook-to-boostbook : QUICKBOOK : XML ] ;
324
325
326# <quickbook-binary> shell command to run QuickBook
327# <quickbook-binary-dependencies> targets to build QuickBook from sources.
328toolset.flags quickbook.quickbook-to-boostbook QB-COMMAND      <quickbook-binary> ;
329toolset.flags quickbook.quickbook-to-boostbook QB-DEPENDENCIES <quickbook-binary-dependencies> ;
330toolset.flags quickbook.quickbook-to-boostbook INCLUDES        <include> ;
331toolset.flags quickbook.quickbook-to-boostbook QB-DEFINES      <quickbook-define> ;
332toolset.flags quickbook.quickbook-to-boostbook QB-INDENT       <quickbook-indent> ;
333toolset.flags quickbook.quickbook-to-boostbook QB-LINE-WIDTH   <quickbook-line-width> ;
334toolset.flags quickbook.quickbook-to-boostbook QB-OPTIONS      <quickbook-strict-mode>on : --strict ;
335
336
337rule quickbook-to-boostbook ( target : source : properties * )
338{
339    # Signal dependency of quickbook sources on <quickbook-binary-dependencies>
340    # upon invocation of quickbook-to-boostbook.
341    DEPENDS $(target) : [ on $(target) return $(QB-DEPENDENCIES) ] ;
342}
343
344
345actions quickbook-to-boostbook
346{
347    "$(QB-COMMAND)" -I"$(INCLUDES)" -D"$(QB-DEFINES)" --indent="$(QB-INDENT)" --linewidth="$(QB-LINE-WIDTH)" $(QB-OPTIONS) --output-file="$(1)" "$(2)"
348}
349
350
351# Declare a main target to convert a quickbook source into a boostbook XML file.
352#
353rule to-boostbook ( target-name : sources * : requirements * : default-build * )
354{
355  local project = [ project.current ] ;
356
357  targets.main-target-alternative
358    [ new typed-target $(target-name) : $(project) : XML
359        : [ targets.main-target-sources $(sources) : $(target-name) ]
360        : [ targets.main-target-requirements $(requirements) : $(project) ]
361        : [ targets.main-target-default-build $(default-build) : $(project) ]
362    ] ;
363}
364