CastXML / pygccxml

pygccxml is a specialized XML reader that reads the output from CastXML or GCCXML. It provides a simple framework to navigate C++ declarations, using Python classes.
Boost Software License 1.0
131 stars 45 forks source link

Failure in algorithm.py with c++11 #55

Closed iMichka closed 8 years ago

iMichka commented 8 years ago

Initially reported here: https://github.com/gccxml/pygccxml/issues/47#issuecomment-215999936 (There are also two xml files in the comment that may be interesting).

/home/ompl/castxml/bin/castxml  -std=c++11   -I. -I. -I/home/ompl/omplapp/ompl/src -I/home/ompl/omplapp/src -I/usr/include/python2.7 -I/usr/include -I/usr/include/assimp -I/usr/include/eigen3 -I/home/ompl/omplapp/ompl/src/../py-bindings -c -x c++ --castxml-cc-gnu  "(" /usr/bin/g++ -std=c++11 ")" --castxml-gccxml -o /tmp/tmpT4yHPz.xml bindings/util.h
Traceback (most recent call last):
  File "/home/ompl/omplapp/ompl/py-bindings/generate_bindings.py", line 800, in <module>
    globals()['ompl_'+module+'_generator_t']()
  File "/home/ompl/omplapp/ompl/py-bindings/generate_bindings.py", line 734, in __init__
    code_generator_t.__init__(self, 'util', None, replacement, 1)
  File "/home/ompl/omplapp/ompl/py-bindings/ompl/bindings_generator.py", line 136, in __init__
    self.mb.split_module('bindings/' + name, use_files_sum_repository=True)
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/module_builder/boost_python_builder.py", line 384, in split_module
    , encoding=self.encoding)
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/file_writers/__init__.py", line 36, in write_multiple_files
    mfs = multiple_files_t( extmodule, dir_path, files_sum_repository=files_sum_repository, encoding=encoding )
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/file_writers/multiple_files.py", line 34, in __init__
    writer.writer_t.__init__( self, extmodule, files_sum_repository, encoding=encoding )
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/file_writers/writer.py", line 36, in __init__
    , extmodule.specially_exposed_decls )
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/utils/__init__.py", line 200, in register_decls
    row = self.row_t( decl )
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/utils/__init__.py", line 71, in __init__
    self.__init_from_decl( decl_or_string )
  File "/usr/local/lib/python2.7/dist-packages/pyplusplus/utils/__init__.py", line 100, in __init_from_decl
    self.signature = decl.create_decl_string( with_defaults=False )
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/calldef.py", line 616, in create_decl_string
    return f_type.partial_decl_string
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/cpptypes.py", line 54, in partial_decl_string
    return self.build_decl_string(False)
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/cpptypes.py", line 829, in build_decl_string
    with_defaults)
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/cpptypes.py", line 820, in create_decl_string
    [_f(x, with_defaults) for x in arguments_types]),
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/cpptypes.py", line 486, in _f
    return x.build_decl_string(with_defaults)
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/cpptypes.py", line 584, in build_decl_string
    return self.base.build_decl_string(with_defaults) + ' &'
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/cpptypes.py", line 895, in build_decl_string
    return self._declaration.partial_decl_string
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/declaration.py", line 361, in partial_decl_string
    return self.create_decl_string(with_defaults=False)
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/declaration.py", line 343, in create_decl_string
    return algorithm.full_name(self, with_defaults)
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/algorithm.py", line 133, in full_name
    partial_declaration_path(decl))
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/algorithm.py", line 64, in partial_declaration_path
    result = [decl.partial_name]
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/declaration.py", line 195, in partial_name
    self._partial_name = self._get_partial_name_impl()
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/class_declaration.py", line 575, in _get_partial_name_impl
    if type_traits.is_std_string(self):
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/type_traits.py", line 1309, in is_std_string
    return remove_cv(type_).decl_string in string_equivalences
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/declaration.py", line 352, in decl_string
    return self.create_decl_string()
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/declaration.py", line 343, in create_decl_string
    return algorithm.full_name(self, with_defaults)
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/algorithm.py", line 128, in full_name
    declaration_path(decl))
  File "/usr/local/lib/python2.7/dist-packages/pygccxml/declarations/algorithm.py", line 107, in full_name_from_declaration_path
    result = result[0] + '::'.join(result[1:])
IndexError: list index out of range
Command exited with non-zero status 1

Happens with gcc4.9 and gcc5. @mamoll do you have a minimal c++ code example to help setup a test for this ?

mamoll commented 8 years ago

Not yet. I hope to get around this soon.

mamoll commented 8 years ago

Here is a minimal example that fails on Ubuntu 15.10, gcc 5.2.1, castxml version 0.1-gf1bb3c2, pygccxml 1.7.4, and pyplusplus 1.6.0. Save the attached files and run python test.py.

castxml.cfg test.h test.py

mamoll commented 8 years ago

The same example also fails on OS X 10.11.5, gcc 6.1.0, castxml 0.1-g8c32543, pygccxml 1.7.4, and pyplusplus 1.6.0 with the same error.

iMichka commented 8 years ago

Hi

I had some time to look at this. I could write a test to reproduce the bug, which I pushed to the hotfix/v1.7.6 branch. The travis build for this branch is not failing because it does not test against gcc (this is only done on the develop branch). But I can reproduce the bug locally.

The problem lies in the _M_clone_node method which is exposed in the xml file. First thing I saw is that no parent is set in pygccxml for this method (decl.parent == None).

Other methods, like for example _M_drop_node, have a parent (e.g. in this case the class '_Rb_tree<int, std::pair<const int, int>, std::_Select1st<std::pair<const int, int> >, std::less<int>, std::allocator<std::pair<const int, int> > >) However the class definition in the xml file lists the _M_clone_node method (3 times), so _M_clone_node should have a parent.

_M_clone_node is defined three times with different argument types, whereas the others like _M_drop_node are defined only once. This is the only difference I can see for the moment.

I will now investigate how and when the @parent.setter is called in the declaration_tclass. Once this is understood and fixed, the declaration string creation should work again. I hope it will not take me too long.

mamoll commented 8 years ago

Thanks for looking into this. This seems like a painful bug to fix.

iMichka commented 8 years ago

This should work now. The bug was that you can pass a struct or class instance without name to a method, and when building the declaration string this was failing. I added a new test for this.

It took me a long time to reproduce. The code in stl_tree.h is hard to follow (this is were _M_clone_node is defined).

Please test this. If it's ok I'll release the 1.7.6 version after this.

mamoll commented 8 years ago

This works! Python binding generation is taking forever, though. On my Ubuntu 15.10 VM it took more than 12 hours to generate the bindings. That's more than an order of magnitude slower than the gccxml-based workflow in the pre-C++11 version of the code. Clang + castxml is somewhere in between in terms of generation time. Nevertheless, the bug is fixed. Thanks!

iMichka commented 8 years ago

Great ! I'll make the 1.7.6 release with this fix during the weekend.

I will definitively have a look at the performance problem for v 1.8.0. I had already a look but was not able to solve it. I have maybe an idea how to solve this but this needs some work.