From 6d5cf0e6424b2e9e428f211b15cafc491500abca Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 28 Aug 2008 02:57:12 +0200 Subject: [PATCH] scons: use Doxygen builder (lib implementation from http://www.scons.org/wiki/DoxygenBuilder) --- SConstruct | 15 +-- admin/scons/BuilderDoxygen.py | 230 ++++++++++++++++++++++++++++++++++ admin/scons/BuilderGCH.py | 3 +- doc/devel/.gitignore | 1 + doc/devel/Doxyfile | 10 +- 5 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 admin/scons/BuilderDoxygen.py diff --git a/SConstruct b/SConstruct index 93c3e39fd..d0a143db5 100644 --- a/SConstruct +++ b/SConstruct @@ -61,7 +61,7 @@ def setupBasicEnvironment(): opts = defineCmdlineOptions() env = LumieraEnvironment(options=opts ,toolpath = [TOOLDIR] - ,tools = ["default", "BuilderGCH"] + ,tools = ["default", "BuilderGCH", "BuilderDoxygen"] ) env.Append ( CCCOM=' -std=gnu99') # workaround for a bug: CCCOM currently doesn't honor CFLAGS, only CCFLAGS @@ -340,16 +340,9 @@ def definePostBuildTargets(env, artifacts): env.Clean ('build', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log' ]) env.Clean ('build', [ '$SRCDIR/pre.gch' ]) - # Doxygen documentation - # Note: at the moment we only depend on Doxyfile - # obviousely, we should depend on all sourcefiles - # real Doxygen builder for scons is under developement for 0.97 - # so for the moment I prefere not to bother - doxyfile = File('doc/devel/Doxyfile') - env.NoClean(doxyfile) - doxydoc = artifacts['doxydoc'] = [ Dir('doc/devel/html'), Dir('doc/devel/latex') ] - env.Command(doxydoc, doxyfile, "doxygen Doxyfile 2>&1 |tee ,doxylog", chdir='doc/devel') - env.Clean ('doc/devel', doxydoc + ['doc/devel/,doxylog']) + doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile') + env.Alias ('doxydoc', doxydoc) + env.Clean ('doxydoc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt']) def defineInstallTargets(env, artifacts): diff --git a/admin/scons/BuilderDoxygen.py b/admin/scons/BuilderDoxygen.py new file mode 100644 index 000000000..943fce946 --- /dev/null +++ b/admin/scons/BuilderDoxygen.py @@ -0,0 +1,230 @@ +# -*- python -*- +## +## BuilderDoxygen.py - SCons builder for generating Doxygen documentation +## + +# +# Astxx, the Asterisk C++ API and Utility Library. +# Copyright (C) 2005, 2006 Matthew A. Nicholson +# Copyright (C) 2006 Tim Blechmann +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1 as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see http://www.gnu.org/licenses/ +##################################################################### + +# history: 8/2008 adapted for Lumiera build system +# added patch for Doxyfile in subdirectory +# see http://www.scons.org/wiki/DoxygenBuilder + + +import os +import os.path +import glob +from fnmatch import fnmatch + + +def DoxyfileParse(file_contents): + """ + Parse a Doxygen source file and return a dictionary of all the values. + Values will be strings and lists of strings. + """ + data = {} + + import shlex + lex = shlex.shlex(instream = file_contents, posix = True) + lex.wordchars += "*+./-:" + lex.whitespace = lex.whitespace.replace("\n", "") + lex.escape = "" + + lineno = lex.lineno + token = lex.get_token() + key = token # the first token should be a key + last_token = "" + key_token = False + next_key = False + new_data = True + + def append_data(data, key, new_data, token): + if new_data or len(data[key]) == 0: + data[key].append(token) + else: + data[key][-1] += token + + while token: + if token in ['\n']: + if last_token not in ['\\']: + key_token = True + elif token in ['\\']: + pass + elif key_token: + key = token + key_token = False + else: + if token == "+=": + if not data.has_key(key): + data[key] = list() + elif token == "=": + data[key] = list() + else: + append_data( data, key, new_data, token ) + new_data = True + + last_token = token + token = lex.get_token() + + if last_token == '\\' and token != '\n': + new_data = False + append_data( data, key, new_data, '\\' ) + + # compress lists of len 1 into single strings + for (k, v) in data.items(): + if len(v) == 0: + data.pop(k) + + # items in the following list will be kept as lists and not converted to strings + if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS"]: + continue + + if len(v) == 1: + data[k] = v[0] + + return data + +def DoxySourceScan(node, env, path): + """ + Doxygen Doxyfile source scanner. This should scan the Doxygen file and add + any files used to generate docs to the list of source files. + """ + default_file_patterns = [ + '*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx', + '*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++', + '*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm', + '*.py', + ] + + default_exclude_patterns = [ + '*~', + ] + + sources = [] + + data = DoxyfileParse(node.get_contents()) + + if data.get("RECURSIVE", "NO") == "YES": + recursive = True + else: + recursive = False + + file_patterns = data.get("FILE_PATTERNS", default_file_patterns) + exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns) + + # + # We're running in the top-level directory, but the doxygen + # configuration file is in the same directory as node; this means + # that relative pathnames in node must be adjusted before they can + # go onto the sources list + conf_dir = os.path.dirname(str(node)) + + for node in data.get("INPUT", []): + if not os.path.isabs(node): + node = os.path.join(conf_dir, node) + if os.path.isfile(node): + sources.append(node) + elif os.path.isdir(node): + if recursive: + for root, dirs, files in os.walk(node): + for f in files: + filename = os.path.join(root, f) + + pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False) + exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True) + + if pattern_check and not exclude_check: + sources.append(filename) + else: + for pattern in file_patterns: + sources.extend(glob.glob("/".join([node, pattern]))) + + sources = map( lambda path: env.File(path), sources ) + return sources + + +def DoxySourceScanCheck(node, env): + """Check if we should scan this file""" + return os.path.isfile(node.path) + +def DoxyEmitter(source, target, env): + """Doxygen Doxyfile emitter""" + # possible output formats and their default values and output locations + output_formats = { + "HTML": ("YES", "html"), + "LATEX": ("YES", "latex"), + "RTF": ("NO", "rtf"), + "MAN": ("NO", "man"), + "XML": ("NO", "xml"), + } + + data = DoxyfileParse(source[0].get_contents()) + + targets = [] + out_dir = data.get("OUTPUT_DIRECTORY", ".") + + # add our output locations + for (k, v) in output_formats.items(): + if data.get("GENERATE_" + k, v[0]) == "YES": + targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) ) + + # don't clobber targets + for node in targets: + env.Precious(node) + + # set up cleaning stuff + for node in targets: + env.Clean(node, node) + + return (targets, source) + + +def generate(env): + """ + Add builders and construction variables for the + Doxygen tool. This is currently for Doxygen 1.4.6. + """ + doxyfile_scanner = env.Scanner( + DoxySourceScan, + "DoxySourceScan", + scan_check = DoxySourceScanCheck, + ) + + import SCons.Builder + doxyfile_builder = SCons.Builder.Builder( + action = "cd ${SOURCE.dir} && (${DOXYGEN} ${SOURCE.file} 2>&1 |tee ,doxylog)", + emitter = DoxyEmitter, + target_factory = env.fs.Entry, + single_source = True, + source_scanner = doxyfile_scanner, + ) + + env.Append(BUILDERS = { + 'Doxygen': doxyfile_builder, + }) + + env.AppendUnique( + DOXYGEN = 'doxygen', + ) + +def exists(env): + """ + Make sure doxygen exists. + """ + return env.Detect("doxygen") + diff --git a/admin/scons/BuilderGCH.py b/admin/scons/BuilderGCH.py index a8e0eb95c..c522cb9cd 100644 --- a/admin/scons/BuilderGCH.py +++ b/admin/scons/BuilderGCH.py @@ -18,8 +18,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# along with this program; if not, see http://www.gnu.org/licenses/ ##################################################################### # history: 8/2008 adapted for Lumiera build system diff --git a/doc/devel/.gitignore b/doc/devel/.gitignore index 96886436c..d6d649abd 100644 --- a/doc/devel/.gitignore +++ b/doc/devel/.gitignore @@ -1,2 +1,3 @@ ,doxylog +warnings.txt html/* diff --git a/doc/devel/Doxyfile b/doc/devel/Doxyfile index 28bab1f05..b7c59fa54 100644 --- a/doc/devel/Doxyfile +++ b/doc/devel/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Lumiera -PROJECT_NUMBER = 3.0+alpha +PROJECT_NUMBER = 0.1+pre OUTPUT_DIRECTORY = CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English @@ -32,7 +32,7 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = NO +DETAILS_AT_TOP = YES INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 @@ -65,8 +65,8 @@ CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -SORT_BRIEF_DOCS = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES @@ -179,7 +179,7 @@ HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDNAME = "Lumiera Doxygen docs" DOCSET_BUNDLE_ID = org.doxygen.Project HTML_DYNAMIC_SECTIONS = NO CHM_FILE =