From: Martin Ling Date: Fri, 1 Aug 2014 16:18:09 +0000 (+0100) Subject: C++ bindings: Reimplement enums.py using doxygen XML output instead of gccxml. X-Git-Tag: libsigrok-0.4.0~1168 X-Git-Url: http://sigrok.org/gitweb/?p=libsigrok.git;a=commitdiff_plain;h=3532ed01256b986ecaf37ea5bb29d81465e2aa89 C++ bindings: Reimplement enums.py using doxygen XML output instead of gccxml. --- diff --git a/.gitignore b/.gitignore index c7d86586..21e039a2 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Doxyfile b/Doxyfile index 95ceaea0..2bd7df5d 100644 --- 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 diff --git a/Makefile.am b/Makefile.am index d961ad56..44bc9598 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/bindings/cxx/enums.py b/bindings/cxx/enums.py index 6eeedeaa..bdf12bf6 100644 --- a/bindings/cxx/enums.py +++ b/bindings/cxx/enums.py @@ -17,29 +17,15 @@ ## along with this program. If not, see . ## -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 %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, '};' diff --git a/configure.ac b/configure.ac index 68f9d1f6..d2f8926a 100644 --- a/configure.ac +++ b/configure.ac @@ -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