# Copyright 2003, 2004, 2005 Dave Abrahams # Copyright 2003, 2004, 2005 Douglas Gregor # Copyright 2005, 2006, 2007 Rene Rivera # Copyright 2003, 2004, 2005 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This module defines rules to handle generation of documentation # from BoostBook sources. import "class" : new ; import common ; import errors ; import targets ; import feature ; import generators ; import print ; import property ; import project ; import property-set ; import regex ; import scanner ; import sequence ; import make ; import type ; import modules path project ; import build-system ; import xsltproc : xslt xslt-dir ; # Make this module into a project. project.initialize $(__name__) ; project boostbook ; feature.feature format : html xhtml htmlhelp onehtml man pdf ps docbook fo tests : incidental implicit composite propagated ; type.register DTDXML : dtdxml ; type.register XML : xml ; type.register BOOSTBOOK : boostbook : XML ; type.register DOCBOOK : docbook : XML ; type.register FO : fo : XML ; type.register PDF : pdf ; type.register PS : ps ; type.register XSLT : xsl : XML ; type.register HTMLDIR ; type.register XHTMLDIR ; type.register HTMLHELP ; type.register MANPAGES ; type.register TESTS : tests ; # Artificial target type, used to require invocation of top-level # BoostBook generator. type.register BOOSTBOOK_MAIN ; # Initialize BoostBook support. The parameters are: # docbook-xsl-dir: The DocBook XSL stylesheet directory. If not provided, # we use DOCBOOK_XSL_DIR from the environment (if available). Otherwise, # we let the XML processor load the stylesheets remotely. # # docbook-dtd-dir: The DocBook DTD directory. If not provided, we use # DOCBOOK_DTD_DIR From the environment (if available). Otherwise, we let # the XML processor load the DTD remotely. # # boost-book-dir: The BoostBook directory with the DTD and XSL subdirs. # rule init ( docbook-xsl-dir ? : docbook-dtd-dir ? : boostbook-dir ? ) { docbook-xsl-dir ?= [ modules.peek : DOCBOOK_XSL_DIR ] ; docbook-dtd-dir ?= [ modules.peek : DOCBOOK_DTD_DIR ] ; if ! $(.initialized) { .initialized = true ; if $(docbook-xsl-dir) { .docbook-xsl-dir = [ path.make $(docbook-xsl-dir) ] ; } if $(docbook-dtd-dir) { .docbook-dtd-dir = [ path.make $(docbook-dtd-dir) ] ; } local boost-root = [ modules.peek : BOOST_ROOT ] ; if $(boost-root) { boost-root = [ path.make $(boost-root) ] ; } local boost-build-root = [ build-system.location ] ; local search-dirs = $(boostbook-dir) [ path.join $(boost-root) tools boostbook ] $(boost-build-root)/../../boostbook ; if --debug-configuration in [ modules.peek : ARGV ] { ECHO "notice: Boost.Book: searching XSLS/DTD in" ; ECHO "notice:" [ sequence.transform path.native : $(search-dirs) ] ; } local boostbook-xsl-dir ; for local dir in $(search-dirs) { boostbook-xsl-dir += [ path.glob $(dir) : xsl ] ; } local boostbook-dtd-dir ; for local dir in $(search-dirs) { boostbook-dtd-dir += [ path.glob $(dir) : dtd ] ; } .boostbook-xsl-dir = $(boostbook-xsl-dir[1]) ; .boostbook-dtd-dir = $(boostbook-dtd-dir[1]) ; if ! $(.boostbook-xsl-dir) || ! $(.boostbook-dtd-dir) { errors.warning "couldn't find BoostBook xsl or dtd directories;" : please set \"BOOST_ROOT\" variable to the root directory of your boost installation. Searched in: : $(search-dirs:J=" ") ; } # Register generators only if we've were called via "using boostbook ; " generators.register-standard boostbook.dtdxml-to-boostbook : DTDXML : XML ; generators.register-standard boostbook.boostbook-to-docbook : XML : DOCBOOK ; generators.register-standard boostbook.boostbook-to-tests : XML : TESTS ; generators.register-standard boostbook.docbook-to-onehtml : DOCBOOK : HTML ; generators.register-standard boostbook.docbook-to-htmldir : DOCBOOK : HTMLDIR ; generators.register-standard boostbook.docbook-to-xhtmldir : DOCBOOK : XHTMLDIR ; generators.register-standard boostbook.docbook-to-htmlhelp : DOCBOOK : HTMLHELP ; generators.register-standard boostbook.docbook-to-manpages : DOCBOOK : MANPAGES ; generators.register-standard boostbook.docbook-to-fo : DOCBOOK : FO ; # The same about Jamfile main target rules. IMPORT $(__name__) : boostbook : : boostbook ; } } rule xsl-dir { return $(.boostbook-xsl-dir) ; } rule dtd-dir { return $(.boostbook-dtd-dir) ; } rule docbook-xsl-dir { return $(.docbook-xsl-dir) ; } rule docbook-dtd-dir { return $(.docbook-dtd-dir) ; } rule dtdxml-to-boostbook ( target : source : properties * ) { xslt $(target) : $(source) "$(.boostbook-xsl-dir)/dtd/dtd2boostbook.xsl" : $(properties) ; } rule boostbook-to-docbook ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/docbook.xsl ] ; xslt $(target) : $(source) $(stylesheet) : $(properties) ; } rule docbook-to-onehtml ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/html-single.xsl ] ; xslt $(target) : $(source) $(stylesheet) : $(properties) ; } rule docbook-to-htmldir ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/html.xsl ] ; xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : html ; } rule docbook-to-xhtmldir ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/xhtml.xsl ] ; xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : xhtml ; } rule docbook-to-htmlhelp ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/html-help.xsl ] ; xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : htmlhelp ; } rule docbook-to-manpages ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/manpages.xsl ] ; xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : man ; } rule docbook-to-fo ( target : source : properties * ) { local stylesheet = [ path.native $(.boostbook-xsl-dir)/fo.xsl ] ; xslt $(target) : $(source) $(stylesheet) : $(properties) ; } rule generate-xml-catalog ( target : sources * : properties * ) { print.output $(target) ; # BoostBook DTD catalog entry local boostbook-dtd-dir = [ boostbook.dtd-dir ] ; if $(boostbook-dtd-dir) { boostbook-dtd-dir = [ regex.replace $(boostbook-dtd-dir) " " "%20" ] ; } print.text "" "" "" " " : true ; local docbook-xsl-dir = [ boostbook.docbook-xsl-dir ] ; if ! $(docbook-xsl-dir) { ECHO "BoostBook warning: no DocBook XSL directory specified." ; ECHO " If you have the DocBook XSL stylesheets installed, please " ; ECHO " set DOCBOOK_XSL_DIR to the stylesheet directory on either " ; ECHO " the command line (via -sDOCBOOK_XSL_DIR=...) or in a " ; ECHO " Boost.Jam configuration file. The DocBook XSL stylesheets " ; ECHO " are available here: http://docbook.sourceforge.net/ " ; ECHO " Stylesheets will be downloaded on-the-fly (very slow!) " ; } else { docbook-xsl-dir = [ regex.replace $(docbook-xsl-dir) " " "%20" ] ; print.text " " ; } local docbook-dtd-dir = [ boostbook.docbook-dtd-dir ] ; if ! $(docbook-dtd-dir) { ECHO "BoostBook warning: no DocBook DTD directory specified." ; ECHO " If you have the DocBook DTD installed, please set " ; ECHO " DOCBOOK_DTD_DIR to the DTD directory on either " ; ECHO " the command line (via -sDOCBOOK_DTD_DIR=...) or in a " ; ECHO " Boost.Jam configuration file. The DocBook DTD is available " ; ECHO " here: http://www.oasis-open.org/docbook/xml/4.2/index.shtml" ; ECHO " The DTD will be downloaded on-the-fly (very slow!) " ; } else { docbook-dtd-dir = [ regex.replace $(docbook-dtd-dir) " " "%20" ] ; print.text " " ; } print.text "" ; } rule xml-catalog ( ) { if ! $(.xml-catalog) { # The target is created as part of the root project. But ideally # it would be created as part of the boostbook project. This is not # current possible as such global projects don't inherit things like # the build directory. # Find the root project. local root-project = [ project.current ] ; root-project = [ $(root-project).project-module ] ; while [ project.attribute $(root-project) parent-module ] && [ project.attribute $(root-project) parent-module ] != user-config { root-project = [ project.attribute $(root-project) parent-module ] ; } .xml-catalog = [ new file-target boostbook_catalog : XML : [ project.target $(root-project) ] : [ new action : boostbook.generate-xml-catalog ] : ] ; .xml-catalog-file = [ $(.xml-catalog).path ] [ $(.xml-catalog).name ] ; .xml-catalog-file = $(.xml-catalog-file:J=/) ; } return $(.xml-catalog) $(.xml-catalog-file) ; } class boostbook-generator : generator { import feature ; import virtual-target ; import generators ; import boostbook ; rule __init__ ( * : * ) { generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; } rule run ( project name ? : property-set : sources * ) { # Generate the catalog, but only once... local global-catalog = [ boostbook.xml-catalog ] ; local catalog = $(global-catalog[1]) ; local catalog-file = $(global-catalog[2]) ; local targets ; # Add the catalog to the property set property-set = [ $(property-set).add-raw $(catalog-file) ] ; local type = none ; local manifest ; local format = [ $(property-set).get ] ; switch $(format) { case html : { type = HTMLDIR ; manifest = HTML.manifest ; } case xhtml : { type = XHTMLDIR ; manifest = HTML.manifest ; } case htmlhelp : { type = HTMLHELP ; manifest = HTML.manifest ; } case onehtml : type = HTML ; case man : { type = MANPAGES ; manifest = man.manifest ; } case docbook : type = DOCBOOK ; case fo : type = FO ; case pdf : type = PDF ; case ps : type = PS ; case tests : type = TESTS ; } if $(manifest) { # Create DOCBOOK file from BOOSTBOOK sources. local base-target = [ generators.construct $(project) : DOCBOOK : $(property-set) : $(sources) ] ; base-target = $(base-target[2]) ; $(base-target).depends $(catalog) ; # Generate HTML/PDF/PS from DOCBOOK. local target = [ generators.construct $(project) $(name)_$(manifest) : $(type) : [ $(property-set).add-raw manifest=$(name)_$(manifest) ] : $(base-target) ] ; local name = [ $(property-set).get ] ; name ?= $(format) ; $(target[2]).set-path $(name) ; $(target[2]).depends $(catalog) ; targets += $(target[2]) ; } else { local target = [ generators.construct $(project) : $(type) : $(property-set) : $(sources) ] ; if ! $(target) { errors.error "Cannot build documentation type '$(format)'" ; } else { $(target[2]).depends $(catalog) ; targets += $(target[2]) ; } } return $(targets) ; } } generators.register [ new boostbook-generator boostbook.main : : BOOSTBOOK_MAIN ] ; rule boostbook ( target-name : sources * : requirements * : default-build * ) { local project = [ project.current ] ; targets.main-target-alternative [ new typed-target $(target-name) : $(project) : BOOSTBOOK_MAIN : [ targets.main-target-sources $(sources) : $(target-name) ] : [ targets.main-target-requirements $(requirements) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; } ############################################################################# # Dependency scanners ############################################################################# # XInclude scanner. Mostly stolen from c-scanner :) # Note that this assumes an "xi" prefix for XIncludes. This isn't always the # case for XML documents, but we'll assume it's true for anything we encounter. class xinclude-scanner : scanner { import virtual-target ; import path ; import scanner ; rule __init__ ( includes * ) { scanner.__init__ ; self.includes = $(includes) ; } rule pattern ( ) { return "xi:include[ ]*href=\"([^\"]*)\"" ; } rule process ( target : matches * : binding ) { local target_path = [ NORMALIZE_PATH $(binding:D) ] ; NOCARE $(matches) ; INCLUDES $(target) : $(matches) ; SEARCH on $(matches) = $(target_path) $(self.includes:G=) ; scanner.propagate $(__name__) : $(matches) : $(target) ; } } scanner.register xinclude-scanner : xsl:path ; type.set-scanner XML : xinclude-scanner ; ############################################################################# # Testsuite handling ############################################################################# rule boostbook-to-tests ( target : source : properties * ) { local boost_root = [ modules.peek : BOOST_ROOT ] ; local native-path = [ path.native [ path.join $(.boostbook-xsl-dir) testing Jamfile ] ] ; local stylesheet = $(native-path:S=.xsl) ; xslt $(target) : $(source) $(stylesheet) : $(properties) boost.root=$(boost_root) ; }