]> sigrok.org Git - libsigrok.git/commitdiff
C++ bindings: Reimplement enums.py using doxygen XML output instead of gccxml.
authorMartin Ling <redacted>
Fri, 1 Aug 2014 16:18:09 +0000 (17:18 +0100)
committerUwe Hermann <redacted>
Sun, 10 Aug 2014 13:47:13 +0000 (15:47 +0200)
.gitignore
Doxyfile
Makefile.am
bindings/cxx/enums.py
configure.ac

index c7d865864a6ddc9be9617edf9949feadca58ebc2..21e039a27e23dd0f266fe7b74a67e77962976872 100644 (file)
@@ -44,7 +44,7 @@ Makefile.in
 *.kdev4
 
 # Files generated by building C++ bindings
-bindings/cxx/libsigrok.xml
+doxy/
 bindings/cxx/include/libsigrok/enums.hpp
 bindings/cxx/enums.cpp
 bindings/cxx/enums.timestamp
index 95ceaea06f7f97dbc43c44985d249d58073a2ed3..2bd7df5dba989db33cc92a079c669aebb41d179c 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -683,7 +683,7 @@ CITE_BIB_FILES         =
 # messages are off.
 # The default value is: NO.
 
-QUIET                  = NO
+QUIET                  = YES
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are
 # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
@@ -1795,7 +1795,7 @@ MAN_LINKS              = NO
 # captures the structure of the code including all documentation.
 # The default value is: NO.
 
-GENERATE_XML           = NO
+GENERATE_XML           = YES
 
 # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
 # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@@ -1824,7 +1824,7 @@ XML_DTD                =
 # The default value is: YES.
 # This tag requires that the tag GENERATE_XML is set to YES.
 
-XML_PROGRAMLISTING     = YES
+XML_PROGRAMLISTING     = NO
 
 #---------------------------------------------------------------------------
 # Configuration options related to the DOCBOOK output
index d961ad5694648ac5bbfef37368f73eeb5d106780..44bc959877d11b7e5e79a87d13125389dec259c7 100644 (file)
@@ -408,23 +408,23 @@ library_include_HEADERS += \
 
 pkgconfig_DATA += bindings/cxx/libsigrokxx.pc
 
-bindings/cxx/libsigrok.xml: include/libsigrok/libsigrok.h
-       $(AM_V_GEN)gccxml $(CFLAGS) -DGLIB_DISABLE_DEPRECATION_WARNINGS $< -fxml=$@
+doxy/xml/index.xml: include/libsigrok/libsigrok.h
+       $(AM_V_GEN)doxygen Doxyfile
 
 bindings/cxx/enums.cpp: bindings/cxx/enums.timestamp
 
 bindings/cxx/include/libsigrok/enums.hpp: bindings/cxx/enums.timestamp
 
-bindings/cxx/enums.timestamp: bindings/cxx/enums.py bindings/cxx/libsigrok.xml \
+bindings/cxx/enums.timestamp: bindings/cxx/enums.py doxy/xml/index.xml \
                bindings/cxx/ConfigKey_methods.cpp bindings/cxx/QuantityFlag_methods.cpp
-       $(AM_V_GEN)python $<
+       $(AM_V_GEN)python $< doxy/xml/index.xml
        $(AM_V_at)touch $@
 
 bindings/cxx/classes.lo: bindings/cxx/classes.cpp bindings/cxx/enums.cpp \
                $(library_include_HEADERS)
 
 cxx-clean:
-       rm -f bindings/cxx/libsigrok.xml
+       rm -rf doxy/
        rm -f bindings/cxx/enums.cpp
        rm -f bindings/cxx/include/libsigrok/enums.hpp
        rm -f bindings/cxx/enums.timestamp
index 6eeedeaaffcb3bf8d8150a2a4dd5c09f1ff5e0ce..bdf12bf64e6cf89f662d395da92b3766cc99878c 100644 (file)
 ## along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ##
 
-import logging, warnings
-from pygccxml import parser, declarations
+from xml.etree import ElementTree
 from collections import OrderedDict
 import sys, os, re
 
-class crapfilter(logging.Filter):
-    def filter(self, record):
-        if record.msg.find('GCCXML version') > -1:
-            return 0
-        return 1
-logger = logging.getLogger('pygccxml.cxx_parser').addFilter(crapfilter())
-warnings.filterwarnings('ignore', message="unable to find out array size from expression")
+index_file = sys.argv[1]
 
 # Get directory this script is in.
 dirname = os.path.dirname(os.path.realpath(__file__))
 
-# Parse GCCXML output to get declaration tree.
-decls = parser.parse_xml_file(
-    os.path.join(dirname, "libsigrok.xml"), parser.gccxml_configuration_t())
-
-# Get global namespace from declaration tree.
-ns = declarations.get_global_namespace(decls)
-
 mapping = dict([
     ('sr_loglevel', 'LogLevel'),
     ('sr_packettype', 'PacketType'),
@@ -51,13 +37,28 @@ mapping = dict([
     ('sr_channeltype', 'ChannelType'),
     ('sr_trigger_matches', 'TriggerMatchType')])
 
-classes = OrderedDict()
+index = ElementTree.parse(index_file)
 
 # Build mapping between class names and enumerations.
-for enum in ns.enumerations():
-    if enum.name in mapping:
-        classname = mapping[enum.name]
-        classes[classname] = enum
+
+classes = OrderedDict()
+
+for compound in index.findall('compound'):
+    if compound.attrib['kind'] != 'file':
+        continue
+    filename = os.path.join(
+        os.path.dirname(index_file),
+        '%s.xml' % compound.attrib['refid'])
+    doc = ElementTree.parse(filename)
+    for section in doc.find('compounddef').findall('sectiondef'):
+        if section.attrib["kind"] != 'enum':
+            continue
+        for member in section.findall('memberdef'):
+            if member.attrib["kind"] != 'enum':
+                continue
+            name = member.find('name').text
+            if name in mapping:
+                classes[member] = mapping[name]
 
 header = open(os.path.join(dirname, 'include/libsigrok/enums.hpp'), 'w')
 code = open(os.path.join(dirname, 'enums.cpp'), 'w')
@@ -93,16 +94,20 @@ const {classname} *{classname}::get(int id)
 }}
 """
 
-for classname, enum in classes.items():
+for enum, classname in classes.items():
+
+    enum_name = enum.find('name').text
+    member_names = [m.find('name').text for m in enum.findall('enumvalue')]
+    trimmed_names = [re.sub("^SR_[A-Z]+_", "", n) for n in member_names]
 
     # Begin class and public declarations
     print >> header, header_public_template.format(
-        classname=classname, enumname=enum.name)
+        classname=classname, enumname=enum_name)
 
     # Declare public pointers for each enum value
-    for name, value in enum.values:
-        trimmed_name = re.sub("^SR_[A-Z]+_", "", name)
-        print >> header, '\tstatic const %s * const %s;' % (classname, trimmed_name)
+    for trimmed_name in trimmed_names:
+        print >> header, '\tstatic const %s * const %s;' % (
+            classname, trimmed_name)
 
     # Declare additional methods if present
     filename = os.path.join(dirname, "%s_methods.hpp" % classname)
@@ -111,11 +116,10 @@ for classname, enum in classes.items():
 
     # Begin private declarations
     print >> header, header_private_template.format(
-        classname=classname, enumname=enum.name)
+        classname=classname, enumname=enum_name)
 
     # Declare private constants for each enum value
-    for name, value in enum.values:
-        trimmed_name = re.sub("^SR_[A-Z]+_", "", name)
+    for trimmed_name in trimmed_names:
         print >> header, '\tstatic const %s _%s;' % (classname, trimmed_name)
 
     # End class declaration
@@ -123,25 +127,22 @@ for classname, enum in classes.items():
 
     # Begin class code
     print >> code, code_template.format(
-        classname=classname, enumname=enum.name)
+        classname=classname, enumname=enum_name)
 
     # Define private constants for each enum value
-    for name, value in enum.values:
-        trimmed_name = re.sub("^SR_[A-Z]+_", "", name)
+    for name, trimmed_name in zip(member_names, trimmed_names):
         print >> code, 'const %s %s::_%s = %s(%s, "%s");' % (
             classname, classname, trimmed_name, classname, name, trimmed_name)
 
     # Define public pointers for each enum value
-    for name, value in enum.values:
-        trimmed_name = re.sub("^SR_[A-Z]+_", "", name)
+    for trimmed_name in trimmed_names:
         print >> code, 'const %s * const %s::%s = &%s::_%s;' % (
             classname, classname, trimmed_name, classname, trimmed_name)
 
     # Define map of enum values to constants
     print >> code, 'const std::map<enum %s, const %s *> %s::values = {' % (
-        enum.name, classname, classname)
-    for name, value in enum.values:
-        trimmed_name = re.sub("^SR_[A-Z]+_", "", name)
+        enum_name, classname, classname)
+    for name, trimmed_name in zip(member_names, trimmed_names):
         print >> code, '\t{%s, %s::%s},' % (name, classname, trimmed_name)
     print >> code, '};'
 
index 68f9d1f6170209ad35a570fb2622c85b79308270..d2f8926a3b1d4ecb79fdab777747a0fceb9283f7 100644 (file)
@@ -184,10 +184,10 @@ if test "x$HAVE_CXX11" != "x1"; then
        BINDINGS_CXX="no"; cxx_msg="C++11 compiler required"
 fi
 
-# The C++ bindings use gccxml to parse libsigrok symbols.
-AC_CHECK_PROG([HAVE_GCCXML], [gccxml], [yes])
-if test "x$HAVE_GCCXML" != "xyes"; then
-       BINDINGS_CXX="no"; cxx_msg="gccxml required"
+# The C++ bindings use doxygen to parse libsigrok symbols.
+AC_CHECK_PROG([HAVE_DOXYGEN], [doxygen], [yes])
+if test "x$HAVE_DOXYGEN" != "xyes"; then
+       BINDINGS_CXX="no"; cxx_msg="doxygen required"
 fi
 
 # Python is needed for the C++ bindings.
@@ -202,17 +202,6 @@ PKG_CHECK_MODULES([python], [python >= 2.7],
         CXXLIBS="$CXXLIBS $python_LIBS"],
                [BINDINGS_PYTHON="no"; python_msg="Python headers required"])
 
-# The C++ bindings need the pygccxml Python module.
-m4_ifdef([AX_PYTHON_MODULE], [AX_PYTHON_MODULE([pygccxml])],
-       # We'll let it go through even if the macro wasn't found, the python
-       # module may still be there.
-       [HAVE_PYTHON_PYGCCXML="yes";
-               AC_MSG_NOTICE([Missing macro m4_toupper(aX_PYTHON_MODULE), no pygccxml check])]
-)
-if test "x$HAVE_PYMOD_PYGCCXML" != "xyes"; then
-       BINDINGS_CXX="no"; cxx_msg="Python pygccxml module required"
-fi
-
 # The Python bindings need the setuptools Python module.
 m4_ifdef([AX_PYTHON_MODULE], [AX_PYTHON_MODULE([setuptools])],
        # We'll let it go through even if the macro wasn't found, the python