# Copyright 2003, 2004 Douglas Gregor # Copyright 2003, 2004, 2005 Vladimir Prus # Copyright 2006 Rene Rivera # 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 various outputs from source # files documented with doxygen comments. The supported transformations are: # # * Source -> Doxygen XML -> BoostBook XML # * Source -> Doxygen HTML # # The type of transformation is selected based on the target requested. For # BoostBook XML, the default, specifying a target with an ".xml" suffix, or an # empty suffix, will produce a .xml and .boostbook. For Doxygen # HTML specifying a target with an ".html" suffix will produce a directory # with the Doxygen html files, and a .html file redirecting to # that directory. import "class" : new ; import targets ; import feature ; import property ; import generators ; import boostbook ; import type ; import path ; import print ; import regex ; import stage ; import project ; import xsltproc ; import make ; import os ; import toolset : flags ; import alias ; import common ; import modules ; # Use to specify extra configuration paramters. These get translated # into a doxyfile which configures the building of the docs. feature.feature doxygen:param : : free ; # Specify the "boost.doxygen.header.prefix" XSLT option. feature.feature prefix : : free ; # Specify the "boost.doxygen.reftitle" XSLT option. feature.feature reftitle : : free ; # Which processor to use for various translations from Doxygen. feature.feature doxygen.processor : xsltproc doxproc : propagated implicit ; # To generate, or not, index sections. feature.feature doxygen.doxproc.index : no yes : propagated incidental ; # The ID for the resulting BoostBook reference section. feature.feature doxygen.doxproc.id : : free ; # The title for the resulting BoostBook reference section. feature.feature doxygen.doxproc.title : : free ; # Doxygen configuration input file. type.register DOXYFILE : doxyfile ; # Doxygen XML multi-file output. type.register DOXYGEN_XML_MULTIFILE : xml-dir : XML ; # Doxygen XML coallesed output. type.register DOXYGEN_XML : doxygen : XML ; # Doxygen HTML multifile directory. type.register DOXYGEN_HTML_MULTIFILE : html-dir : HTML ; # Redirection HTML file to HTML multifile directory. type.register DOXYGEN_HTML : : HTML ; # Initialize the Doxygen module. Parameters are: # name: the name of the 'doxygen' executable. If not specified, the name # 'doxygen' will be used # rule init ( name ? ) { if ! $(.initialized) { .initialized = true ; if ! $(name) { local doxygen-path ; if [ os.name ] = NT { local ProgramFiles = [ modules.peek : ProgramFiles ] ; if $(ProgramFiles) { ProgramFiles = "$(ProgramFiles:J= )" ; } else { ProgramFiles = "C:\\Program Files" ; } doxygen-path = [ GLOB [ modules.peek : PATH ] "$(ProgramFiles)\\doxygen\\bin" : doxygen\.exe ] ; } else { doxygen-path = [ GLOB [ modules.peek : PATH ] : doxygen ] ; } doxygen-path = $(doxygen-path[1]) ; if $(doxygen-path) { .doxygen = $(doxygen-path) ; } .doxygen ?= doxygen ; } else { .doxygen = $(name) ; } if --debug-configuration in [ modules.peek : ARGV ] { ECHO "notice:" using doxygen ":" $(.doxygen) ; } .doxproc = [ modules.binding $(__name__) ] ; .doxproc = $(.doxproc:D)/doxproc.py ; generators.register-composing doxygen.headers-to-doxyfile : H HPP CPP : DOXYFILE ; generators.register-standard doxygen.run : DOXYFILE : DOXYGEN_XML_MULTIFILE ; generators.register-standard doxygen.xml-dir-to-boostbook : DOXYGEN_XML_MULTIFILE : BOOSTBOOK : doxproc ; generators.register-standard doxygen.xml-to-boostbook : DOXYGEN_XML : BOOSTBOOK : xsltproc ; generators.register-standard doxygen.collect : DOXYGEN_XML_MULTIFILE : DOXYGEN_XML ; generators.register-standard doxygen.run : DOXYFILE : DOXYGEN_HTML_MULTIFILE ; generators.register-standard doxygen.html-redirect : DOXYGEN_HTML_MULTIFILE : DOXYGEN_HTML ; IMPORT $(__name__) : doxygen : : doxygen ; } } rule name ( ) { return $(.doxygen) ; } # Runs Doxygen on the given Doxygen configuration file (the source) to generate # the Doxygen files. The output is dumped according to the settings in the # Doxygen configuration file, not according to the target! Because of this, we # essentially "touch" the target file, in effect making it look like we have # really written something useful to it. Anyone that uses this action must deal # with this behavior. # actions doxygen-action { $(RM) "$(*.XML)" & "$(NAME:E=doxygen)" "$(>)" && echo "Stamped" > "$(<)" } # Runs the Python doxproc XML processor. # actions doxproc { python "$(DOXPROC)" "--xmldir=$(>)" "--output=$(<)" "$(OPTIONS)" "--id=$(ID)" "--title=$(TITLE)" } # Generates a doxygen configuration file (doxyfile) given a set of C++ sources # and a property list that may contain features. # rule headers-to-doxyfile ( target : sources * : properties * ) { local text "# Generated by Boost.Build version 2" ; local output-dir ; # Translate into command line flags. for local param in [ feature.get-values : $(properties) ] { local namevalue = [ regex.match ([^=]*)=(.*) : $(param) ] ; text += "$(namevalue[1]) = $(namevalue[2])" ; if $(namevalue[1]) = OUTPUT_DIRECTORY { output-dir = "$(namevalue[2])" ; } } if ! $(output-dir) { output-dir = [ on $(target) return $(LOCATE) ] ; text += "OUTPUT_DIRECTORY = \"$(output-dir)\"" ; } local headers = \"$(sources:G=)\" ; # Doxygen generates LaTex by default. So disable it unconditionally, or at # least until someone needs, and hence writes support for, LaTex output. text += "GENERATE_LATEX = NO" ; text += "INPUT = $(headers:J= )" ; print.output $(target) plain ; print.text $(text) : true ; } # Run Doxygen. See doxygen-action for a description of the strange properties of # this rule. # rule run ( target : source : properties * ) { doxygen-action $(target) : $(source) ; NAME on $(target) = $(.doxygen) ; RM on $(target) = [ modules.peek common : RM ] ; *.XML on $(target) = [ path.native [ path.join [ path.make [ on $(target) return $(LOCATE) ] ] $(target:B:S=) *.xml ] ] ; } # The rules below require Boost.Book stylesheets, so we need some code to check # that the boostbook module has actualy been initialized. # rule check-boostbook ( ) { if ! [ modules.peek boostbook : .initialized ] { ECHO "error: the boostbook module is not initialized" ; ECHO "error: you've attempted to use the 'doxygen' toolset, " ; ECHO "error: which requires Boost.Book," ; ECHO "error: but never initialized Boost.Book." ; EXIT "error: Hint: add 'using boostbook ;' to your user-config.jam" ; } } # Collect the set of Doxygen XML files into a single XML source file that can be # handled by an XSLT processor. The source is completely ignored (see # doxygen-action), because this action picks up the Doxygen XML index file # xml/index.xml. This is because we can not teach Doxygen to act like a NORMAL # program and take a "-o output.xml" argument (grrrr). The target of the # collection will be a single Doxygen XML file. # rule collect ( target : source : properties * ) { check-boostbook ; local collect-xsl-dir = [ path.native [ path.join [ boostbook.xsl-dir ] doxygen collect ] ] ; local source-path = [ path.make [ on $(source) return $(LOCATE) ] ] ; local collect-path = [ path.root [ path.join $(source-path) $(source:B) ] [ path.pwd ] ] ; local native-path = [ path.native $(collect-path) ] ; local real-source = [ path.native [ path.join $(collect-path) index.xml ] ] ; xsltproc.xslt $(target) : $(real-source) $(collect-xsl-dir:S=.xsl) : doxygen.xml.path=$(native-path) ; } # Translate Doxygen XML into BoostBook. # rule xml-to-boostbook ( target : source : properties * ) { check-boostbook ; local xsl-dir = [ boostbook.xsl-dir ] ; local d2b-xsl = [ path.native [ path.join [ boostbook.xsl-dir ] doxygen doxygen2boostbook.xsl ] ] ; local xslt-properties = $(properties) ; for local prefix in [ feature.get-values : $(properties) ] { xslt-properties += "boost.doxygen.header.prefix=$(prefix)" ; } for local title in [ feature.get-values : $(properties) ] { xslt-properties += "boost.doxygen.reftitle=$(title)" ; } xsltproc.xslt $(target) : $(source) $(d2b-xsl) : $(xslt-properties) ; } flags doxygen.xml-dir-to-boostbook OPTIONS yes : --enable-index ; flags doxygen.xml-dir-to-boostbook ID ; flags doxygen.xml-dir-to-boostbook TITLE ; rule xml-dir-to-boostbook ( target : source : properties * ) { DOXPROC on $(target) = $(.doxproc) ; LOCATE on $(source:S=) = [ on $(source) return $(LOCATE) ] ; doxygen.doxproc $(target) : $(source:S=) ; } # Generate the HTML redirect to HTML dir index.html file. # rule html-redirect ( target : source : properties * ) { local uri = "$(target:B)/index.html" ; print.output $(target) plain ; print.text " Automatic redirection failed, please go to $(uri). " : true ; } # User-level rule to generate BoostBook XML from a set of headers via Doxygen. # rule doxygen ( target : sources * : requirements * : default-build * : usage-requirements * ) { local project = [ project.current ] ; if $(target:S) = .html { # Build an HTML directory from the sources. local html-location = [ feature.get-values : $(requirements) ] ; local output-dir ; if [ $(project).get build-dir ] { # Explicitly specified build dir. Add html at the end. output-dir = [ path.join [ $(project).build-dir ] $(html-location:E=html) ] ; } else { # Trim 'bin' from implicit build dir, for no other reason that backward # compatibility. output-dir = [ path.join [ path.parent [ $(project).build-dir ] ] $(html-location:E=html) ] ; } output-dir = [ path.root $(output-dir) [ path.pwd ] ] ; local output-dir-native = [ path.native $(output-dir) ] ; requirements = [ property.change $(requirements) : ] ; ## The doxygen configuration file. targets.main-target-alternative [ new typed-target $(target:S=.tag) : $(project) : DOXYFILE : [ targets.main-target-sources $(sources) : $(target:S=.tag) ] : [ targets.main-target-requirements $(requirements) GENERATE_HTML=YES GENERATE_XML=NO "OUTPUT_DIRECTORY=\"$(output-dir-native)\"" HTML_OUTPUT=$(target:B) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; $(project).mark-target-as-explicit $(target:S=.tag) ; ## The html directory to generate by running doxygen. targets.main-target-alternative [ new typed-target $(target:S=.dir) : $(project) : DOXYGEN_HTML_MULTIFILE : $(target:S=.tag) : [ targets.main-target-requirements $(requirements) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; $(project).mark-target-as-explicit $(target:S=.dir) ; ## The redirect html file into the generated html. targets.main-target-alternative [ new typed-target $(target) : $(project) : DOXYGEN_HTML : $(target:S=.dir) : [ targets.main-target-requirements $(requirements) $(output-dir) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; } else { # Build a BoostBook XML file from the sources. local location-xml = [ feature.get-values : $(requirements) ] ; requirements = [ property.change $(requirements) : ] ; local target-xml = $(target:B=$(target:B)-xml) ; ## The doxygen configuration file. targets.main-target-alternative [ new typed-target $(target-xml:S=.tag) : $(project) : DOXYFILE : [ targets.main-target-sources $(sources) : $(target-xml:S=.tag) ] : [ targets.main-target-requirements $(requirements) GENERATE_HTML=NO GENERATE_XML=YES XML_OUTPUT=$(target-xml) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; $(project).mark-target-as-explicit $(target-xml:S=.tag) ; ## The Doxygen XML directory of the processed source files. targets.main-target-alternative [ new typed-target $(target-xml:S=.dir) : $(project) : DOXYGEN_XML_MULTIFILE : $(target-xml:S=.tag) : [ targets.main-target-requirements $(requirements) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; $(project).mark-target-as-explicit $(target-xml:S=.dir) ; ## The resulting BoostBook file is generated by the processor tool. The ## tool can be either the xsltproc plus accompanying XSL scripts. Or it ## can be the python doxproc.py script. targets.main-target-alternative [ new typed-target $(target-xml) : $(project) : BOOSTBOOK : $(target-xml:S=.dir) : [ targets.main-target-requirements $(requirements) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; $(project).mark-target-as-explicit $(target-xml) ; targets.main-target-alternative [ new install-target-class $(target:S=.xml) : $(project) : $(target-xml) : [ targets.main-target-requirements $(requirements) $(location-xml:E=.) $(target:S=.xml) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] ] ; $(project).mark-target-as-explicit $(target:S=.xml) ; targets.main-target-alternative [ new alias-target-class $(target) : $(project) : : [ targets.main-target-requirements $(requirements) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] : [ targets.main-target-usage-requirements $(usage-requirements) $(target:S=.xml) : $(project) ] ] ; } }