1 # Copyright 2003, 2004 Douglas Gregor
2 # Copyright 2003, 2004, 2005 Vladimir Prus
3 # Copyright 2006 Rene Rivera
4 # Distributed under the Boost Software License, Version 1.0.
5 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
7 # This module defines rules to handle generation of various outputs from source
8 # files documented with doxygen comments. The supported transformations are:
10 # * Source -> Doxygen XML -> BoostBook XML
11 # * Source -> Doxygen HTML
13 # The type of transformation is selected based on the target requested. For
14 # BoostBook XML, the default, specifying a target with an ".xml" suffix, or an
15 # empty suffix, will produce a <target>.xml and <target>.boostbook. For Doxygen
16 # HTML specifying a target with an ".html" suffix will produce a directory
17 # <target> with the Doxygen html files, and a <target>.html file redirecting to
20 import "class" : new ;
35 import toolset : flags ;
44 # Use to specify extra configuration paramters. These get translated
45 # into a doxyfile which configures the building of the docs.
46 feature.feature doxygen:param : : free ;
48 # Specify the "<xsl:param>boost.doxygen.header.prefix" XSLT option.
49 feature.feature prefix : : free ;
51 # Specify the "<xsl:param>boost.doxygen.reftitle" XSLT option.
52 feature.feature reftitle : : free ;
54 # Which processor to use for various translations from Doxygen.
55 feature.feature doxygen.processor : xsltproc doxproc : propagated implicit ;
57 # To generate, or not, index sections.
58 feature.feature doxygen.doxproc.index : no yes : propagated incidental ;
60 # The ID for the resulting BoostBook reference section.
61 feature.feature doxygen.doxproc.id : : free ;
63 # The title for the resulting BoostBook reference section.
64 feature.feature doxygen.doxproc.title : : free ;
66 # Location for images when generating XML
67 feature.feature doxygen:xml-imagedir : : free ;
69 # Indicates whether the entire directory should be deleted
70 feature.feature doxygen.rmdir : off on : optional incidental ;
72 # Doxygen configuration input file.
73 type.register DOXYFILE : doxyfile ;
75 # Doxygen XML multi-file output.
76 type.register DOXYGEN_XML_MULTIFILE : xml-dir : XML ;
78 # Doxygen XML coallesed output.
79 type.register DOXYGEN_XML : doxygen : XML ;
81 # Doxygen HTML multifile directory.
82 type.register DOXYGEN_HTML_MULTIFILE : html-dir : HTML ;
84 # Redirection HTML file to HTML multifile directory.
85 type.register DOXYGEN_HTML : : HTML ;
87 type.register DOXYGEN_XML_IMAGES : doxygen-xml-images ;
89 # Initialize the Doxygen module. Parameters are:
90 # name: the name of the 'doxygen' executable. If not specified, the name
91 # 'doxygen' will be used
99 .doxproc = [ modules.binding $(__name__) ] ;
100 .doxproc = $(.doxproc:D)/doxproc.py ;
102 generators.register-composing doxygen.headers-to-doxyfile
103 : H HPP CPP : DOXYFILE ;
104 generators.register-standard doxygen.run
105 : DOXYFILE : DOXYGEN_XML_MULTIFILE ;
106 generators.register-standard doxygen.xml-dir-to-boostbook
107 : DOXYGEN_XML_MULTIFILE : BOOSTBOOK : <doxygen.processor>doxproc ;
108 generators.register-standard doxygen.xml-to-boostbook
109 : DOXYGEN_XML : BOOSTBOOK : <doxygen.processor>xsltproc ;
110 generators.register-standard doxygen.collect
111 : DOXYGEN_XML_MULTIFILE : DOXYGEN_XML ;
112 generators.register-standard doxygen.run
113 : DOXYFILE : DOXYGEN_HTML_MULTIFILE ;
114 generators.register-standard doxygen.html-redirect
115 : DOXYGEN_HTML_MULTIFILE : DOXYGEN_HTML ;
116 generators.register-standard doxygen.copy-latex-pngs
117 : DOXYGEN_HTML : DOXYGEN_XML_IMAGES ;
119 IMPORT $(__name__) : doxygen : : doxygen ;
135 rule freeze-config ( )
139 errors.user-error "doxygen must be initialized before it can be used." ;
141 if ! $(.config-frozen)
143 .config-frozen = true ;
152 rule modify-config ( )
156 errors.user-error "Cannot change doxygen after it has been used." ;
160 rule check-doxygen ( )
162 if --debug-configuration in [ modules.peek : ARGV ]
164 ECHO "notice:" using doxygen ":" $(.doxygen) ;
169 local ProgramFiles = [ modules.peek : ProgramFiles ] ;
172 extra-paths = "$(ProgramFiles:J= )" ;
176 extra-paths = "C:\\Program Files" ;
179 .doxygen = [ common.get-invocation-command doxygen :
180 doxygen : $(.doxygen) : $(extra-paths) ] ;
193 local file = [ path.make [ modules.binding $(__name__) ] ] ;
194 local dir = [ path.native
195 [ path.join [ path.parent $(file) ] doxygen ] ] ;
197 "cd \"$(dir)\" && \"$(.doxygen)\" windows-paths-check.doxyfile 2>&1" ;
198 result = [ SHELL $(command) ] ;
199 if [ MATCH "(Parsing file /)" : $(result) ]
206 # Runs Doxygen on the given Doxygen configuration file (the source) to generate
207 # the Doxygen files. The output is dumped according to the settings in the
208 # Doxygen configuration file, not according to the target! Because of this, we
209 # essentially "touch" the target file, in effect making it look like we have
210 # really written something useful to it. Anyone that uses this action must deal
211 # with this behavior.
213 actions doxygen-action
215 $(RM) "$(*.XML)" & "$(NAME:E=doxygen)" "$(>)" && echo "Stamped" > "$(<)"
219 # Runs the Python doxproc XML processor.
223 python "$(DOXPROC)" "--xmldir=$(>)" "--output=$(<)" "$(OPTIONS)" "--id=$(ID)" "--title=$(TITLE)"
227 rule translate-path ( path )
232 if [ os.name ] = CYGWIN
247 match = [ MATCH ^(.):(.*) : $(path) ] ;
250 return /cygdrive/$(match[1])$(match[2]:T) ;
270 # Generates a doxygen configuration file (doxyfile) given a set of C++ sources
271 # and a property list that may contain <doxygen:param> features.
273 rule headers-to-doxyfile ( target : sources * : properties * )
275 local text "# Generated by Boost.Build version 2" ;
279 # Translate <doxygen:param> into command line flags.
280 for local param in [ feature.get-values <doxygen:param> : $(properties) ]
282 local namevalue = [ regex.match ([^=]*)=(.*) : $(param) ] ;
283 if $(namevalue[1]) = OUTPUT_DIRECTORY
285 output-dir = [ translate-path
286 [ utility.unquote $(namevalue[2]) ] ] ;
287 text += "OUTPUT_DIRECTORY = \"$(output-dir)\"" ;
291 text += "$(namevalue[1]) = $(namevalue[2])" ;
297 output-dir = [ translate-path [ on $(target) return $(LOCATE) ] ] ;
298 text += "OUTPUT_DIRECTORY = \"$(output-dir)\"" ;
302 for local header in $(sources:G=)
304 header = [ translate-path $(header) ] ;
305 headers += \"$(header)\" ;
308 # Doxygen generates LaTex by default. So disable it unconditionally, or at
309 # least until someone needs, and hence writes support for, LaTex output.
310 text += "GENERATE_LATEX = NO" ;
311 text += "INPUT = $(headers:J= )" ;
312 print.output $(target) plain ;
313 print.text $(text) : true ;
317 # Run Doxygen. See doxygen-action for a description of the strange properties of
320 rule run ( target : source : properties * )
323 if <doxygen.rmdir>on in $(properties)
327 [ MATCH <doxygen:param>OUTPUT_DIRECTORY=\"?([^\"]*) :
331 [ MATCH <doxygen:param>HTML_OUTPUT=(.*) :
333 if $(output-dir) && $(html-dir) &&
334 [ path.glob $(output-dir) : $(html-dir) ]
336 HTMLDIR on $(target) =
337 [ path.native [ path.join $(output-dir) $(html-dir) ] ] ;
338 rm-htmldir $(target) ;
341 doxygen-action $(target) : $(source) ;
342 NAME on $(target) = $(.doxygen) ;
343 RM on $(target) = [ modules.peek common : RM ] ;
347 [ path.make [ on $(target) return $(LOCATE) ] ]
354 RMDIR = rmdir /s /q ;
361 actions quietly rm-htmldir
366 # The rules below require Boost.Book stylesheets, so we need some code to check
367 # that the boostbook module has actualy been initialized.
369 rule check-boostbook ( )
371 if ! [ modules.peek boostbook : .initialized ]
373 ECHO "error: the boostbook module is not initialized" ;
374 ECHO "error: you've attempted to use the 'doxygen' toolset, " ;
375 ECHO "error: which requires Boost.Book," ;
376 ECHO "error: but never initialized Boost.Book." ;
377 EXIT "error: Hint: add 'using boostbook ;' to your user-config.jam" ;
382 # Collect the set of Doxygen XML files into a single XML source file that can be
383 # handled by an XSLT processor. The source is completely ignored (see
384 # doxygen-action), because this action picks up the Doxygen XML index file
385 # xml/index.xml. This is because we can not teach Doxygen to act like a NORMAL
386 # program and take a "-o output.xml" argument (grrrr). The target of the
387 # collection will be a single Doxygen XML file.
389 rule collect ( target : source : properties * )
392 local collect-xsl-dir
393 = [ path.native [ path.join [ boostbook.xsl-dir ] doxygen collect ] ] ;
395 = [ path.make [ on $(source) return $(LOCATE) ] ] ;
397 = [ path.root [ path.join $(source-path) $(source:B) ] [ path.pwd ] ] ;
399 = [ path.native $(collect-path) ] ;
401 = [ path.native [ path.join $(collect-path) index.xml ] ] ;
402 xsltproc.xslt $(target) : $(real-source) $(collect-xsl-dir:S=.xsl)
403 : <xsl:param>doxygen.xml.path=$(native-path) ;
407 # Translate Doxygen XML into BoostBook.
409 rule xml-to-boostbook ( target : source : properties * )
412 local xsl-dir = [ boostbook.xsl-dir ] ;
413 local d2b-xsl = [ path.native [ path.join [ boostbook.xsl-dir ] doxygen
414 doxygen2boostbook.xsl ] ] ;
416 local xslt-properties = $(properties) ;
417 for local prefix in [ feature.get-values <prefix> : $(properties) ]
419 xslt-properties += "<xsl:param>boost.doxygen.header.prefix=$(prefix)" ;
421 for local title in [ feature.get-values <reftitle> : $(properties) ]
423 xslt-properties += "<xsl:param>boost.doxygen.reftitle=$(title)" ;
426 xsltproc.xslt $(target) : $(source) $(d2b-xsl) : $(xslt-properties) ;
430 flags doxygen.xml-dir-to-boostbook OPTIONS <doxygen.doxproc.index>yes : --enable-index ;
431 flags doxygen.xml-dir-to-boostbook ID <doxygen.doxproc.id> ;
432 flags doxygen.xml-dir-to-boostbook TITLE <doxygen.doxproc.title> ;
435 rule xml-dir-to-boostbook ( target : source : properties * )
437 DOXPROC on $(target) = $(.doxproc) ;
439 LOCATE on $(source:S=) = [ on $(source) return $(LOCATE) ] ;
441 doxygen.doxproc $(target) : $(source:S=) ;
445 # Generate the HTML redirect to HTML dir index.html file.
447 rule html-redirect ( target : source : properties * )
449 local uri = "$(target:B)/index.html" ;
450 print.output $(target) plain ;
452 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
453 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
454 <html xmlns=\"http://www.w3.org/1999/xhtml\">
456 <meta http-equiv=\"refresh\" content=\"0; URL=$(uri)\" />
462 Automatic redirection failed, please go to <a href=
463 \"$(uri)\">$(uri)</a>.
470 rule copy-latex-pngs ( target : source : requirements * )
472 local directory = [ path.native
473 [ feature.get-values <doxygen:xml-imagedir> :
474 $(requirements) ] ] ;
476 local location = [ on $(target) return $(LOCATE) ] ;
481 [ path.make $(location) ]
482 [ path.make $(directory) ] ] ] ;
483 local html-location =
488 [ path.make $(directory) ] ] ] ;
490 common.MkDir $(pdf-location) ;
491 common.MkDir $(html-location) ;
493 DEPENDS $(target) : $(pdf-location) $(html-location) ;
497 CP on $(target) = copy /y ;
498 FROM on $(target) = \\*.png ;
499 TOHTML on $(target) = .\\html\\$(directory) ;
500 TOPDF on $(target) = \\$(directory) ;
504 CP on $(target) = cp ;
505 FROM on $(target) = /*.png ;
506 TOHTML on $(target) = ./html/$(directory) ;
507 TOPDF on $(target) = $(target:D)/$(directory) ;
511 actions copy-latex-pngs
513 $(CP) $(>:S=)$(FROM) $(TOHTML)
514 $(CP) $(>:S=)$(FROM) $(<:D)$(TOPDF)
515 echo "Stamped" > "$(<)"
518 # building latex images for doxygen XML depends
519 # on latex, dvips, and ps being in your PATH.
520 # This is true for most Unix installs, but
521 # not on Win32, where you will need to install
522 # MkTex and Ghostscript and add these tools
535 if [ os.name ] = "NT"
539 gswin32c -version >$(<)
552 if ! $(.check-tools-targets)
554 # Find the root project.
555 local root-project = [ project.current ] ;
556 root-project = [ $(root-project).project-module ] ;
558 [ project.attribute $(root-project) parent-module ] &&
559 [ project.attribute $(root-project) parent-module ] != user-config
562 [ project.attribute $(root-project) parent-module ] ;
565 .latex.check = [ new file-target latex.check
567 : [ project.target $(root-project) ]
568 : [ new action : doxygen.check-latex ]
571 .dvips.check = [ new file-target dvips.check
573 : [ project.target $(root-project) ]
574 : [ new action : doxygen.check-dvips ]
577 .gs.check = [ new file-target gs.check
579 : [ project.target $(root-project) ]
580 : [ new action : doxygen.check-gs ]
583 .check-tools-targets = $(.latex.check) $(.dvips.check) $(.gs.check) ;
585 return $(.check-tools-targets) ;
588 project.initialize $(__name__) ;
591 class doxygen-check-tools-target-class : basic-target
594 rule construct ( name : sources * : property-set )
596 return [ property-set.empty ] [ doxygen.check-tools ] ;
600 local project = [ project.current ] ;
602 targets.main-target-alternative
603 [ new doxygen-check-tools-target-class check-tools : $(project)
604 : [ targets.main-target-sources : check-tools : no-renaming ]
605 : [ targets.main-target-requirements : $(project) ]
606 : [ targets.main-target-default-build : $(project) ]
607 : [ targets.main-target-usage-requirements : $(project) ]
610 # User-level rule to generate BoostBook XML from a set of headers via Doxygen.
612 rule doxygen ( target : sources * : requirements * : default-build * : usage-requirements * )
615 local project = [ project.current ] ;
617 if $(target:S) = .html
619 # Build an HTML directory from the sources.
620 local html-location = [ feature.get-values <location> : $(requirements) ] ;
622 if [ $(project).get build-dir ]
624 # Explicitly specified build dir. Add html at the end.
625 output-dir = [ path.join [ $(project).build-dir ] $(html-location:E=html) ] ;
629 # Trim 'bin' from implicit build dir, for no other reason that backward
631 output-dir = [ path.join [ path.parent [ $(project).build-dir ] ]
632 $(html-location:E=html) ] ;
634 output-dir = [ path.root $(output-dir) [ path.pwd ] ] ;
635 local output-dir-native = [ path.native $(output-dir) ] ;
636 requirements = [ property.change $(requirements) : <location> ] ;
638 ## The doxygen configuration file.
639 targets.main-target-alternative
640 [ new typed-target $(target:S=.tag) : $(project) : DOXYFILE
641 : [ targets.main-target-sources $(sources) : $(target:S=.tag) ]
642 : [ targets.main-target-requirements $(requirements)
643 <doxygen:param>GENERATE_HTML=YES
644 <doxygen:param>GENERATE_XML=NO
645 <doxygen:param>"OUTPUT_DIRECTORY=\"$(output-dir-native)\""
646 <doxygen:param>HTML_OUTPUT=$(target:B)
648 : [ targets.main-target-default-build $(default-build) : $(project) ]
650 $(project).mark-target-as-explicit $(target:S=.tag) ;
652 ## The html directory to generate by running doxygen.
653 targets.main-target-alternative
654 [ new typed-target $(target:S=.dir) : $(project) : DOXYGEN_HTML_MULTIFILE
656 : [ targets.main-target-requirements $(requirements)
657 <doxygen:param>"OUTPUT_DIRECTORY=\"$(output-dir-native)\""
658 <doxygen:param>HTML_OUTPUT=$(target:B)
660 : [ targets.main-target-default-build $(default-build) : $(project) ]
662 $(project).mark-target-as-explicit $(target:S=.dir) ;
664 ## The redirect html file into the generated html.
665 targets.main-target-alternative
666 [ new typed-target $(target) : $(project) : DOXYGEN_HTML
668 : [ targets.main-target-requirements $(requirements)
669 <location>$(output-dir)
671 : [ targets.main-target-default-build $(default-build) : $(project) ]
676 # Build a BoostBook XML file from the sources.
677 local location-xml = [ feature.get-values <location> : $(requirements) ] ;
678 requirements = [ property.change $(requirements) : <location> ] ;
679 local target-xml = $(target:B=$(target:B)-xml) ;
681 # Check whether we need to build images
682 local images-location =
683 [ feature.get-values <doxygen:xml-imagedir> : $(requirements) ] ;
684 if $(images-location)
686 doxygen $(target).doxygen-xml-images.html : $(sources)
689 <doxygen:param>QUIET=YES
690 <doxygen:param>WARNINGS=NO
691 <doxygen:param>WARN_IF_UNDOCUMENTED=NO
692 <dependency>/doxygen//check-tools ;
693 $(project).mark-target-as-explicit
694 $(target).doxygen-xml-images.html ;
696 targets.main-target-alternative
697 [ new typed-target $(target).doxygen-xml-images
698 : $(project) : DOXYGEN_XML_IMAGES
699 : $(target).doxygen-xml-images.html
700 : [ targets.main-target-requirements $(requirements)
702 : [ targets.main-target-default-build $(default-build)
706 $(project).mark-target-as-explicit
707 $(target).doxygen-xml-images ;
709 if ! [ regex.match "^(.*/)$" : $(images-location) ]
711 images-location = $(images-location)/ ;
715 <dependency>$(target).doxygen-xml-images
716 <xsl:param>boost.doxygen.formuladir=$(images-location) ;
719 ## The doxygen configuration file.
720 targets.main-target-alternative
721 [ new typed-target $(target-xml:S=.tag) : $(project) : DOXYFILE
722 : [ targets.main-target-sources $(sources) : $(target-xml:S=.tag) ]
723 : [ targets.main-target-requirements $(requirements)
724 <doxygen:param>GENERATE_HTML=NO
725 <doxygen:param>GENERATE_XML=YES
726 <doxygen:param>XML_OUTPUT=$(target-xml)
728 : [ targets.main-target-default-build $(default-build) : $(project) ]
730 $(project).mark-target-as-explicit $(target-xml:S=.tag) ;
732 ## The Doxygen XML directory of the processed source files.
733 targets.main-target-alternative
734 [ new typed-target $(target-xml:S=.dir) : $(project) : DOXYGEN_XML_MULTIFILE
735 : $(target-xml:S=.tag)
736 : [ targets.main-target-requirements $(requirements)
738 : [ targets.main-target-default-build $(default-build) : $(project) ]
740 $(project).mark-target-as-explicit $(target-xml:S=.dir) ;
742 ## The resulting BoostBook file is generated by the processor tool. The
743 ## tool can be either the xsltproc plus accompanying XSL scripts. Or it
744 ## can be the python doxproc.py script.
745 targets.main-target-alternative
746 [ new typed-target $(target-xml) : $(project) : BOOSTBOOK
747 : $(target-xml:S=.dir)
748 : [ targets.main-target-requirements $(requirements)
750 : [ targets.main-target-default-build $(default-build) : $(project) ]
752 $(project).mark-target-as-explicit $(target-xml) ;
754 targets.main-target-alternative
755 [ new install-target-class $(target:S=.xml) : $(project)
757 : [ targets.main-target-requirements $(requirements)
758 <location>$(location-xml:E=.)
759 <name>$(target:S=.xml)
761 : [ targets.main-target-default-build $(default-build) : $(project) ]
763 $(project).mark-target-as-explicit $(target:S=.xml) ;
765 targets.main-target-alternative
766 [ new alias-target-class $(target) : $(project)
768 : [ targets.main-target-requirements $(requirements)
770 : [ targets.main-target-default-build $(default-build) : $(project) ]
771 : [ targets.main-target-usage-requirements $(usage-requirements)
772 <dependency>$(target:S=.xml)