From: abn Date: Tue, 30 Jun 2015 13:35:56 +0000 (+0200) Subject: IMP: generation of Python docstrings from Doxygen output. X-Git-Tag: V7_7_0a1~9^2 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=32cb713ab84874d6b05e773d0ff431880cd6b144;p=tools%2Fmedcoupling.git IMP: generation of Python docstrings from Doxygen output. For now only a few classes from MEDLoader and MEDCoupling are included. --- diff --git a/doc/doxygen/CMakeLists.txt b/doc/doxygen/CMakeLists.txt index 558964b94..99392afa3 100644 --- a/doc/doxygen/CMakeLists.txt +++ b/doc/doxygen/CMakeLists.txt @@ -22,6 +22,8 @@ SALOME_CONFIGURE_FILE(static/header.html.in static/header.html) IF(SALOME_MED_ENABLE_PYTHON) + INCLUDE(doxy2swig/doxy2swig.cmake) + FILE(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/tmp/medcouplingexamples.in" input) FILE(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/BuildPyExamplesFromCPP.py" pythondocexamplesgenerator) FILE(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" output) @@ -62,6 +64,13 @@ IF(SALOME_MED_ENABLE_PYTHON) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) + # Create dummy target gathering the generation of all .i files: + ADD_CUSTOM_TARGET(swig_ready) + ADD_DEPENDENCIES(swig_ready usr_docs) + + SALOME_MED_SWIG_DOCSTRING_CONFIGURE(usr_docs swig_ready MEDCoupling) + SALOME_MED_SWIG_DOCSTRING_CONFIGURE(usr_docs swig_ready MEDLoader) + SET(doxyfile_med_user ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_med_user) FILE(STRINGS ${doxyfile_med_user} enabled_sections REGEX "ENABLED_SECTIONS") IF(enabled_sections) @@ -73,6 +82,9 @@ IF(SALOME_MED_ENABLE_PYTHON) "#Temporary variable to enable python documentation sections\nENABLED_SECTIONS = ENABLE_EXAMPLES") ENDIF() + # Swig generation to have docstrings correctly populated: + INCLUDE(doxy2swig/doxy2swig.cmake) + ELSE() ADD_CUSTOM_TARGET(usr_docs ALL COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile_med_user @@ -81,7 +93,7 @@ ELSE() ) ENDIF() -INSTALL(CODE "EXECUTE_PROCESS(COMMAND \"${CMAKE_COMMAND}\" --build ${PROJECT_BINARY_DIR} --target usr_docs)") +#INSTALL(CODE "EXECUTE_PROCESS(COMMAND \"${CMAKE_COMMAND}\" --build ${PROJECT_BINARY_DIR} --target usr_docs)") INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc_ref_user/html/ DESTINATION ${SALOME_INSTALL_DOC}/gui/MED) INSTALL(FILES images/head.png DESTINATION ${SALOME_INSTALL_DOC}/gui/MED) diff --git a/doc/doxygen/Doxyfile_med_user.in b/doc/doxygen/Doxyfile_med_user.in index 5845b2807..1ecbb3e27 100644 --- a/doc/doxygen/Doxyfile_med_user.in +++ b/doc/doxygen/Doxyfile_med_user.in @@ -226,7 +226,9 @@ MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- -GENERATE_XML = NO +GENERATE_XML = YES +XML_OUTPUT = xml +XML_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- diff --git a/doc/doxygen/doxy2swig/MEDCoupling_doc.i.in b/doc/doxygen/doxy2swig/MEDCoupling_doc.i.in new file mode 100644 index 000000000..0ca88d7ee --- /dev/null +++ b/doc/doxygen/doxy2swig/MEDCoupling_doc.i.in @@ -0,0 +1 @@ +@_swig_include_set@ \ No newline at end of file diff --git a/doc/doxygen/doxy2swig/MEDLoader_doc.i.in b/doc/doxygen/doxy2swig/MEDLoader_doc.i.in new file mode 100644 index 000000000..0ca88d7ee --- /dev/null +++ b/doc/doxygen/doxy2swig/MEDLoader_doc.i.in @@ -0,0 +1 @@ +@_swig_include_set@ \ No newline at end of file diff --git a/doc/doxygen/doxy2swig/doxy2swig.cmake b/doc/doxygen/doxy2swig/doxy2swig.cmake new file mode 100644 index 000000000..0e96b3664 --- /dev/null +++ b/doc/doxygen/doxy2swig/doxy2swig.cmake @@ -0,0 +1,112 @@ +# Copyright (C) 2012-2015 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +## +## This module is dedicated to the generation of specific SWIG files (".i") containing +## the docstrings built from the C++ doxygen documentation. +## + +SET(_DOXY2SWIG ${PROJECT_SOURCE_DIR}/doc/doxygen/doxy2swig/doxy2swig.py) +SET(_SWIG_DOC_SUFFIX "doc_class_") + +# +# MEDCoupling classes to include +# +SET(_classes_MEDCoupling + ParaMEDMEM_1_1MEDCouplingUMesh + ParaMEDMEM_1_1MEDCouplingCMesh + ParaMEDMEM_1_1MEDCouplingRemapper + ParaMEDMEM_1_1DataArray + ParaMEDMEM_1_1DataArrayInt + ParaMEDMEM_1_1DataArrayDouble + ) + +# +# MEDLoader classes to include +# +SET(_classes_MEDLoader + MEDLoader + ParaMEDMEM_1_1MEDFileMeshes + ParaMEDMEM_1_1MEDFileMesh + ParaMEDMEM_1_1MEDFileUMesh + ParaMEDMEM_1_1MEDFileCMesh + ) + +## +## Generates the ".i" files from a list of C++ classes. +## +## \param[in] target_doc main target for the stantard doxygen generation +## \param[in] target_swig dummy target encompassing the final build of all SWIG files +## \param[in] cls_list list of classes for which to generate SWIG files +## \param[in] swig_main_file main SWIG file including the other generated SWIG files +## \param[out] swig_files list of generated SWIG files +## +MACRO(SALOME_MED_SWIG_DOCSTRING_GENERATE target_doc target_swig cls_list swig_main_file swig_files) + # List of generated SWIG files (.i) for doc purposes only: + SET(${swig_files}) + FOREACH(_cls IN LISTS ${cls_list}) + SET(_xml_file "${CMAKE_CURRENT_BINARY_DIR}/../doxygen/doc_ref_user/xml/class${_cls}.xml") + SET(_swig_file_base "${_SWIG_DOC_SUFFIX}${_cls}.i") + SET(_swig_file "${PROJECT_BINARY_DIR}/doc/${_swig_file_base}" ) + + # SWIG doc files will always be generated *after* Doxygen is run: + ### WARNING: ADD_CUSTOM_COMMAND(TARGET xxx POST_BUILD ...) command + ### must be in exactly the same subdir as the initial target construction command. + ### That's why this file is included with an INCLUDE() rather than using ADD_SUBDIRECTORY + # Note: we touch the main .i file to be sure to retrigger swig when the doc in a included + # class changes. + ADD_CUSTOM_COMMAND(OUTPUT ${_swig_file} + COMMAND ${PYTHON_EXECUTABLE} ${_DOXY2SWIG} "-n" ${_xml_file} ${_swig_file} + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${swig_main_file} + DEPENDS ${_xml_file} + COMMENT "Generating docstring SWIG file (from Doxygen's XML): ${_swig_file_base}" + VERBATIM + ) + ADD_CUSTOM_TARGET(${_swig_file_base} DEPENDS ${_swig_file}) + # The doxy2swig script is executed once the doxygen documentation has been generated ... + ADD_DEPENDENCIES(${_swig_file_base} ${target_doc}) + # ... and the meta target 'swig_ready' (here ${target_swig}) is ready when all .i files + # have been generated: + ADD_DEPENDENCIES(${target_swig} ${_swig_file_base}) + + LIST(APPEND ${swig_files} ${_swig_file_base}) + ENDFOREACH() +ENDMACRO(SALOME_MED_SWIG_DOCSTRING_GENERATE) + + +## +## Configures the MEDCoupling_doc.i or MEDLoader_doc.i file so that they include +## the list of SWIG files generated by the macro above. +## +## \param[in] target_doc main target for the stantard doxygen generation +## \param[in] target_swig dummy target encompassing the final build of all SWIG files +## \param[in] root_name either 'MEDCoupling' or 'MEDLoader' +## +MACRO(SALOME_MED_SWIG_DOCSTRING_CONFIGURE target_doc target_swig root_name) + SET(_all_swig_docs) + SET(_swig_include_set) + SET(_in_file doxy2swig/${root_name}_doc.i.in) + SET(_out_file ${PROJECT_BINARY_DIR}/doc/${root_name}_doc.i) + SALOME_MED_SWIG_DOCSTRING_GENERATE(${target_doc} ${target_swig} _classes_${root_name} ${_out_file} _all_swig_docs) + FOREACH(f IN LISTS _all_swig_docs) + SET(_swig_include_set "${_swig_include_set}\n%include \"${f}\"") + ENDFOREACH() + CONFIGURE_FILE(${_in_file} ${_out_file} @ONLY) +ENDMACRO(SALOME_MED_SWIG_DOCSTRING_CONFIGURE) + diff --git a/doc/doxygen/doxy2swig/doxy2swig.py b/doc/doxygen/doxy2swig/doxy2swig.py new file mode 100755 index 000000000..7a3b3ea8f --- /dev/null +++ b/doc/doxygen/doxy2swig/doxy2swig.py @@ -0,0 +1,455 @@ +#!/usr/bin/env python +"""Doxygen XML to SWIG docstring converter. + +Usage: + + doxy2swig.py [options] input.xml output.i + +Converts Doxygen generated XML files into a file containing docstrings +that can be used by SWIG-1.3.x. Note that you need to get SWIG +version > 1.3.23 or use Robin Dunn's docstring patch to be able to use +the resulting output. + +input.xml is your doxygen generated XML file and output.i is where the +output will be written (the file will be clobbered). + +""" +###################################################################### +# +# This code is implemented using Mark Pilgrim's code as a guideline: +# http://www.faqs.org/docs/diveintopython/kgp_divein.html +# +# Author: Prabhu Ramachandran +# License: BSD style +# +# Thanks: +# Johan Hake: the include_function_definition feature +# Bill Spotz: bug reports and testing. +# Sebastian Henschel: Misc. enhancements. +# +###################################################################### + +from xml.dom import minidom +import re +import textwrap +import sys +import types +import os.path +import optparse + + +def my_open_read(source): + if hasattr(source, "read"): + return source + else: + return open(source) + +def my_open_write(dest): + if hasattr(dest, "write"): + return dest + else: + return open(dest, 'w') + + +class Doxy2SWIG: + """Converts Doxygen generated XML files into a file containing + docstrings that can be used by SWIG-1.3.x that have support for + feature("docstring"). Once the data is parsed it is stored in + self.pieces. + + """ + + def __init__(self, src, include_function_definition=True, quiet=False): + """Initialize the instance given a source object. `src` can + be a file or filename. If you do not want to include function + definitions from doxygen then set + `include_function_definition` to `False`. This is handy since + this allows you to use the swig generated function definition + using %feature("autodoc", [0,1]). + + """ + f = my_open_read(src) + self.my_dir = os.path.dirname(f.name) + self.xmldoc = minidom.parse(f).documentElement + f.close() + + self.pieces = [] + self.pieces.append('\n// File: %s\n'%\ + os.path.basename(f.name)) + + self.space_re = re.compile(r'\s+') + self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)') + self.multi = 0 + self.ignores = ['inheritancegraph', 'param', 'listofallmembers', + 'innerclass', 'name', 'declname', 'incdepgraph', + 'invincdepgraph', 'programlisting', 'type', + 'references', 'referencedby', 'location', + 'collaborationgraph', 'reimplements', + 'reimplementedby', 'derivedcompoundref', + 'basecompoundref'] + #self.generics = [] + self.include_function_definition = include_function_definition + if not include_function_definition: + self.ignores.append('argsstring') + + self.quiet = quiet + + + def generate(self): + """Parses the file set in the initialization. The resulting + data is stored in `self.pieces`. + + """ + self.parse(self.xmldoc) + + def parse(self, node): + """Parse a given node. This function in turn calls the + `parse_` functions which handle the respective + nodes. + + """ + pm = getattr(self, "parse_%s"%node.__class__.__name__) + pm(node) + + def parse_Document(self, node): + self.parse(node.documentElement) + + def parse_Text(self, node): + txt = node.data + txt = txt.replace('\\', r'\\\\') + txt = txt.replace('"', r'\"') + # ignore pure whitespace + m = self.space_re.match(txt) + if m and len(m.group()) == len(txt): + pass + else: + self.add_text(textwrap.fill(txt, break_long_words=False)) + + def parse_Element(self, node): + """Parse an `ELEMENT_NODE`. This calls specific + `do_` handers for different elements. If no handler + is available the `generic_parse` method is called. All + tagNames specified in `self.ignores` are simply ignored. + + """ + name = node.tagName + ignores = self.ignores + if name in ignores: + return + attr = "do_%s" % name + if hasattr(self, attr): + handlerMethod = getattr(self, attr) + handlerMethod(node) + else: + self.generic_parse(node) + #if name not in self.generics: self.generics.append(name) + + def parse_Comment(self, node): + """Parse a `COMMENT_NODE`. This does nothing for now.""" + return + + def add_text(self, value): + """Adds text corresponding to `value` into `self.pieces`.""" + if type(value) in (types.ListType, types.TupleType): + self.pieces.extend(value) + else: + self.pieces.append(value) + + def get_specific_nodes(self, node, names): + """Given a node and a sequence of strings in `names`, return a + dictionary containing the names as keys and child + `ELEMENT_NODEs`, that have a `tagName` equal to the name. + + """ + nodes = [(x.tagName, x) for x in node.childNodes \ + if x.nodeType == x.ELEMENT_NODE and \ + x.tagName in names] + return dict(nodes) + + def generic_parse(self, node, pad=0): + """A Generic parser for arbitrary tags in a node. + + Parameters: + + - node: A node in the DOM. + - pad: `int` (default: 0) + + If 0 the node data is not padded with newlines. If 1 it + appends a newline after parsing the childNodes. If 2 it + pads before and after the nodes are processed. Defaults to + 0. + + """ + npiece = 0 + if pad: + npiece = len(self.pieces) + if pad == 2: + self.add_text('\n') + for n in node.childNodes: + self.parse(n) + if pad: + if len(self.pieces) > npiece: + self.add_text('\n') + + def space_parse(self, node): + self.add_text(' ') + self.generic_parse(node) + + do_ref = space_parse + do_emphasis = space_parse + do_bold = space_parse + do_computeroutput = space_parse + do_formula = space_parse + + def do_compoundname(self, node): + self.add_text('\n\n') + data = node.firstChild.data + self.add_text('%%feature("docstring") %s "\n'%data) + + def do_compounddef(self, node): + kind = node.attributes['kind'].value + if kind in ('class', 'struct'): + prot = node.attributes['prot'].value + if prot <> 'public': + return + names = ('compoundname', 'briefdescription', + 'detaileddescription', 'includes') + first = self.get_specific_nodes(node, names) + for n in names: + if first.has_key(n): + self.parse(first[n]) + self.add_text(['";','\n']) + for n in node.childNodes: + if n not in first.values(): + self.parse(n) + elif kind in ('file', 'namespace'): + nodes = node.getElementsByTagName('sectiondef') + for n in nodes: + self.parse(n) + + def do_includes(self, node): + self.add_text('C++ includes: ') + self.generic_parse(node, pad=1) + + def do_parameterlist(self, node): + text='unknown' + for key, val in node.attributes.items(): + if key == 'kind': + if val == 'param': text = 'Parameters' + elif val == 'exception': text = 'Exceptions' + else: text = val + break + self.add_text(['\n', '\n', text, ':', '\n']) + self.generic_parse(node, pad=1) + + def do_para(self, node): + self.add_text('\n') + self.generic_parse(node, pad=1) + + def do_parametername(self, node): + self.add_text('\n') + try: + data=node.firstChild.data + except AttributeError: # perhaps a tag in it + data=node.firstChild.firstChild.data + if data.find('Exception') != -1: + self.add_text(data) + else: + self.add_text("%s: "%data) + + def do_parameterdefinition(self, node): + self.generic_parse(node, pad=1) + + def do_detaileddescription(self, node): + self.generic_parse(node, pad=1) + + def do_briefdescription(self, node): + self.generic_parse(node, pad=1) + + def do_memberdef(self, node): + prot = node.attributes['prot'].value + id = node.attributes['id'].value + kind = node.attributes['kind'].value + tmp = node.parentNode.parentNode.parentNode + compdef = tmp.getElementsByTagName('compounddef')[0] + cdef_kind = compdef.attributes['kind'].value + + if prot == 'public': + first = self.get_specific_nodes(node, ('definition', 'name')) + name = first['name'].firstChild.data + if name[:8] == 'operator': # Don't handle operators yet. + return + + if not first.has_key('definition') or \ + kind in ['variable', 'typedef']: + return + + if self.include_function_definition: + defn = first['definition'].firstChild.data + else: + defn = "" + self.add_text('\n') + self.add_text('%feature("docstring") ') + + anc = node.parentNode.parentNode + if cdef_kind in ('file', 'namespace'): + ns_node = anc.getElementsByTagName('innernamespace') + if not ns_node and cdef_kind == 'namespace': + ns_node = anc.getElementsByTagName('compoundname') + if ns_node: + ns = ns_node[0].firstChild.data + self.add_text(' %s::%s "\n%s'%(ns, name, defn)) + else: + self.add_text(' %s "\n%s'%(name, defn)) + elif cdef_kind in ('class', 'struct'): + # Get the full function name. + anc_node = anc.getElementsByTagName('compoundname') + cname = anc_node[0].firstChild.data + self.add_text(' %s::%s "\n%s'%(cname, name, defn)) + + for n in node.childNodes: + if n not in first.values(): + self.parse(n) + self.add_text(['";', '\n']) + + def do_definition(self, node): + data = node.firstChild.data + self.add_text('%s "\n%s'%(data, data)) + + def do_sectiondef(self, node): + kind = node.attributes['kind'].value + if kind in ('public-func', 'func', 'user-defined', ''): + self.generic_parse(node) + + def do_header(self, node): + """For a user defined section def a header field is present + which should not be printed as such, so we comment it in the + output.""" + data = node.firstChild.data + self.add_text('\n/*\n %s \n*/\n'%data) + # If our immediate sibling is a 'description' node then we + # should comment that out also and remove it from the parent + # node's children. + parent = node.parentNode + idx = parent.childNodes.index(node) + if len(parent.childNodes) >= idx + 2: + nd = parent.childNodes[idx+2] + if nd.nodeName == 'description': + nd = parent.removeChild(nd) + self.add_text('\n/*') + self.generic_parse(nd) + self.add_text('\n*/\n') + + def do_simplesect(self, node): + kind = node.attributes['kind'].value + if kind in ('date', 'rcs', 'version'): + pass + elif kind == 'warning': + self.add_text(['\n', 'WARNING: ']) + self.generic_parse(node) + elif kind == 'see': + self.add_text('\n') + self.add_text('See: ') + self.generic_parse(node) + elif kind == 'return': + self.add_text(['\n', '===> Returns: ']) + self.generic_parse(node) + else: + self.generic_parse(node) + + def do_argsstring(self, node): + self.generic_parse(node, pad=1) + + def do_member(self, node): + kind = node.attributes['kind'].value + refid = node.attributes['refid'].value + if kind == 'function' and refid[:9] == 'namespace': + self.generic_parse(node) + + def do_doxygenindex(self, node): + self.multi = 1 + comps = node.getElementsByTagName('compound') + for c in comps: + refid = c.attributes['refid'].value + fname = refid + '.xml' + if not os.path.exists(fname): + fname = os.path.join(self.my_dir, fname) + if not self.quiet: + print "parsing file: %s"%fname + p = Doxy2SWIG(fname, self.include_function_definition, self.quiet) + p.generate() + self.pieces.extend(self.clean_pieces(p.pieces)) + + def write(self, fname): + o = my_open_write(fname) + if self.multi: + o.write("".join(self.pieces)) + else: + o.write("".join(self.clean_pieces(self.pieces))) + o.close() + + def clean_pieces(self, pieces): + """Cleans the list of strings given as `pieces`. It replaces + multiple newlines by a maximum of 2 and returns a new list. + It also wraps the paragraphs nicely. + + """ + ret = [] + count = 0 + for i in pieces: + if i == '\n': + count = count + 1 + else: + if i == '";': + if count: + ret.append('\n') + elif count > 2: + ret.append('\n\n') + elif count: + ret.append('\n'*count) + count = 0 + ret.append(i) + + _data = "".join(ret) + ret = [] + for i in _data.split('\n\n'): + if i == 'Parameters:' or i == 'Exceptions:': + ret.extend([i, '\n-----------', '\n\n']) + elif i.find('// File:') > -1: # leave comments alone. + ret.extend([i, '\n']) + else: + _tmp = textwrap.fill(i.strip(), break_long_words=False) + _tmp = self.lead_spc.sub(r'\1"\2', _tmp) + ret.extend([_tmp, '\n\n']) + return ret + + +def convert(input, output, include_function_definition=True, quiet=False): + p = Doxy2SWIG(input, include_function_definition, quiet) + p.generate() + p.write(output) + +def main(): + usage = __doc__ + parser = optparse.OptionParser(usage) + parser.add_option("-n", '--no-function-definition', + action='store_true', + default=False, + dest='func_def', + help='do not include doxygen function definitions') + parser.add_option("-q", '--quiet', + action='store_true', + default=False, + dest='quiet', + help='be quiet and minimize output') + + options, args = parser.parse_args() + if len(args) != 2: + parser.error("error: no input and output specified") + + convert(args[0], args[1], not options.func_def, options.quiet) + + +if __name__ == '__main__': + main() + diff --git a/src/MEDCoupling/MEDCouplingUMesh.cxx b/src/MEDCoupling/MEDCouplingUMesh.cxx index 70db4e588..4efb00a5e 100644 --- a/src/MEDCoupling/MEDCouplingUMesh.cxx +++ b/src/MEDCoupling/MEDCouplingUMesh.cxx @@ -316,8 +316,8 @@ void MEDCouplingUMesh::setMeshDimension(int meshDim) } /*! - * Allocates memory to store an estimation of the given number of cells. Closer is the estimation to the number of cells effectively inserted, - * less will be the needs to realloc. If the number of cells to be inserted is not known simply put 0 to this parameter. + * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted, + * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter. * If a nodal connectivity previouly existed before the call of this method, it will be reset. * * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain. diff --git a/src/MEDCoupling_Swig/CMakeLists.txt b/src/MEDCoupling_Swig/CMakeLists.txt index 4d218def5..07929a88d 100644 --- a/src/MEDCoupling_Swig/CMakeLists.txt +++ b/src/MEDCoupling_Swig/CMakeLists.txt @@ -43,6 +43,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Geometric2D ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/ExprEval ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/GaussPoints + ${PROJECT_BINARY_DIR}/doc ) # _ABR_ Ensure dependency mechanism on all SWIG files and headers @@ -50,6 +51,15 @@ SET (SWIG_MODULE_MEDCoupling_EXTRA_DEPS ${MEDCoupling_SWIG_DPYS_FILES} ${medcoupling_HEADERS_HXX} ${medcoupling_HEADERS_TXX} ${interpkernel_HEADERS_HXX} ${interpkernel_HEADERS_TXX}) +# SWIG must run after the doc if we want to have the docstrings extracted from Doxygen +# into the Python module: +IF(SALOME_BUILD_DOC) + LIST(APPEND SWIG_MODULE_MEDCoupling_EXTRA_FLAGS -DWITH_DOCSTRINGS) + LIST(APPEND SWIG_MODULE_MEDCoupling_EXTRA_DEPS + ${PROJECT_BINARY_DIR}/doc/MEDCoupling_doc.i + swig_ready) +ENDIF() + SWIG_ADD_MODULE(MEDCoupling python MEDCoupling.i) SWIG_LINK_LIBRARIES(MEDCoupling ${PYTHON_LIBRARIES} ${PLATFORM_LIBS} medcoupling) diff --git a/src/MEDCoupling_Swig/MEDCouplingCommon.i b/src/MEDCoupling_Swig/MEDCouplingCommon.i index 24920cc8e..8f1717456 100644 --- a/src/MEDCoupling_Swig/MEDCouplingCommon.i +++ b/src/MEDCoupling_Swig/MEDCouplingCommon.i @@ -20,6 +20,10 @@ %module MEDCoupling +#ifdef WITH_DOCSTRINGS +%include MEDCoupling_doc.i +#endif + %include std_vector.i %include std_string.i diff --git a/src/MEDLoader/Swig/CMakeLists.txt b/src/MEDLoader/Swig/CMakeLists.txt index 4fcecf52d..6cef3ea9a 100644 --- a/src/MEDLoader/Swig/CMakeLists.txt +++ b/src/MEDLoader/Swig/CMakeLists.txt @@ -44,6 +44,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../../INTERP_KERNEL/Geometric2D ${CMAKE_CURRENT_SOURCE_DIR}/../../INTERP_KERNEL/ExprEval ${CMAKE_CURRENT_SOURCE_DIR}/../../INTERP_KERNEL/GaussPoints + ${PROJECT_BINARY_DIR}/doc ) SET (SWIG_MODULE_MEDLoader_EXTRA_DEPS ${MEDLoader_SWIG_DPYS_FILES} @@ -51,13 +52,22 @@ SET (SWIG_MODULE_MEDLoader_EXTRA_DEPS ${MEDLoader_SWIG_DPYS_FILES} ${medcoupling_HEADERS_HXX} ${medcoupling_HEADERS_TXX} ${interpkernel_HEADERS_HXX} ${interpkernel_HEADERS_TXX}) +# SWIG must run after the doc if we want to have the docstrings extracted from Doxygen +# into the Python module: +IF(SALOME_BUILD_DOC) + LIST(APPEND SWIG_MODULE_MEDLoader_EXTRA_FLAGS -DWITH_DOCSTRINGS) + LIST(APPEND SWIG_MODULE_MEDLoader_EXTRA_DEPS + ${PROJECT_BINARY_DIR}/doc/MEDLoader_doc.i + swig_ready) +ENDIF() + SWIG_ADD_MODULE(MEDLoader python MEDLoader.i) SWIG_LINK_LIBRARIES(MEDLoader ${PYTHON_LIBRARIES} ${PLATFORM_LIBS} medloader medcoupling) IF(WIN32) SET_TARGET_PROPERTIES(_MEDLoader PROPERTIES DEBUG_OUTPUT_NAME _MEDLoader_d) ENDIF(WIN32) -INSTALL(TARGETS _MEDLoader DESTINATION ${SALOME_INSTALL_PYTHON}) +INSTALL(TARGETS _MEDLoader DESTINATION ${SALOME_INSTALL_PYTHON}) INSTALL(FILES MEDLoader.i MEDLoaderTypemaps.i MEDLoaderCommon.i DESTINATION ${SALOME_INSTALL_HEADERS}) SET(PYFILES_TO_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/MEDLoader.py) diff --git a/src/MEDLoader/Swig/MEDLoaderCommon.i b/src/MEDLoader/Swig/MEDLoaderCommon.i index b4132f8ca..2512825f8 100644 --- a/src/MEDLoader/Swig/MEDLoaderCommon.i +++ b/src/MEDLoader/Swig/MEDLoaderCommon.i @@ -23,6 +23,10 @@ #define MEDCOUPLING_EXPORT #define MEDLOADER_EXPORT +#ifdef WITH_DOCSTRINGS +%include "MEDLoader_doc.i" +#endif + %include "MEDCouplingCommon.i" %{