diff --git a/doc/python/doxygen-boost.hh b/doc/python/doxygen-boost.hh new file mode 100644 index 0000000000000000000000000000000000000000..763b308be32b75ae15e829af05b01178564f5036 --- /dev/null +++ b/doc/python/doxygen-boost.hh @@ -0,0 +1,42 @@ +#ifndef DOXYGEN_BOOST_DOC_HH +#define DOXYGEN_BOOST_DOC_HH + +#ifndef DOXYGEN_DOC_HH +# error "You should have included doxygen.hh first." +#endif // DOXYGEN_DOC_HH + +#include <boost/python.hpp> + +namespace doxygen +{ + +namespace visitor +{ + +template <typename function_type> +struct member_func_impl : boost::python::def_visitor<member_func_impl<function_type> > +{ + member_func_impl(const char* n, function_type f) : name(n), function(f) {} + template <class classT> + inline void visit(classT& c) const + { + c.def(name, function, doxygen::member_func_doc(function)); + } + + const char* name; + function_type function; +}; + +// TODO surprisingly, this does not work when defined here but it works when +// defined after the generated files are included. +template <typename function_type> +inline member_func_impl<function_type> member_func (const char* name, function_type function) +{ + return member_func_impl<function_type>(name, function); +} + +} // namespace visitor + +} // namespace doxygen + +#endif // DOXYGEN_BOOST_DOC_HH diff --git a/doc/python/doxygen.hh b/doc/python/doxygen.hh new file mode 100644 index 0000000000000000000000000000000000000000..b8c533c8ac3ba31a65d22055ee6fdd771e28ed0a --- /dev/null +++ b/doc/python/doxygen.hh @@ -0,0 +1,97 @@ +#ifndef DOXYGEN_DOC_HH +#define DOXYGEN_DOC_HH + +#include <boost/preprocessor/repetition.hpp> +#include <boost/preprocessor/punctuation/comma_if.hpp> + +#ifndef DOXYGEN_DOC_MAX_NUMBER_OF_ARGUMENTS_IN_CONSTRUCTOR +#define DOXYGEN_DOC_MAX_NUMBER_OF_ARGUMENTS_IN_CONSTRUCTOR 10 +#endif + +namespace doxygen +{ +template <typename _class> +struct class_doc_impl +{ +static inline const char* run () +{ + return ""; +} +}; + +template <typename _class> +inline const char* class_doc () +{ + return class_doc_impl<_class>::run(); +} + +template <typename FuncPtr> +inline const char* member_func_doc (FuncPtr) +{ + return ""; +} + +#define DOXYGEN_DOC_DECLARE_CONSTRUCTOR(z,nargs,unused) \ +template < \ + typename Class \ + BOOST_PP_COMMA_IF(nargs) \ + BOOST_PP_ENUM_PARAMS(nargs, class Arg)> \ +struct constructor_doc_##nargs##_impl { \ +static inline const char* run () \ +{ \ + return ""; \ +} \ +}; \ + \ +template < \ + typename Class \ + BOOST_PP_COMMA_IF(nargs) \ + BOOST_PP_ENUM_PARAMS(nargs, class Arg)> \ +inline const char* constructor_doc () \ +{ \ + return constructor_doc_##nargs##_impl< \ + Class \ + BOOST_PP_COMMA_IF(nargs) \ + BOOST_PP_ENUM_PARAMS(nargs, Arg)>::run(); \ +} + +BOOST_PP_REPEAT(DOXYGEN_DOC_MAX_NUMBER_OF_ARGUMENTS_IN_CONSTRUCTOR, DOXYGEN_DOC_DECLARE_CONSTRUCTOR, ~) + +/* +template <typename Class> +inline const char* constructor_doc () +{ + return ""; +} +*/ + +template <typename Class> +struct destructor_doc_impl +{ +static inline const char* run () +{ + return ""; +} +}; + +template <typename Class> +inline const char* destructor_doc () +{ + return destructor_doc_impl<Class>::run(); +} + +/* TODO class attribute can be handled by + +template <typename Class, typename AttributeType> +const char* attribute_doc (AttributeType Class::* ptr) +{ + // Body looks like + // if (ptr == &Class::attributeName) + // return "attrib documentation"; + return "undocumented"; +} +*/ + +} // namespace doxygen + +#endif // DOXYGEN_DOC_HH diff --git a/doc/python/doxygen_xml_parser.py b/doc/python/doxygen_xml_parser.py new file mode 100755 index 0000000000000000000000000000000000000000..09fab28d0eca8cef251911232fc7e75012028bb5 --- /dev/null +++ b/doc/python/doxygen_xml_parser.py @@ -0,0 +1,609 @@ +#!/usr/bin/python3 + +from __future__ import print_function +from lxml import etree +from os import path +from xml_docstring import XmlDocString +import sys + +template_file_header = \ +"""#ifndef DOXYGEN_AUTODOC_{header_guard} +#define DOXYGEN_AUTODOC_{header_guard} + +#include "{path}/doxygen.hh" +""" +template_file_footer = \ +""" +#endif // DOXYGEN_AUTODOC_{header_guard} +""" + +template_class_doc = \ +""" +template <{tplargs}> +struct class_doc_impl< {classname} > +{{ +static inline const char* run () +{{ + return "{docstring}"; +}} +}};""" +template_constructor_doc = \ +""" +template <{tplargs}> +struct constructor_doc_{nargs}_impl< {classname_prefix}{comma}{argsstring} > +{{ +static inline const char* run () +{{ + return "{docstring}"; +}} +}};""" +template_destructor_doc = \ +""" +template <{tplargs}> +struct destructor_doc_impl < {classname_prefix} > +{{ +static inline const char* run () +{{ + return "{docstring}"; +}} +}};""" +template_member_func_doc = \ +""" +{template}inline const char* member_func_doc ({rettype} ({classname_prefix}*function_ptr) {argsstring}) +{{{body} + return ""; +}}""" +template_member_func_doc_body = \ +""" + if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername})) + return "{docstring}";""" +template_static_func_doc = \ +""" +{template}inline const char* member_func_doc ({rettype} (*function_ptr) {argsstring}) +{{{body} + return ""; +}}""" +template_static_func_doc_body = \ +""" + if (function_ptr == static_cast<{rettype} (*) {argsstring}>(&{namespace}::{membername})) + return "{docstring}";""" +template_open_namespace = \ +"""namespace {namespace} {{""" +template_close_namespace = \ +"""}} // namespace {namespace}""" +template_include_intern = \ +"""#include "{filename}" +""" +template_include_extern = \ +"""#include <{filename}> +""" + +def _templateParamToDict (param): + type = param.find('type') + declname = param.find('declname') + defname = param.find('defname') + # FIXME type may contain references in two ways: + # - the real param type + # - the name of the template argument is recognized as the name of a type... + if defname is None and declname is None: + typetext = type.text + for c in type.iter(): + if c == type: continue + if c.text is not None: typetext += c.text + if c.tail is not None: typetext += c.tail + if typetext.startswith ("typename") or typetext.startswith ("class"): + s = typetext.split(maxsplit=1) + assert len(s) == 2 + return { "type": s[0].strip(), "name": s[1].strip() } + else: + return { "type": type.text, "name": "" } + else: + assert defname.text == declname.text + return { "type": type.text, "name": defname.text } + +def makeHeaderGuard (filename): + import os + return filename.upper().replace('.', '_').replace(os.path.sep, '_') + +def format_description (brief, detailed): + b = [ el.text.strip() for el in brief .iter() if el.text ] if brief is not None else [] + d = [ el.text.strip() for el in detailed.iter() if el.text ] if detailed is not None else [] + text = "".join(b) + if d: + text += '\n' + "".join(d) + return text + +class Reference(object): + def __init__ (self, index, id=None, name=None): + self.id = id + self.name = name + self.index = index + + def xmlToType (self, node, array=None, parentClass=None, tplargs=None): + """ + - node: + - parentClass: a class + - tplargs: if one of the args is parentClass and no template arguments are provided, + set the template arguments to this value + - array: content of the sibling tag 'array' + """ + if node.text is not None: + t = node.text.strip() + else: + t = "" + for c in node.iterchildren(): + if c.tag == "ref": + refid = c.attrib["refid"] + if parentClass is not None and refid == parentClass.id: + t += " " + parentClass.name + if c.tail is not None and c.tail.lstrip()[0] != '<': + t += tplargs + elif self.index.hasref(refid): + t += " " + self.index.getref(refid).name + else: + self.index.output.warn ("Unknown reference: ", c.text, refid) + t += " " + c.text.strip() + else: + if c.text is not None: + t += " " + c.text.strip() + if c.tail is not None: + t += " " + c.tail.strip() + if array is not None: + t += array.text + return t + +# Only for function as of now. +class MemberDef(Reference): + def __init__ (self, index, memberdefxml, parent): + super().__init__ (index=index, + id = memberdefxml.attrib["id"], + name = memberdefxml.find("definition").text) + self.parent = parent + + self.xml = memberdefxml + self.const = (memberdefxml.attrib['const']=="yes") + self.static = (memberdefxml.attrib['static']=="yes") + self.rettype = memberdefxml.find('type') + self.params = tuple( [ (param.find('type'), param.find('array')) for param in self.xml.findall("param") ] ) + self.special = self.rettype.text is None and len(self.rettype.getchildren())==0 + #assert self.special or len(self.rettype.text) > 0 + + self._templateParams (self.xml.find('templateparamlist')) + + def _templateParams (self, tpl): + if tpl is not None: + self.template_params = tuple ([ _templateParamToDict(param) for param in tpl.iterchildren(tag="param") ]) + else: + self.template_params = tuple() + + def prototypekey (self): + prototype = ( + self.xmlToType(self.rettype), + tuple( [ tuple(t.items()) for t in self.template_params ]), + tuple( [ self.xmlToType(param.find('type')) for param in self.xml.findall("param") ] ), + self.const, + ) + return prototype + + def s_prototypeArgs (self): + return "({0}){1}".format (self.s_args(), " const" if self.const else "") + + def s_args (self): + # If the class is templated, check if one of the argument is the class itself. + # If so, we must add the template arguments to the class (if there is none) + + if len(self.parent.template_params) > 0: + tplargs = " <" + ", ".join([ d['name'] for d in self.parent.template_params ]) + " > " + args = ", ".join( + [ self.xmlToType(type, array, parentClass=self.parent, tplargs=tplargs) for type,array in self.params]) + else: + args = ", ".join([ self.xmlToType(type, array) for type, array in self.params]) + return args + + def s_tpldecl (self): + if len(self.template_params) == 0: return "" + return ", ".join([ d['type'] + " " + d['name'] for d in self.template_params ]) + + def s_rettype (self): + assert not self.special + return self.xmlToType(self.rettype) + + def s_name (self): + return self.xml.find('name').text.strip() + + def s_docstring (self): + return self.index.xml_docstring.getDocString ( + self.xml.find('briefdescription'), + self.xml.find('detaileddescription'), + self.index.output) + + def include (self): + import os.path + loc = self.xml.find('location') + # The location is based on $CMAKE_SOURCE_DIR. Remove first directory. + return loc.attrib['file'].split(os.path.sep,1)[1] + +class CompoundBase(Reference): + def __init__ (self, compound, index): + self.compound = compound + self.filename = path.join (index.directory, compound.attrib["refid"]+".xml") + self.tree = etree.parse (self.filename) + self.definition = self.tree.getroot().find("compounddef") + super().__init__ (index, + id = self.definition.attrib['id'], + name = self.definition.find("compoundname").text) + +class NamespaceCompound (CompoundBase): + def __init__ (self, *args): + super().__init__ (*args) + self.typedefs = [] + self.enums = [] + self.static_funcs = [] + self.template_params = tuple() + + # Add references + for section in self.definition.iterchildren("sectiondef"): + assert "kind" in section.attrib + kind = section.attrib["kind"] + if kind == "enum": + self.parseEnumSection (section) + elif kind == "typedef": + self.parseTypedefSection (section) + elif kind == "func": + self.parseFuncSection (section) + + def parseEnumSection (self, section): + for member in section.iterchildren("memberdef"): + ref = Reference (index=self.index, + id=member.attrib["id"], + name= self.name + "::" + member.find("name").text) + self.index.registerReference (ref) + self.enums.append(member) + for value in member.iterchildren("enumvalue"): + ref = Reference (index=self.index, + id=value.attrib["id"], + name= self.name + "::" + member.find("name").text) + + def parseTypedefSection (self, section): + for member in section.iterchildren("memberdef"): + ref = Reference (index=self.index, + id=member.attrib["id"], + name= self.name + "::" + member.find("name").text) + self.index.registerReference (ref) + self.typedefs.append(member) + + def parseFuncSection (self, section): + for member in section.iterchildren("memberdef"): + self.static_funcs.append (MemberDef (self.index, member, self)) + + def innerNamespace (self): + return self.name + + def write (self, output): + pass + +class ClassCompound (CompoundBase): + def __init__ (self, *args): + super().__init__ (*args) + self.member_funcs = list() + self.static_funcs = list() + self.special_funcs = list() + self.attributes = list() + + self.struct = (self.compound.attrib['kind'] == "struct") + self.public = (self.definition.attrib['prot'] == "public") + self.template_specialization = (self.name.find('<') > 0) + + # Handle templates + self._templateParams (self.definition.find('templateparamlist')) + for memberdef in self.definition.iter(tag="memberdef"): + if memberdef.attrib['prot'] != "public": + continue + if memberdef.attrib['kind'] == "variable": + self._attribute (memberdef) + elif memberdef.attrib['kind'] == "typedef": + ref = Reference (index=self.index, + id=memberdef.attrib["id"], + name= self.name + "::" + memberdef.find("name").text) + self.index.registerReference (ref) + elif memberdef.attrib['kind'] == "enum": + ref = Reference (index=self.index, + id=memberdef.attrib["id"], + name= self.name + "::" + memberdef.find("name").text) + self.index.registerReference (ref) + for value in memberdef.iterchildren("enumvalue"): + ref = Reference (index=self.index, + id=value.attrib["id"], + name= self.name + "::" + memberdef.find("name").text) + self.index.registerReference (ref) + elif memberdef.attrib['kind'] == "function": + self._memberfunc (memberdef) + + def _templateParams (self, tpl): + if tpl is not None: + self.template_params = tuple([ _templateParamToDict(param) for param in tpl.iterchildren(tag="param") ]) + else: + self.template_params = tuple() + + def _templateDecl (self): + if not hasattr(self, "template_params") or len(self.template_params) == 0: + return "" + return ", ".join([ d['type'] + " " + d['name'] for d in self.template_params ]) + + def _className (self): + if not hasattr(self, "template_params") or len(self.template_params) == 0: + return self.name + return self.name + " <" + ", ".join([ d['name'] for d in self.template_params ]) + " >" + + def innerNamespace (self): + return self._className() + + def _memberfunc (self, member): + m = MemberDef (self.index, member, self) + if m.special: + self.special_funcs.append (m) + elif m.static: + self.static_funcs.append (m) + else: + self.member_funcs.append (m) + + def _writeClassDoc (self, output): + docstring = self.index.xml_docstring.getDocString ( + self.definition.find('briefdescription'), + self.definition.find('detaileddescription'), + self.index.output) + if len(docstring) == 0: return + output.out (template_class_doc.format ( + tplargs = self._templateDecl(), + classname = self._className(), + docstring = docstring, + )) + + def write (self, output): + if not self.public: return + if self.template_specialization: + output.warn ("Disable class {} because template argument are not resolved for templated class specialization.".format(self.name)) + return + + include = self.definition.find('includes') + output.open (include.text) + output.out (template_include_extern.format (filename=include.text)) + output.out (template_open_namespace.format (namespace="doxygen")) + + # Write class doc + self._writeClassDoc(output) + + # Group member function by prototype + member_funcs = dict() + for m in self.member_funcs: + prototype = m.prototypekey() + if prototype in member_funcs: + member_funcs[prototype].append (m) + else: + member_funcs[prototype] = [ m, ] + + classname_prefix = self._className() + "::" + + for member in self.special_funcs: + docstring = member.s_docstring() + if len(docstring) == 0: continue + if member.s_name()[0] == '~': + output.out (template_destructor_doc.format ( + tplargs = self._templateDecl(), + classname_prefix = self._className(), + docstring = docstring, + )) + else: + output.out (template_constructor_doc.format ( + tplargs = ", ".join([ d['type'] + " " + d['name'] for d in self.template_params + member.template_params ]), + nargs = len(member.params), + comma = ", " if len(member.params) > 0 else "", + classname_prefix = self._className(), + argsstring = member.s_args(), + docstring = docstring, + )) + + for prototype, members in member_funcs.items(): + # remove undocumented members + documented_members = [] + docstrings = [] + for member in members: + docstring = member.s_docstring() + if len(docstring) == 0: continue + documented_members.append (member) + docstrings.append (docstring) + if len(documented_members) == 0: continue + + body = "".join([ + template_member_func_doc_body.format ( + classname_prefix = classname_prefix, + membername = member.s_name(), + docstring = docstring, + rettype = member.s_rettype(), + argsstring = member.s_prototypeArgs(), + ) + for member, docstring in zip(documented_members,docstrings) ]) + + member = members[0] + tplargs = ", ".join([ d['type'] + " " + d['name'] for d in self.template_params + member.template_params ]) + output.out (template_member_func_doc.format ( + template = "template <{}>\n".format (tplargs) if len(tplargs) > 0 else "", + rettype = member.s_rettype(), + classname_prefix = classname_prefix, + argsstring = member.s_prototypeArgs(), + body = body + )) + + output.out (template_close_namespace.format (namespace="doxygen")) + output.close() + + def _attribute (self, member): + self.attributes.append (member) + +class Index: + """ + This class is responsible for generating the list of all C++-usable documented elements. + """ + def __init__ (self, input, output): + self.tree = etree.parse (input) + self.directory = path.dirname (input) + self.xml_docstring = XmlDocString (self) + self.compounds = list() + self.references = dict() + self.output = output + + def parseCompound (self): + for compound in self.tree.getroot().iterchildren ("compound"): + if compound.attrib['kind'] in ["class", "struct"]: + obj = ClassCompound (compound, self) + elif compound.attrib['kind'] == "namespace": + obj = NamespaceCompound (compound, self) + if obj.id not in self.compounds: + self.compounds.append (obj.id) + self.registerReference (obj) + + def write (self): + # Header + from os.path import abspath, dirname + from time import asctime + + self.output.open ("doxygen_xml_parser_for_cmake.hh") + self.output.out ("// Generated on {}".format (asctime())) + self.output.close() + + # Implement template specialization for classes and member functions + for id in self.compounds: + compound = self.references[id] + compound.write(self.output) + + self.output.open ("functions.h") + + # Implement template specialization for static functions + static_funcs = dict() + prototypes = list() + includes = list() + for id in self.compounds: + compound = self.references[id] + for m in compound.static_funcs: + include = m.include() + if include not in includes: + includes.append (include) + docstring = m.s_docstring() + if len(docstring) == 0: continue + prototype = m.prototypekey() + if prototype in static_funcs: + static_funcs[prototype].append ( (m, docstring) ) + else: + static_funcs[prototype] = [ (m, docstring) , ] + prototypes.append (prototype) + + self.output.out ( + "".join([ template_include_intern.format (filename=filename) + for filename in includes])) + + self.output.out (template_open_namespace.format (namespace="doxygen")) + + for prototype in prototypes: + member_and_docstring_s = static_funcs[prototype] + body = "".join([ + template_static_func_doc_body.format ( + namespace = member.parent.innerNamespace(), + membername = member.s_name(), + docstring = docstring, + rettype = member.s_rettype(), + argsstring = member.s_prototypeArgs(), + ) + for member, docstring in member_and_docstring_s ]) + + member = member_and_docstring_s[0][0] + # TODO fix case of static method in templated class. + tplargs = ", ".join([ d['type'] + " " + d['name'] for d in member.parent.template_params + member.template_params ]) + self.output.out (template_static_func_doc.format ( + template = "template <{}>\n".format (tplargs) if len(tplargs) > 0 else "", + rettype = member.s_rettype(), + argsstring = member.s_prototypeArgs(), + body = body + )) + + self.output.out (template_close_namespace.format (namespace="doxygen")) + self.output.close () + + def registerReference (self, obj, overwrite=True): + if obj.id in self.references: + if obj.name != self.references[obj.id].name: + self.output.warn ("!!!! Compounds " + obj.id + " already exists.", obj.name, self.references[obj.id].name) + else: + self.output.warn ("Reference " + obj.id + " already exists.", obj.name) + if not overwrite: return + self.references[obj.id] = obj + + def hasref (self, id): + return (id in self.references) + + def getref (self, id): + return self.references[id] + +class OutputStreams(object): + def __init__ (self, output_dir, warn, error, errorPrefix = ""): + self.output_dir = output_dir + self._out = None + self._warn = warn + self._err = error + self.errorPrefix = errorPrefix + + self._created_files = dict() + + def open (self, name): + assert self._out == None, "You did not close the previous file" + import os + fullname = os.path.join(self.output_dir, name) + dirname = os.path.dirname(fullname) + if not os.path.isdir (dirname): os.makedirs (dirname) + + if name in self._created_files: + self._out = self._created_files[name] + else: + self._out = open(fullname, mode='w') + self._created_files[name] = self._out + + # Header + self.out(template_file_header.format ( + path = os.path.dirname(os.path.abspath(__file__)), + header_guard = makeHeaderGuard (name), + )) + + def close (self): + self._out = None + + def writeFooterAndCloseFiles (self): + for n, f in self._created_files.items(): + # Footer + self._out = f + self.out(template_file_footer.format( + header_guard = makeHeaderGuard (n), + )) + f.close() + self._created_files.clear() + self._out = None + + def out(self, *args): + print (*args, file=self._out) + def warn(self, *args): + print (self.errorPrefix, *args, file=self._warn) + def err(self, *args): + print (self.errorPrefix, *args, file=self._err) + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description='Process Doxygen XML documentation and generate C++ code.') + parser.add_argument('doxygen_index_xml', type=str, help='the Doxygen XML index.') + parser.add_argument('output_directory', type=str, help='the output directory.') + args = parser.parse_args() + + index = Index (input = sys.argv[1], + output = OutputStreams (args.output_directory, sys.stdout, sys.stderr)) + index.parseCompound() + index.write() + index.output.writeFooterAndCloseFiles() + assert index.output._out == None diff --git a/doc/python/xml_docstring.py b/doc/python/xml_docstring.py new file mode 100644 index 0000000000000000000000000000000000000000..2ff48dff1ff5c3bb2b7095d3348340b9d423fa14 --- /dev/null +++ b/doc/python/xml_docstring.py @@ -0,0 +1,131 @@ +class XmlDocString (object): + def __init__ (self, index): + self.index = index + self.tags = { + "para": self.para, + "ref": self.ref, + "briefdescription": self.otherTags, + "detaileddescription": self.otherTags, + "parameterlist": self.parameterlist, + "parameterdescription": self.otherTags, + "emphasis": self.emphasis, + "simplesect": self.simplesect, + } + self.unkwownTags = set() + self.unkwownReferences = dict() + self._linesep = "\\n\"\n\"" + + def clear (self): + self.lines = [] + self.unkwownTags.clear() + self.unkwownReferences.clear() + + def writeErrors (self, output): + ret = False + for t in self.unkwownTags: + output.warn ("Unknown tag: ", t) + ret = True + for ref,node in self.unkwownReferences.items(): + output.warn ("Unknown reference: ", ref, node.text) + ret = True + return ret + + def _write (self, str): + nlines=str.split(sep="\n") + if len(self.lines)==0: + self.lines += nlines + else: + self.lines[-1] += nlines[0] + self.lines += nlines[1:] + #self.lines += nlines[1:] + + def _newline (self,n=1): + self.lines.extend (["",] * n) + + def _clean(self): + s = 0 + for l in self.lines: + if len(l.strip())==0: s+=1 + else: break + e = len(self.lines) + for l in reversed(self.lines): + if len(l.strip())==0: e-=1 + else: break + self.lines = self.lines[s:e] + + def getDocString (self, brief, detailled, output): + self.clear() + if brief is not None: + self.visit (brief) + if detailled is not None and len(detailled.getchildren()) > 0: + if brief is not None: self._newline () + self.visit (detailled) + from sys import stdout, stderr + self.writeErrors(output) + self._clean() + return self._linesep.join(self.lines) + + def visit (self, node): + assert isinstance(node.tag, str) + tag = node.tag + if tag not in self.tags: + self.unknownTag (node) + else: + self.tags[tag](node) + + def unknownTag (self, node): + self.unkwownTags.add (node.tag) + self.otherTags (node) + + def otherTags (self, node): + if node.text: + self._write (node.text.strip()) + for c in node.iterchildren(): + self.visit (c) + if c.tail: self._write (c.tail.strip()) + + def emphasis (self, node): + self._write ("*") + self.otherTags(node) + self._write ("*") + + def simplesect (self, node): + self._write (node.attrib["kind"].title()+": ") + self.otherTags (node) + + def para (self, node): + if node.text: self._write (node.text) + for c in node.iterchildren(): + self.visit (c) + if c.tail: self._write (c.tail) + self._newline() + + def ref (self, node): + refid = node.attrib["refid"] + if self.index.hasref(refid): + self._write (self.index.getref(refid).name) + else: + self.unkwownReferences[refid] = node + self._write (node.text) + assert len(node.getchildren()) == 0 + + def parameterlist (self, node): + self._newline() + self._write (node.attrib["kind"].title()) + self._newline() + for item in node.iterchildren("parameteritem"): + self.parameteritem (item) + + def parameteritem (self, node): + indent = " " + self._write (indent + "- ") + # should contain two children + assert len(node.getchildren()) == 2 + namelist = node.find ("parameternamelist") + desc = node.find ("parameterdescription") + sep = "" + for name in namelist.iterchildren("parametername"): + self._write (sep + name.text) + sep = ", " + self._write (" ") + self.visit (desc) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 00e57c43a6644eeb9fe19ae0625bae83135805cc..ec2bb845c6f0c8b4f9543d5fe9edea2b280acd66 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -44,7 +44,7 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src") INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}") ADD_CUSTOM_TARGET(generate_doxygen_cpp_doc - COMMAND ${CMAKE_SOURCE_DIR}/cmake/doxygen/doxygen_xml_parser.py + COMMAND ${CMAKE_SOURCE_DIR}/doc/python/doxygen_xml_parser.py ${CMAKE_BINARY_DIR}/doc/doxygen-xml/index.xml ${CMAKE_CURRENT_BINARY_DIR}/doxygen_autodoc > ${CMAKE_CURRENT_BINARY_DIR}/doxygen_autodoc.log BYPRODUCTS @@ -57,7 +57,7 @@ ADD_DEPENDENCIES(generate_doxygen_cpp_doc doc) SET(${LIBRARY_NAME}_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/doxygen_autodoc/doxygen_xml_parser_for_cmake.hh fcl.hh - ) + ) SET(${LIBRARY_NAME}_SOURCES version.cc diff --git a/python/math.cc b/python/math.cc index 8c372e6d19011b33b5a4ca5c7ff8fade29a0204d..c5d0a18ed4cae8d96b6abb125be534b3661b163f 100644 --- a/python/math.cc +++ b/python/math.cc @@ -44,7 +44,7 @@ #include "doxygen_autodoc/hpp/fcl/math/transform.h" -#include "../cmake/doxygen/doxygen-boost.hh" +#include "../doc/python/doxygen-boost.hh" using namespace boost::python; using namespace hpp::fcl;