def finalize(cls, finalize_pure_virtuals=False): """ Attempt to finalize a class by not exposing virtual methods. Still exposes in the case of pure virtuals otherwise the class could not be instantiated. """ if isinstance(cls, pd.mdecl_wrapper_t): for x in cls: finalize(x) else: matcher = pd.virtuality_type_matcher(pd.VIRTUALITY_TYPES.VIRTUAL) if finalize_pure_virtuals: matcher = matcher | pd.virtuality_type_matcher( pd.VIRTUALITY_TYPES.PURE_VIRTUAL) members = cls.decls(matcher, decl_type=pd.member_calldef_t, allow_empty=True) members.set_virtuality(pd.VIRTUALITY_TYPES.NOT_VIRTUAL) cls.decls(pd.access_type_matcher_t(pd.ACCESS_TYPES.PROTECTED), allow_empty=True).exclude() cls.decls(pd.access_type_matcher_t(pd.ACCESS_TYPES.PRIVATE), allow_empty=True).exclude() wrapper_needs = cls.is_wrapper_needed() if len(wrapper_needs): print "Finalize failed for: ", cls.name for x in wrapper_needs: print " ", x
def finalize(cls, finalize_pure_virtuals=False): """ Attempt to finalize a class by not exposing virtual methods. Still exposes in the case of pure virtuals otherwise the class could not be instantiated. """ if isinstance(cls, pd.mdecl_wrapper_t): for x in cls: finalize(x) else: matcher = pd.virtuality_type_matcher( pd.VIRTUALITY_TYPES.VIRTUAL ) if finalize_pure_virtuals: matcher = matcher | pd.virtuality_type_matcher( pd.VIRTUALITY_TYPES.PURE_VIRTUAL) members = cls.decls( matcher, decl_type=pd.member_calldef_t, allow_empty=True) members.set_virtuality( pd.VIRTUALITY_TYPES.NOT_VIRTUAL ) cls.decls(pd.access_type_matcher_t(pd.ACCESS_TYPES.PROTECTED),allow_empty=True).exclude() cls.decls(pd.access_type_matcher_t(pd.ACCESS_TYPES.PRIVATE),allow_empty=True).exclude() wrapper_needs = cls.is_wrapper_needed() if len(wrapper_needs): print "Finalize failed for: ", cls.name for x in wrapper_needs: print " ", x
def parse_class(self, class_decl): class_dict = {'name': class_decl.name, 'member_functions': []} if class_decl.bases: class_dict['bases'] = class_decl.bases[0].declaration_path constructors = [] # constructors constructors = [] query_methods = declarations.access_type_matcher_t('public') if hasattr(class_decl, 'constructors'): cotrs = class_decl.constructors(function=query_methods, allow_empty=True, recursive=False, header_file=self.target_file, name=class_decl.name) for cotr in cotrs: constructors.append(self.parse_function(cotr)) class_dict['constructors'] = constructors # class member functions member_functions = [] query_methods = declarations.access_type_matcher_t('public') if hasattr(class_decl, 'member_functions'): functions = class_decl.member_functions(function=query_methods, allow_empty=True, recursive=False, header_file=self.target_file) for fcn in functions: if str(fcn.name) not in [class_decl.name, '~'+class_decl.name]: member_functions.append(self.parse_function(fcn)) class_dict['member_functions'] = member_functions # enums class_enums = [] if hasattr(class_decl, 'variables'): enums = class_decl.enumerations( allow_empty=True, recursive=False, header_file=self.target_file) if enums: for _enum in enums: current_enum = {'name': _enum.name, 'values': _enum.values} class_enums.append(current_enum) class_dict['enums'] = class_enums # variables class_vars = [] query_methods = declarations.access_type_matcher_t('public') if hasattr(class_decl, 'variables'): variables = class_decl.variables(allow_empty=True, recursive=False, function=query_methods, header_file=self.target_file) if variables: for _var in variables: current_var = { 'name': _var.name, 'value': _var.value, "has_static": _var.has_static if hasattr(_var, 'has_static') else '0'} class_vars.append(current_var) class_dict['vars'] = class_vars return class_dict
def typeConversionsOutput(mem_fun,access_type): typedef_list=[] for td in mem_fun(function=declarations.access_type_matcher_t( access_type ),recursive=False): if (not td.is_artificial): # entityOutput(td) typedef_list.append(td) return typedef_list
def dataMembersOutput(mem_fun,access_type): typedef_list=[] for td in mem_fun(function=declarations.access_type_matcher_t( access_type ),recursive=False): typedef_list.append(td) # if (mem_fun.__name__ == 'variables'): # print('mangled:'+td.get_mangled_name()+'\n') return typedef_list
def emitClassMethods(c): global hSrc, cppSrc, chsSrc #chsSrc += '-- *** Constructors\n' query = declarations.access_type_matcher_t( 'public' ) #query = declarations.custom_matcher_t( lambda f: len(f.overloads) == 0) & declarations.access_type_matcher_t( 'public' ) if not c.is_abstract: tc = [] if c.find_trivial_constructor() != None: tc.append(c.find_trivial_constructor()) ok = False cons = [a for a in c.constructors(allow_empty=True, function=query, recursive = False) if not a.is_copy_constructor] if len(cons) == 1: emitConstructorBinding(c,cons[0]) else: cnt = 0 for mf in cons: # + tc: emitConstructorBinding(c,mf,str(cnt)) cnt += 1 emitDestructorBinding(c) #chsSrc += '-- *** Methods\n' methods = {} for mf in c.mem_funs(allow_empty=True, function=query, recursive = False): if methods.has_key(mf.name): methods[mf.name].append(mf) else: methods[mf.name] = [mf] for mname,mlist in methods.iteritems(): if len(mlist) == 1: emitMethodBinding(c,mlist[0]) # default method is the first one else: emitMethodBinding(c,mlist[0],'','0') cnt = 0 for mf in mlist: emitMethodBinding(c,mf,str(cnt),str(cnt)) cnt += 1
def test_and_matcher( self ): criteria1 = declarations.regex_matcher_t( 'oper.*' , lambda decl: decl.name ) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC ) found = declarations.matcher.find( criteria1 & criteria2, self.global_ns ) found = filter( lambda d: not d.is_artificial, found ) self.failUnless( len( found ) <= 6 )
def AutoExclude( mb ): """ Automaticaly exclude a range of things that don't convert well from C++ to Python """ global_ns = mb.global_ns for ns in NAMESPACES: main_ns = global_ns.namespace( ns ) # vars that are static consts but have their values set in the header file are bad Remove_Static_Consts ( main_ns ) ## Exclude protected and private that are not pure virtual query = declarations.access_type_matcher_t( 'private' ) \ & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) try: non_public_non_pure_virtual = main_ns.calldefs( query ) non_public_non_pure_virtual.exclude() except: pass #Virtual functions that return reference could not be overriden from Python query = declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.VIRTUAL ) \ & declarations.custom_matcher_t( lambda decl: declarations.is_reference( decl.return_type ) ) try: main_ns.calldefs( query ).virtuality = declarations.VIRTUALITY_TYPES.NOT_VIRTUAL except: pass
def test_access_type( self ): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC ) public_members = declarations.matcher.find( criteria, self.global_ns ) if '0.9' in public_members[0].compiler: public_members = filter( lambda d: not d.is_artificial, public_members ) self.failUnless( 16 == len( public_members ) ) else: self.failUnless( 20 == len( public_members ) )
def test_access_type( self ): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC ) public_members = declarations.matcher.find( criteria, self.declarations ) if '0.9' in public_members[0].compiler: #2 empty classes, this compiler doesn't generate constructor and copy constructor self.failUnless( 15 == len( public_members ) ) else: self.failUnless( 19 == len( public_members ) )
def test_and_matcher(self): criteria1 = declarations.regex_matcher_t('oper.*', lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find(criteria1 & criteria2, self.global_ns) found = [d for d in found if not d.is_artificial] self.assertTrue(len(found) <= 6)
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) if '0.9' in public_members[0].compiler: public_members = [d for d in public_members if not d.is_artificial] self.failUnless(17 == len(public_members)) else: self.failUnless(21 == len(public_members))
def test_and_matcher(self): criteria1 = declarations.regex_matcher_t('oper.*', lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find(criteria1 & criteria2, self.global_ns) found = filter(lambda d: not d.is_artificial, found) self.failUnless(len(found) <= 6)
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) if '0.9' in public_members[0].compiler: public_members = filter(lambda d: not d.is_artificial, public_members) self.failUnless(16 == len(public_members)) else: self.failUnless(20 == len(public_members))
def test_or_matcher( self ): criteria1 = declarations.regex_matcher_t( 'oper.*' , lambda decl: decl.name ) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC ) found = declarations.matcher.find( criteria1 | criteria2, self.declarations ) if '0.9' in found[0].compiler: #2 empty classes, this compiler doesn't generate constructor and copy constructor self.failUnless( 15 <= len( found ) <= 21) else: self.failUnless( 19 <= len( found ) <= 25)
def test_and_matcher(self): criteria1 = declarations.regex_matcher_t( 'oper.*', lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find( criteria1 & criteria2, self.global_ns) found = [d for d in found if not d.is_artificial] self.assertTrue(len(found) <= 6)
def test_or_matcher( self ): criteria1 = declarations.regex_matcher_t( 'oper.*' , lambda decl: decl.name ) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC ) found = declarations.matcher.find( criteria1 | criteria2, self.global_ns ) if '0.9' in found[0].compiler: found = filter( lambda d: not d.is_artificial, found ) self.failUnless( 15 <= len( found ) <= 21) else: self.failUnless( 19 <= len( found ) <= 25)
def filter_declarations( mb ): global_ns = mb.global_ns global_ns.exclude() ogrerefapp_ns = global_ns.namespace( 'OgreRefApp' ) ogrerefapp_ns.include() ## Exclude protected and private that are not pure virtual query = ~declarations.access_type_matcher_t( 'public' ) \ & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) non_public_non_pure_virtual = ogrerefapp_ns.calldefs( query ) non_public_non_pure_virtual.exclude()
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) if "CastXML" in utils.xml_generator: public_members = [d for d in public_members if not d.is_artificial] self.failUnless(21 == len(public_members)) if "0.9" in utils.xml_generator: public_members = [d for d in public_members if not d.is_artificial] self.failUnless(17 == len(public_members)) else: self.failUnless(21 == len(public_members))
def test_or_matcher(self): criteria1 = declarations.regex_matcher_t('oper.*', lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find(criteria1 | criteria2, self.global_ns) if '0.9' in found[0].compiler: found = filter(lambda d: not d.is_artificial, found) self.failUnless(15 <= len(found) <= 21) else: self.failUnless(19 <= len(found) <= 25)
def Auto_Document ( mb, namespace=None ): """Indicate that the functions being exposed are declated protected or private in the C++ code this should warn people to be careful using them :) """ global_ns = mb.global_ns if namespace: main_ns = global_ns.namespace( namespace ) else: main_ns = global_ns query = declarations.access_type_matcher_t( 'private' ) for c in main_ns.calldefs( query, allow_empty=True ): # print "PRIVATE:", c s = c.documentation if not s: s = "" c.documentation="Private declaration.\\n"+s query = declarations.access_type_matcher_t( 'protected' ) for c in main_ns.calldefs( query, allow_empty=True ): # print "PROTECTED:", c s = c.documentation if not s: s = "" c.documentation="Protected declaration.\\n"+s
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) public_members = [d for d in public_members if not d.is_artificial] if "CastXML" in utils.xml_generator: nbr = len(public_members) self.assertTrue(17 == nbr or 21 == nbr) if nbr == 21: # We are using llvm 3.9, see bug #32. Make sure the 4 names # are still there ll = ["isa", "flags", "str", "length"] for l in ll: self.assertTrue(l in [mbr.name for mbr in public_members]) else: self.assertTrue(17 == len(public_members))
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) public_members = [d for d in public_members if not d.is_artificial] if self.xml_generator_from_xml_file.is_castxml: nbr = len(public_members) self.assertTrue(nbr in [17, 21]) if nbr == 21: # We are using llvm 3.9, see bug #32. Make sure the 4 names # are still there ll = ["isa", "flags", "str", "length"] for l in ll: self.assertTrue(l in [mbr.name for mbr in public_members]) else: self.assertTrue(17 == len(public_members))
def test_or_matcher(self): criteria1 = declarations.regex_matcher_t("oper.*", lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find(criteria1 | criteria2, self.global_ns) if "CastXML" in utils.xml_generator: found = [d for d in found if not d.is_artificial] self.assertTrue(len(found) != 35) elif "0.9" in utils.xml_generator: found = [d for d in found if not d.is_artificial] self.assertTrue(15 <= len(found) <= 21) else: self.assertTrue(19 <= len(found) <= 25)
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) public_members = [d for d in public_members if not d.is_artificial] if self.xml_generator_from_xml_file.is_castxml: nbr = len(public_members) self.assertTrue(nbr in [17, 21]) if nbr == 21: # We are using llvm 3.9, see bug #32. Make sure the 4 names # are still there names = ["isa", "flags", "str", "length"] for name in names: self.assertTrue( names in [mbr.name for mbr in public_members]) else: self.assertTrue(17 == len(public_members))
def test_or_matcher(self): criteria1 = declarations.regex_matcher_t("oper.*", lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find(criteria1 | criteria2, self.global_ns) if self.xml_generator_from_xml_file.is_castxml: found = [d for d in found if not d.is_artificial] self.assertTrue(len(found) != 35) elif self.xml_generator_from_xml_file.is_gccxml_09 or \ self.xml_generator_from_xml_file.is_gccxml_09_buggy: found = [d for d in found if not d.is_artificial] self.assertTrue(15 <= len(found) <= 21) else: self.assertTrue(19 <= len(found) <= 25)
def test_or_matcher(self): criteria1 = declarations.regex_matcher_t( "oper.*", lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find( criteria1 | criteria2, self.global_ns) if "CastXML" in utils.xml_generator: found = [d for d in found if not d.is_artificial] self.assertTrue(len(found) != 35) elif "0.9" in utils.xml_generator: found = [d for d in found if not d.is_artificial] self.assertTrue(15 <= len(found) <= 21) else: self.assertTrue(19 <= len(found) <= 25)
def test_or_matcher(self): criteria1 = declarations.regex_matcher_t( "oper.*", lambda decl: decl.name) criteria2 = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) found = declarations.matcher.find( criteria1 | criteria2, self.global_ns) if self.xml_generator_from_xml_file.is_castxml: found = [d for d in found if not d.is_artificial] self.assertTrue(len(found) != 35) elif self.xml_generator_from_xml_file.is_gccxml_09 or \ self.xml_generator_from_xml_file.is_gccxml_09_buggy: found = [d for d in found if not d.is_artificial] self.assertTrue(15 <= len(found) <= 21) else: self.assertTrue(19 <= len(found) <= 25)
def filter_declarations( mb ): """ filter class declarations """ global_ns = mb.global_ns global_ns.exclude() #global_ns.namespace('std').class_('pair<float, float>').include() MyGUI_ns = global_ns.namespace( 'MyGUI' ) MyGUI_ns.include() global_ns.namespace( 'Ogre' ).class_('SharedPtr<Ogre::Resource>').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('HardwarePixelBufferSharedPtr').include(already_exposed=True) global_ns.namespace( 'OIS' ).class_('KeyEvent').include(already_exposed=True) global_ns.namespace( 'OIS' ).class_('MouseEvent').include(already_exposed=True) # Exclude protected and private that are not pure virtual query = declarations.access_type_matcher_t( 'private' ) \ & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) MyGUI_ns.calldefs( query, allow_empty=True ).exclude()
def _test_class_membership(self, class_inst, enum_name, access): # getting enum through get_members function nested_enum1 = class_inst.enum( name=enum_name, function=declarations.access_type_matcher_t(access)) # getting enum through declarations property nested_enum2 = class_inst.enum(enum_name) # it shoud be same object self.assertTrue(nested_enum1 is nested_enum2, ("enum accessed through access definition('%s') and " + "through declarations('%s') are different enums " + "or instances.") % (nested_enum1.name, nested_enum2.name)) # check whether we meaning same class instance self.assertTrue( class_inst is nested_enum1.parent is nested_enum2.parent, 'There are 2 or more instances of ns namespace.')
def _test_class_membership(self, class_inst, enum_name, access): # getting enum through get_members function nested_enum1 = class_inst.enum( name=enum_name, function=declarations.access_type_matcher_t(access)) # getting enum through declarations property nested_enum2 = class_inst.enum(enum_name) # it shoud be same object self.failUnless( nested_enum1 is nested_enum2, ("enum accessed through access definition('%s') and " + "through declarations('%s') are different enums " + "or instances.") % (nested_enum1.name, nested_enum2.name)) # check whether we meaning same class instance self.failUnless( class_inst is nested_enum1.parent is nested_enum2.parent, 'There are 2 or more instances of ns namespace.')
def _process_methods(self): if not self.methods_: query = declarations.access_type_matcher_t("public") hierarchy = self.gcc.recursive_bases cls_decls = self.gcc.decls(function=query) base_decls = [ c.related_class.decls(function=query, allow_empty=True) for c in hierarchy if c.access_type == "public" ] for m in iter_seq([cls_decls] + base_decls): if isinstance(m, declarations.enumeration.enumeration_t): try: e = create_decl(m, self.doxyindex, self.opts) except RuntimeError: pass # ok - not found by doxygen mechanism else: if e.is_exported(): raise RuntimeError("Enum '%s' within class '%s' - not allowed." % (m.name, self.gcc.name)) elif isinstance(m, declarations.calldef.member_function_t): if m.virtuality != "pure virtual": raise RuntimeError("'%s' is not virtual" % m) dm = create_decl(m, self.doxyindex, self.opts) if dm.is_exported(): self.methods_.add(dm) else: self.internal_methods_.add(dm) # this is needed as methods in base classes need to know # the class they belong to in the generated (flat) hierarchy dm.gcc_leaf_class = self.gcc else: if not isinstance( m, ( declarations.calldef.constructor_t, declarations.calldef.destructor_t, declarations.calldef.member_operator_t, ), ): raise RuntimeError( "Unknown declaration '%s' of type '%s' within class '%s'." % (m.name, m, self.gcc.name) )
def emitClassMethods(c): global hSrc, cppSrc, chsSrc #chsSrc += '-- *** Constructors\n' query = declarations.access_type_matcher_t('public') #query = declarations.custom_matcher_t( lambda f: len(f.overloads) == 0) & declarations.access_type_matcher_t( 'public' ) if not c.is_abstract: tc = [] if c.find_trivial_constructor() != None: tc.append(c.find_trivial_constructor()) ok = False cons = [ a for a in c.constructors( allow_empty=True, function=query, recursive=False) if not a.is_copy_constructor ] if len(cons) == 1: emitConstructorBinding(c, cons[0]) else: cnt = 0 for mf in cons: # + tc: emitConstructorBinding(c, mf, str(cnt)) cnt += 1 emitDestructorBinding(c) #chsSrc += '-- *** Methods\n' methods = {} for mf in c.mem_funs(allow_empty=True, function=query, recursive=False): if methods.has_key(mf.name): methods[mf.name].append(mf) else: methods[mf.name] = [mf] for mname, mlist in methods.iteritems(): if len(mlist) == 1: emitMethodBinding(c, mlist[0]) # default method is the first one else: emitMethodBinding(c, mlist[0], '', '0') cnt = 0 for mf in mlist: emitMethodBinding(c, mf, str(cnt), str(cnt)) cnt += 1
def _process_methods(self): if not self.methods_: query = declarations.access_type_matcher_t('public') hierarchy = self.gcc.recursive_bases cls_decls = self.gcc.decls(function=query) base_decls = [ c.related_class.decls(function=query, allow_empty=True) for c in hierarchy if c.access_type == 'public' ] for m in iter_seq([cls_decls] + base_decls): if isinstance(m, declarations.enumeration.enumeration_t): try: e = create_decl(m, self.doxyindex, self.opts) except RuntimeError: pass # ok - not found by doxygen mechanism else: if e.is_exported(): raise RuntimeError( "Enum '%s' within class '%s' - not allowed." % (m.name, self.gcc.name)) elif isinstance(m, declarations.calldef.member_function_t): if m.virtuality != 'pure virtual': raise RuntimeError("'%s' is not virtual" % m) dm = create_decl(m, self.doxyindex, self.opts) if dm.is_exported(): self.methods_.add(dm) else: self.internal_methods_.add(dm) # this is needed as methods in base classes need to know # the class they belong to in the generated (flat) hierarchy dm.gcc_leaf_class = self.gcc else: if not isinstance( m, (declarations.calldef.constructor_t, declarations.calldef.destructor_t, declarations.calldef.member_operator_t)): raise RuntimeError( "Unknown declaration '%s' of type '%s' within class '%s'." % (m.name, m, self.gcc.name))
def exclude_protected(cls): """ Exclude all protected declarations. """ cls.decls(pd.access_type_matcher_t(pd.ACCESS_TYPES.PROTECTED),allow_empty=True).exclude()
def test_access_type(self): criteria = declarations.access_type_matcher_t( declarations.ACCESS_TYPES.PUBLIC) public_members = declarations.matcher.find(criteria, self.global_ns) public_members = [d for d in public_members if not d.is_artificial] self.assertTrue(17 == len(public_members))
def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # print paths as matrices self.replace_member_functions( self.ompl_ns.member_functions('printAsMatrix')) # print debug info self.replace_member_functions( self.ompl_ns.member_functions('printDebug')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions( 'maybeConstructSolution').exclude() self.ompl_ns.class_('PRM').member_functions( 'growRoadmap', function=declarations.access_type_matcher_t( 'protected')).exclude() self.ompl_ns.class_('PRM').member_functions( 'expandRoadmap', function=declarations.access_type_matcher_t( 'protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # add wrappers for boost::function types self.add_boost_function('unsigned int()', 'NumNeighborsFn', 'Number of neighbors function') # self.add_boost_function('std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_boost_function( 'bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_( 'SimpleSetup' ).add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)' ) self.ompl_ns.namespace('geometric').class_( 'SimpleSetup' ).add_registration_code( 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())' ) # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a known limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.member_function('solve').exclude() PRM_cls.add_wrapper_code(""" virtual ::ompl::base::PlannerStatus solve( ::ompl::base::PlannerTerminationCondition const & ptc ) { if( bp::override func_solve = this->get_override( "solve" ) ) return func_solve( boost::ref(ptc) ); else{ return default_solve( boost::ref(ptc) ); } } ::ompl::base::PlannerStatus default_solve( ::ompl::base::PlannerTerminationCondition const & ptc ); """) PRM_cls.add_declaration_code( open('PRM.SingleThreadSolve.cpp', 'r').read()) PRM_cls.add_registration_code("""def("solve", (::ompl::base::PlannerStatus(::ompl::geometric::PRM::*)( ::ompl::base::PlannerTerminationCondition const &))(&PRM_wrapper::solve), (::ompl::base::PlannerStatus(PRM_wrapper::*)( ::ompl::base::PlannerTerminationCondition const & ))(&PRM_wrapper::default_solve), bp::arg("ptc") )""" ) # exclude PRM*, define it in python to use the single-threaded version # of PRM with the k* connection strategy self.ompl_ns.class_('PRMstar').exclude() # LazyPRM's Vertex type is void* so exclude addMilestone which has return type void* self.ompl_ns.class_('LazyPRM').member_function( 'addMilestone').exclude() # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in [ 'EST', 'KPIECE1', 'BKPIECE1', 'LBKPIECE1', 'PRM', 'LazyPRM', 'PDST', 'LazyRRT', 'RRT', 'RRTConnect', 'TRRT', 'RRTstar', 'LBTRRT', 'SBL', 'SPARS', 'SPARStwo', 'STRIDE', 'FMT', 'BITstar' ]: self.ompl_ns.class_(planner).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )""" ) if planner != 'PRM': # PRM overrides setProblemDefinition, so we don't need to add this code self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner) # do this for all multithreaded planners for planner in ['SPARS', 'SPARStwo']: cls = self.ompl_ns.class_(planner) cls.constructor( arg_types=["::ompl::base::SpaceInformationPtr const &" ]).exclude() cls.add_registration_code( 'def(bp::init<ompl::base::SpaceInformationPtr const &>(bp::arg("si")))' ) cls.add_wrapper_code(""" {0}_wrapper(::ompl::base::SpaceInformationPtr const &si) : ompl::geometric::{0}(si), bp::wrapper<ompl::geometric::{0}>() {{ OMPL_WARN("%s: this planner uses multiple threads and might crash if your StateValidityChecker, OptimizationObjective, etc., are allocated within Python.", getName().c_str()); }} """.format(planner)) # used in SPARS self.std_ns.class_('deque<ompl::base::State*>').rename('dequeState') # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This can # be equal to an unsigned long or unsigned int, depending on architecture (or version of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename( 'NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>' ).rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename( 'KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned long, ompl::base::State*>' ).rename('mapVertexToState') except: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename( 'NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename( 'NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename( 'KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned int, ompl::base::State*>').rename( 'mapVertexToState')
def generate(defined_symbols, extraIncludes): messages.disable( messages.W1005 # using a non public variable type for arguments or returns , messages.W1006 # `Py++` need your # help to expose function that takes > as argument/returns C++ arrays. # Take a look on "Function Transformation" > functionality and define # the transformation. , messages.W1007 # more than 10 args -> BOOST_PYTHON_MAX_ARITY is set , messages.W1009 # execution error W1009: The function takes as argument (name=pFunIdx, pos=1) > # non-const reference to Python immutable type - function could not be called > from Python , messages.W1014 # "operator*" is not supported. See , messages.W1016 # `Py++` does not exports non-const casting operators # Warnings 1020 - 1031 are all about why Py++ generates wrapper for class X , messages.W1023 # Py++` will generate class wrapper - there are few functions that should be # redefined in class wrapper , messages.W1025 # `Py++` will generate class wrapper - class contains "c_" - T* > member variable , messages.W1026 # `Py++` will generate class wrapper - class contains "arr_" - T& > member variable , messages.W1027 # `Py++` will generate class wrapper - class contains "mat_" - > array member variable , messages.W1035 # error. `Py++` can not expose static pointer member variables. , messages.W1036 # error. `Py++` can not expose pointer to Python immutable > member variables. This # could be changed in future. , messages.W1040 # error. The declaration is unexposed, but there are other > declarations, which # refer to it. This could cause "no to_python converter > found" run # time error # This is serious and lead to RuntimeError: `Py++` is going to write different content to the same file , messages.W1047 # There are two or more classes that use same > alias("MatElement"). Duplicated aliases causes # few problems, but the main one > is that some of the classes will not # be exposed to Python.Other classes : > , messages.W1049 # This method could not be overriden in Python - method returns > # reference to local variable! , messages.W1052 # `Py++` will not expose free operator ) logger.debug("Install SRC: ", os.path.abspath(__file__)) logger.debug("Execute from: ", os.getcwd()) sourcedir = os.path.dirname(os.path.abspath(__file__)) sourceHeader = os.path.abspath(sourcedir + "/" + r"pygimli.h") gimliInclude = os.path.dirname( os.path.abspath(sourcedir + "/../src/" + r"gimli.h")) settings.includesPaths.append(gimliInclude) xml_cached_fc = parser.create_cached_source_fc( sourceHeader, settings.module_name + '.cache') #xml_cached_fc = parser.create_cached_source_fc(os.path.join(r"pygimli.h"), settings.module_name + '.cache') import platform defines = ['PYGIMLI_CAST', 'HAVE_BOOST_THREAD_HPP'] caster = 'gccxml' if platform.architecture()[ 0] == '64bit' and platform.system() == 'Windows': if sys.platform == 'darwin': pass else: defines.append('_WIN64') logger.info('Marking win64 for gccxml') for define in [settings.gimli_defines, defined_symbols]: if len(define) > 0: defines.append(define) try: if sys.platform == 'win32': # os.name == 'nt' (default on my mingw) results in wrong commandline # for gccxml os.name = 'mingw' casterpath = settings.caster_path.replace('\\', '\\\\') casterpath = settings.caster_path.replace('/', '\\') if not 'gccxml' in casterpath: caster = 'castxml' if not '.exe' in casterpath: casterpath += '\\' + caster + '.exe' else: casterpath = settings.caster_path if not 'gccxml' in casterpath: caster = 'castxml' except Exception as e: logger.info("caster_path=%s" % casterpath) logger.info(str(e)) raise Exception("Problems determine castxml binary") settings.includesPaths.insert(0, os.path.abspath(extraIncludes)) logger.info("caster_path=%s" % casterpath) logger.info("working_directory=%s" % settings.gimli_path) logger.info("include_paths=%s" % settings.includesPaths) logger.info("define_symbols=%s" % defines) logger.info("indexing_suite_version=2") mb = module_builder.module_builder_t([xml_cached_fc], gccxml_path=casterpath, working_directory=settings.gimli_path, include_paths=settings.includesPaths, define_symbols=defines, indexing_suite_version=2, caster=caster ) logger.info("Reading of c++ sources done.") mb.classes().always_expose_using_scope = True mb.calldefs().create_with_signature = True global_ns = mb.global_ns global_ns.exclude() main_ns = global_ns.namespace(MAIN_NAMESPACE) main_ns.include() #for c in main_ns.free_functions(): ##print(c) #if 'pow' in c.name: #print(c) #print(c.name) ##if c.decl_string.startswith('::GIMLI::pow'): ##print(c) ##print(c.name) #sys.exit() logger.info("Apply handmade wrappers.") hand_made_wrappers.apply(mb) logger.info("Apply custom rvalues.") # START manual r-value converters rvalue_converters = [ 'register_pytuple_to_rvector3_conversion', 'register_pysequence_to_rvector_conversion', #'register_pysequence_to_bvector_conversion', 'register_pysequence_to_indexvector_conversion', 'register_pysequence_to_r3vector_conversion', 'register_pysequence_to_StdVectorRVector3_conversion', #'register_rvector_to_ndarray_conversion', ] for converter in rvalue_converters: mb.add_declaration_code('void %s();' % converter) mb.add_registration_code('%s();' % converter) # END manual r-value converters custom_rvalue_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'custom_rvalue.cpp') logger.info("Starting to exclude stuff that we don't need or that is known to be spurious.") exclude(main_ns.variables, name=[ 'Triangle6_S1', 'Triangle6_S2', 'Triangle6_S3', 'HexahedronFacesID', 'Hexahedron20FacesID', 'TetrahedronFacesID', 'HexahedronSplit5TetID', 'HexahedronSplit6TetID', 'TriPrismFacesID', 'TriPrimSplit3TetID', 'NodeCoordinates', 'EdgeCoordinates', 'TriCoordinates', 'QuadCoordinates', 'TetCoordinates', 'HexCoordinates', 'PrismCoordinates', 'PyramidCoordinates', 'PyramidFacesID', 'Tet10NodeSplit', 'Tet10NodeSplitZienk', 'Hex20NodeSplit', 'Prism15NodeSplit', 'Pyramid13NodeSplit' ] ) exclude(main_ns.free_functions, return_type=[ 'float *', 'float &', "::GIMLI::__VectorExpr< double, GIMLI::__VectorUnaryExprOp< double, GIMLI::VectorIterator< double >, GIMLI::ABS_ > >"], name=[ 'strReplaceBlankWithUnderscore', 'toStr', 'toInt', 'toFloat', 'toDouble', 'str', 'getRowSubstrings', 'getNonEmptyRow', 'getSubstrings', 'abs', 'type'] ) exclude(main_ns.free_operators, name=[''], return_type=['::std::ostream &', '::std::istream &'] ) exclude(main_ns.classes, name=['ABS_', 'ACOT', 'ATAN', 'COS', 'COT', 'EXP', 'ABS_', 'LOG', 'LOG10', 'SIGN', 'SIN', 'SQRT', 'SQR', 'TAN', 'TANH', 'PLUS', 'MINUS', 'MULT', 'DIVID', 'BINASSIGN', 'cerrPtr', 'cerrPtrObject', 'coutPtr', 'coutPtrObject', 'deletePtr', 'edge_', 'distancePair_', 'IPCMessage', 'PythonGILSave', ] ) exclude(main_ns.member_functions, name=['begin', 'end', 'val'], return_type=[''] ) exclude(main_ns.member_operators, symbol=['']) for f in main_ns.declarations: if isinstance(f, decl_wrappers.calldef_wrapper.free_function_t): if (str(f.return_type).find('GIMLI::VectorExpr') != -1): f.exclude() ex = ['::GIMLI::MatrixElement', '::GIMLI::__VectorUnaryExprOp', '::GIMLI::__VectorBinaryExprOp', '::GIMLI::__ValVectorExprOp', '::GIMLI::__VectorValExprOp', '::GIMLI::__VectorExpr', '::GIMLI::Expr', '::GIMLI::InversionBase', 'GIMLI::MatrixElement', 'GIMLI::__VectorUnaryExprOp', 'GIMLI::__VectorBinaryExprOp', 'GIMLI::__ValVectorExprOp', 'GIMLI::__VectorValExprOp', 'GIMLI::__VectorExpr', 'GIMLI::Expr', 'GIMLI::InversionBase', 'std::vector<unsigned long', ] for c in main_ns.free_functions(): for e in ex: if c.decl_string.find(e) > -1: try: c.exclude() logger.debug("Exclude: " + str(c)) except: logger.debug("Fail to exclude: " + str(c)) for c in main_ns.classes(): for e in ex: if c.decl_string.startswith(e): try: c.exclude() logger.debug("Exclude: " + c.name) except: logger.debug("Fail to exclude: " + c.name) try: for mem in c.constructors(): for e in ex: if mem.decl_string.find(e) > -1: try: mem.exclude() #logger.info("Exclude: " + str(mem)) except: logger.debug("Fail to exclude: " + str(mem)) for mem in c.member_functions(): for e in ex: if mem.decl_string.find(e) > -1: try: mem.exclude() #logger.info("Exclude: " + str(mem)) except: logger.debug("Fail to exclude: " + str(mem)) except: #print(c, "has no member functions") pass #print('#'*100) #print(c, c.name) if c.name.startswith('Vector<unsigned long>'): #print(' ', c.name) for mem in c.constructors(): #print("mem", mem, mem.decl_string) if mem.decl_string.find('( ::GIMLI::Index )') > -1: logger.debug("Exclude: " + str(mem)) mem.exclude() #print("mem", mem) mb.calldefs(access_type_matcher_t('protected')).exclude() mb.calldefs(access_type_matcher_t('private')).exclude() # setMemberFunctionCallPolicieByReturn(mb, [ '::GIMLI::Node &' #, '::GIMLI::Cell &' #, '::GIMLI::Boundary &' #, '::GIMLI::Shape &' #, '::GIMLI::Node *' #, '::GIMLI::Cell *' #, '::GIMLI::Boundary *' #, '::GIMLI::Shape *' #] #, call_policies.reference_existing_object) setMemberFunctionCallPolicieByReturn( mb, ['::std::string *', 'float *', 'double *', 'int *', 'long *', 'long int *', 'long long int *', 'unsigned int *', 'long unsigned int *', 'unsigned long long int *', '::GIMLI::Index *', '::GIMLI::SIndex *', 'bool *'], call_policies.return_pointee_value) setMemberFunctionCallPolicieByReturn(mb, ['::std::string &', 'float &', 'double &', 'int &', 'long &', 'long int &', 'long long int &', 'unsigned int &', 'long unsigned int &', 'unsigned long long int &', '::GIMLI::Index &', '::GIMLI::SIndex &', 'bool &' ], call_policies.return_by_value) # setMemberFunctionCallPolicieByReturn(mb, ['::GIMLI::VectorIterator<double> &'] #, call_policies.copy_const_reference) # setMemberFunctionCallPolicieByReturn(mb, [ #, 'double &' ] #, call_policies.reference_existing_object) # call_policies.return_value_policy(call_policies.reference_existing_object) # call_policies.return_value_policy(call_policies.copy_non_const_reference) # call_policies.return_value_policy(call_policies.copy_const_reference) # addAutoConversions(mb) # excludeMemberByReturn(main_ns, ['::DCFEMLib::SparseMatrix<double> &']) #main_ns.classes(decl_starts_with(['STLMatrix']), allow_empty=True).exclude() #fun = mb.global_ns.member_functions('begin', allow_empty=True) # for f in fun: # f.exclude() # excludeFreeFunctionsByName(main_ns, ['strReplaceBlankWithUnderscore' #'toStr', 'toInt', 'toFloat', 'toDouble', #'getRowSubstrings', 'getNonEmptyRow', 'getSubstrings' ]) #excludeFreeFunctionsByReturn(main_ns, [ 'float *', 'float &' ]) #fun = ns.free_operators(return_type=funct, allow_empty=True) #excludeMemberOperators(main_ns, ['++', '--', '*']) # exclude all that does not match any predefined callpolicie excludeRest = True if excludeRest: mem_funs = mb.calldefs() for mem_fun in mem_funs: if mem_fun.call_policies: continue if not mem_fun.call_policies and \ (declarations.is_reference(mem_fun.return_type) or declarations.is_pointer(mem_fun.return_type)): # print mem_fun # mem_fun.exclude() mem_fun.call_policies = call_policies.return_value_policy( call_policies.reference_existing_object) # mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.return_pointee_value) # mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.return_opaque_pointer) # mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.copy_non_const_reference) logger.info("Create api documentation from Doxgen comments.") # Now it is the time to give a name to our module from doxygen import doxygen_doc_extractor extractor = doxygen_doc_extractor() logger.info("Create code creator.") mb.build_code_creator(settings.module_name, doc_extractor=extractor) # It is common requirement in software world - each file should have license #mb.code_creator.license = '//Boost Software License(http://boost.org/more/license_info.html)' # I don't want absolute includes within code mb.code_creator.user_defined_directories.append(os.path.abspath('.')) # And finally we can write code to the disk def ignore(val): pass logger.info("Create bindings code.") mb.split_module('./generated', on_unused_file_found=ignore) additional_files = [ os.path.join( os.path.abspath(os.path.dirname(__file__)), 'custom_rvalue.cpp'), os.path.join( os.path.abspath(os.path.dirname(__file__)), 'generators.h'), os.path.join( os.path.abspath(os.path.dirname(__file__)), 'tuples.hpp')] logger.info("Add additional files.") for sourcefile in additional_files: p, filename = os.path.split(sourcefile) destfile = os.path.join('./generated', filename) if not samefile(sourcefile, destfile): shutil.copy(sourcefile, './generated') logger.info("Updated " + filename + "as it was missing or out of date")
print 'exclude <template>', m return False if isInPublicScope(m): return True else: print 'exclude', m return False else: print 'exclude', m return False classList = sorted( global_ns.classes(header_dir=this_module_dir_path, function=declarations.custom_matcher_t(matcherFun) & (~(declarations.access_type_matcher_t('private') | declarations.access_type_matcher_t('protected')))), key=attrgetter('name')) enumList = sorted(global_ns.enums(header_dir=this_module_dir_path), key=attrgetter('name')) tyNone = 0 tyPrim = 1 tyGlue = 2 tyObj = 3 def isGlueType(ty): ty = declarations.type_traits.remove_reference( declarations.type_traits.remove_cv(ty)) ty = declarations.type_traits.remove_cv(ty)
def get_header_info(self): """ PyGCCXML header code parser magic happens here! : returns the parsed header data in python dict : return dict keys: namespace, class, io_signature, make, properties, methods : Can be used as an CLI command or an external API """ gr = self.modname.split('-')[0] module = self.modname.split('-')[-1] self.parsed_data['module_name'] = module generator_path, generator_name = utils.find_xml_generator() xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, include_paths=self.include_paths, compiler='gcc', define_symbols=['BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_GENERIC'], cflags='-std=c++11') decls = parser.parse([self.target_file], xml_generator_config) global_namespace = declarations.get_global_namespace(decls) # namespace try: self.parsed_data['namespace'] = [] ns = global_namespace.namespace(gr) if ns is None: raise BlockToolException main_namespace = ns.namespace(module) if main_namespace is None: raise BlockToolException('namespace cannot be none') self.parsed_data['namespace'] = [gr, module] if main_namespace.declarations: for _namespace in main_namespace.declarations: if isinstance(_namespace, declarations.namespace_t): if Constants.KERNEL not in str(_namespace): main_namespace = _namespace self.parsed_data['namespace'].append( str(_namespace).split('::')[-1].split(' ')[0]) except RuntimeError: raise BlockToolException( 'Invalid namespace format in the block header file') # class try: self.parsed_data['class'] = '' for _class in main_namespace.declarations: if isinstance(_class, declarations.class_t): expected_class_name = self.filename.split('.')[0] if expected_class_name in str(_class): main_class = _class self.parsed_data['class'] = str(_class).split( '::')[2].split(' ')[0] # in more complicated blocks, there are many classes included in this declaration # Break after the first class - safe to assume this is the "main class"? if len(main_class.bases) > 0: self.parsed_data['block_type'] = main_class.bases[ 0].declaration_path[-1] break except RuntimeError: raise BlockToolException( 'Block header namespace {} must consist of a valid class instance' .format(module)) # io_signature, message_ports self.parsed_data['io_signature'] = {} self.parsed_data['message_port'] = {} if os.path.isfile(self.impl_file) and exist_comments(self): self.parsed_data['io_signature'] = io_signature(self.impl_file) self.parsed_data['message_port'] = message_port(self.impl_file) read_comments(self) elif os.path.isfile(self.impl_file) and not exist_comments(self): self.parsed_data['io_signature'] = io_signature(self.impl_file) self.parsed_data['message_port'] = message_port(self.impl_file) if self.addcomments: add_comments(self) elif not os.path.isfile(self.impl_file) and exist_comments(self): read_comments(self) else: self.parsed_data['io_signature'] = {"input": [], "output": []} self.parsed_data['message_port'] = self.parsed_data['io_signature'] # make try: self.parsed_data['make'] = {} self.parsed_data['make']['arguments'] = [] query_m = declarations.custom_matcher_t( lambda mem_fun: mem_fun.name.startswith('make')) query_make = query_m & declarations.access_type_matcher_t('public') make_func = main_class.member_functions( function=query_make, allow_empty=True, header_file=self.target_file) criteria = declarations.calldef_matcher(name='make') _make_fun = declarations.matcher.get_single(criteria, main_class) _make_fun = str(_make_fun).split('make')[-1].split(')')[0].split( '(')[1].lstrip().rstrip().split(',') if make_func: for arg in make_func[0].arguments: make_arguments = None ''' for _arg in _make_fun: if str(arg.name) in _arg: make_arguments = { "name": str(arg.name), "dtype": str(arg.decl_type), "default": "" } if re.findall(r'[-+]?\d*\.\d+|\d+', _arg): make_arguments['default'] = re.findall( r'[-+]?\d*\.\d+|\d+', _arg)[0] elif re.findall(r'\"(.+?)\"', _arg): make_arguments['default'] = re.findall( r'\"(.+?)\"', _arg)[0] elif "true" in _arg: make_arguments['default'] = "True" elif "false" in _arg: make_arguments['default'] = "False" ''' # In case the search did not find an argument in the inner loop # This happens while parsing digital/symbol_sync_cc.h if make_arguments: self.parsed_data['make']['arguments'].append( make_arguments.copy()) else: self.parsed_data['make']['arguments'].append({ "name": str(arg.name), "dtype": str(arg.decl_type), "default": arg. default_value # can we get default argument directly from arg }) except RuntimeError: self.parsed_data['make'] = {} self.parsed_data['make']['arguments'] = [] # setters try: self.parsed_data['methods'] = [] query_methods = declarations.access_type_matcher_t('public') setters = main_class.member_functions(function=query_methods, allow_empty=True, header_file=self.target_file) getter_arguments = [] if setters: for setter in setters: if str(setter.name).startswith( 'set_') and setter.arguments: setter_args = { "name": str(setter.name), "arguments_type": [] } for argument in setter.arguments: args = { "name": str(argument.name), "dtype": str(argument.decl_type) } getter_arguments.append(args['name']) setter_args['arguments_type'].append(args.copy()) self.parsed_data['methods'].append(setter_args.copy()) except RuntimeError: self.parsed_data['methods'] = [] # getters try: self.parsed_data['properties'] = [] query_properties = declarations.access_type_matcher_t('public') getters = main_class.member_functions(function=query_properties, allow_empty=True, header_file=self.target_file) if getters: for getter in getters: if not getter.arguments or getter.has_const: getter_args = { "name": str(getter.name), "dtype": str(getter.return_type), "read_only": True } if getter_args['name'] in getter_arguments: getter_args["read_only"] = False self.parsed_data['properties'].append( getter_args.copy()) except RuntimeError: self.parsed_data['properties'] = [] # all member functions # setters and getters do not return all member functions for a block try: self.parsed_data['member_functions'] = [] query_methods = declarations.access_type_matcher_t('public') functions = main_class.member_functions( function=query_methods, allow_empty=True, header_file=self.target_file) if functions: for fcn in functions: if str(fcn.name) not in [ main_class.name, '~' + main_class.name, 'make' ]: fcn_args = {"name": str(fcn.name), "arguments": []} for argument in fcn.arguments: args = { "name": str(argument.name), "dtype": str(argument.decl_type), "default": argument.default_value } fcn_args['arguments'].append(args.copy()) self.parsed_data['member_functions'].append( fcn_args.copy()) except RuntimeError: self.parsed_data['member_functions'] = [] # documentation try: _index = None header_file = codecs.open(self.target_file, 'r', 'cp932') self.parsed_data['docstring'] = re.compile( r'//.*?$|/\*.*?\*/', re.DOTALL | re.MULTILINE).findall(header_file.read())[2:] header_file.close() for doc in self.parsed_data['docstring']: if Constants.BLOCKTOOL in doc: _index = self.parsed_data['docstring'].index(doc) if _index is not None: self.parsed_data['docstring'] = self.parsed_data[ 'docstring'][:_index] except: self.parsed_data['docstring'] = [] return self.parsed_data
def exclude_protected(cls): """ Exclude all protected declarations. """ cls.decls(pd.access_type_matcher_t(pd.ACCESS_TYPES.PROTECTED), allow_empty=True).exclude()
def generate(defined_symbols, extraIncludes): # messages.disable( # messages.W1005 # using a non public variable type for argucments or returns ## Warnings 1020 - 1031 are all about why Py++ generates wrapper for class X # , messages.W1009 # check this # , messages.W1014 # check this # , messages.W1020 # , messages.W1021 # , messages.W1022 # , messages.W1023 # , messages.W1024 # , messages.W1025 # , messages.W1026 # , messages.W1027 # , messages.W1028 # , messages.W1029 # , messages.W1030 # , messages.W1031 # , messages.W1036 # check this #) print("Install SRC: ", os.path.abspath(__file__)) print("Execute from: ", os.getcwd()) sourcedir = os.path.dirname(os.path.abspath(__file__)) sourceHeader = os.path.abspath(sourcedir + "/" + r"pygimli.h") gimliInclude = os.path.dirname(os.path.abspath(sourcedir + "/../src/" + r"gimli.h")) settings.includesPaths.append(gimliInclude) xml_cached_fc = parser.create_cached_source_fc(sourceHeader, settings.module_name + '.cache') #xml_cached_fc = parser.create_cached_source_fc(os.path.join(r"pygimli.h"), settings.module_name + '.cache') import platform defines = ['PYGIMLI_GCCXML', 'HAVE_BOOST_THREAD_HPP'] if platform.architecture()[0] == '64bit' and platform.architecture()[1] != 'ELF': if sys.platform == 'darwin': pass else: defines.append('_WIN64') print('Marking win64 for gccxml') for define in [settings.gimli_defines, defined_symbols]: if len(define) > 0: defines.append(define) try: if sys.platform == 'win32': #os.name == 'nt' (default on my mingw) results in wrong commandline for gccxml os.name = 'mingw' gccxmlpath = settings.gccxml_path.replace('\\', '\\\\') + '\\\\gccxml.exe' else: gccxmlpath = settings.gccxml_path except Exception as e: print (str(e)) raise Exception("Problems determine gccxml binary") settings.includesPaths.insert(0,os.path.abspath(extraIncludes)) print("gccxml-binary: ", gccxmlpath) print("extra-include: ", os.path.abspath(extraIncludes)) print("gccxml includes: ", settings.includesPaths) print("gccxml defines: ", defines) mb = module_builder.module_builder_t([xml_cached_fc], gccxml_path=gccxmlpath, working_directory=settings.gimli_path, include_paths=settings.includesPaths, define_symbols=defines, indexing_suite_version=2) mb.classes().always_expose_using_scope = True mb.calldefs().create_with_signature = True hand_made_wrappers.apply(mb) global_ns = mb.global_ns global_ns.exclude() main_ns = global_ns.namespace(MAIN_NAMESPACE) main_ns.include() ### START manual r-value converters rvalue_converters = [ 'register_pysequence_to_StdVectorUL_conversion', 'register_pytuple_to_rvector3_conversion', 'register_pysequence_to_rvector_conversion', 'register_pysequence_to_StdVectorRVector3_conversion' ] for converter in rvalue_converters: mb.add_declaration_code('void %s();' % converter) mb.add_registration_code('%s();' % converter) ### END manual r-value converters custom_rvalue_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'custom_rvalue.cpp') exclude(main_ns.variables, name = [ 'Triangle6_S1', 'Triangle6_S2', 'Triangle6_S3' , 'HexahedronFacesID', 'Hexahedron20FacesID' , 'TetrahedronFacesID' , 'HexahedronSplit5TetID', 'HexahedronSplit6TetID' , 'TriPrismFacesID', 'TriPrimSplit3TetID' , 'NodeCoordinates','EdgeCoordinates' , 'TriCoordinates', 'QuadCoordinates' , 'TetCoordinates', 'HexCoordinates' , 'PrismCoordinates', 'PyramidCoordinates', 'PyramidFacesID' , 'Tet10NodeSplit', 'Tet10NodeSplitZienk' , 'Hex20NodeSplit', 'Prism15NodeSplit', 'Pyramid13NodeSplit' ]) for f in main_ns.declarations: if type(f) == decl_wrappers.calldef_wrapper.free_function_t: if (str(f.return_type).find('GIMLI::VectorExpr') != -1): f.exclude() exclude(main_ns.free_functions, return_type = [ 'float *', 'float &' ,"::GIMLI::__VectorExpr< double, GIMLI::__VectorUnaryExprOp< double, GIMLI::VectorIterator< double >, GIMLI::ABS_ > >" ], name = [ 'strReplaceBlankWithUnderscore' , 'toStr', 'toInt', 'toFloat', 'toDouble', 'str' , 'getRowSubstrings', 'getNonEmptyRow', 'getSubstrings' , 'abs' , 'type' ]) exclude(main_ns.free_operators, name = [''], return_type = ['::std::ostream &', '::std::istream &']) exclude(main_ns.classes, name = [ 'ABS_', 'ACOT', 'ATAN', 'COS', 'COT', 'EXP', 'ABS_', 'LOG', 'LOG10', 'SIGN' ,'SIN', 'SQRT', 'SQR', 'TAN', 'TANH', 'PLUS', 'MINUS', 'MULT', 'DIVID', 'BINASSIGN' ,'cerrPtr', 'cerrPtrObject', 'coutPtr', 'coutPtrObject', 'deletePtr' ,'edge_', 'distancePair_' ,'IPCMessage' ,'PythonGILSave' ,'__VectorExpr' ,'__VectorUnaryExprOp' ,'__VectorBinaryExprOp' ,'__VectorValExprOp' ,'__ValVectorExprOp' ,'::GIMLI::__VectorValExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::MULT >' ,'::GIMLI::__VectorBinaryExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::__VectorIterator< double >, GIMLI::MULT>' ,'::GIMLI::__VectorExpr< double, GIMLI::__VectorBinaryExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::__VectorIterator< double >, GIMLI::MULT > >' ,'::GIMLI::__VectorExpr< double, GIMLI::__VectorValExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::MULT > >' ,'::GIMLI::__VectorExpr< double, GIMLI::__VectorUnaryExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::LOG10 > >' ,'::GIMLI::__VectorExpr< double, GIMLI::__VectorUnaryExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::LOG > >' ,'::GIMLI::__VectorUnaryExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::LOG10 >' ,'::GIMLI::__VectorUnaryExprOp< double, GIMLI::__VectorIterator< double >, GIMLI::LOG >' ,'::GIMLI::__VectorExpr<double, GIMLI::__VectorValExprOp<double, GIMLI::__VectorExpr<double, GIMLI::__ValVectorExprOp<double, GIMLI::__VectorIterator<double >, GIMLI::MULT > >, GIMLI::MULT > >' ,'::GIMLI::__VectorValExprOp<double, GIMLI::__VectorExpr<double, GIMLI::__ValVectorExprOp<double, GIMLI::__VectorIterator<double >, GIMLI::MULT > >, GIMLI::MULT >.pypp.hpp', 'GIMLI::Expr<GIMLI::ExprIdentity>' ]) exclude(main_ns.member_functions, name = ['begin', 'end', 'val'], return_type = ['']) exclude(main_ns.member_operators, symbol = ['']) mb.calldefs(access_type_matcher_t('protected')).exclude() mb.calldefs(access_type_matcher_t('private')).exclude() #setMemberFunctionCallPolicieByReturn(mb, [ '::GIMLI::Node &' #, '::GIMLI::Cell &' #, '::GIMLI::Boundary &' #, '::GIMLI::Shape &' #, '::GIMLI::Node *' #, '::GIMLI::Cell *' #, '::GIMLI::Boundary *' #, '::GIMLI::Shape *' #] #, call_policies.reference_existing_object) setMemberFunctionCallPolicieByReturn(mb, [ '::std::string *', 'float *', 'double *', 'int *', 'long *' , 'long long int *', 'unsigned long long int *' , '::GIMLI::Index *'] , call_policies.return_pointee_value) #setMemberFunctionCallPolicieByReturn(mb, ['::GIMLI::VectorIterator<double> &'] #, call_policies.copy_const_reference) setMemberFunctionCallPolicieByReturn(mb, ['::std::string &' , 'double &' ] , call_policies.return_by_value) #setMemberFunctionCallPolicieByReturn(mb, [ #, 'double &' ] #, call_policies.reference_existing_object) #call_policies.return_value_policy(call_policies.reference_existing_object) #call_policies.return_value_policy(call_policies.copy_non_const_reference) #call_policies.return_value_policy(call_policies.copy_const_reference) #addAutoConversions(mb) # excludeMemberByReturn(main_ns, ['::DCFEMLib::SparseMatrix<double> &']) #main_ns.classes(decl_starts_with(['STLMatrix']), allow_empty=True).exclude() #fun = mb.global_ns.member_functions('begin', allow_empty=True) #for f in fun: #f.exclude() #excludeFreeFunctionsByName(main_ns, ['strReplaceBlankWithUnderscore' #'toStr', 'toInt', 'toFloat', 'toDouble', #'getRowSubstrings', 'getNonEmptyRow', 'getSubstrings' ]) #excludeFreeFunctionsByReturn(main_ns, [ 'float *', 'float &' ]) #fun = ns.free_operators(return_type=funct, allow_empty=True) #excludeMemberOperators(main_ns, ['++', '--', '*']) # exclude all that does not match any predefined callpolicie excludeRest = True if excludeRest: mem_funs = mb.calldefs () for mem_fun in mem_funs: if mem_fun.call_policies: continue if not mem_fun.call_policies and \ (declarations.is_reference(mem_fun.return_type) or declarations.is_pointer (mem_fun.return_type)): #print mem_fun #mem_fun.exclude() mem_fun.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) #mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.return_pointee_value) #mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.return_opaque_pointer) #mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.copy_non_const_reference) # Now it is the time to give a name to our module from doxygen import doxygen_doc_extractor extractor = doxygen_doc_extractor() mb.build_code_creator(settings.module_name, doc_extractor=extractor) #It is common requirement in software world - each file should have license #mb.code_creator.license = '//Boost Software License(http://boost.org/more/license_info.html)' #I don't want absolute includes within code mb.code_creator.user_defined_directories.append(os.path.abspath('.')) #And finally we can write code to the disk def ignore(val): pass mb.split_module('./generated', on_unused_file_found=ignore) additional_files = [ os.path.join(os.path.abspath(os.path.dirname(__file__)), 'custom_rvalue.cpp'), os.path.join(os.path.abspath(os.path.dirname(__file__)), 'generators.h'), os.path.join(os.path.abspath(os.path.dirname(__file__)), 'tuples.hpp') ] for sourcefile in additional_files: p,filename = os.path.split(sourcefile) destfile = os.path.join('./generated', filename) if not samefile(sourcefile, destfile): shutil.copy(sourcefile, './generated') print("Updated ", filename, "as it was missing or out of date")
def generate(defined_symbols, extraIncludes): messages.disable( messages.W1005 # using a non public variable type for arguments or returns , messages.W1006 # `Py++` need your # help to expose function that takes > as argument/returns C++ arrays. # Take a look on "Function Transformation" > functionality and define # the transformation. , messages.W1007 # more than 10 args -> BOOST_PYTHON_MAX_ARITY is set , messages.W1009 # execution error W1009: The function takes as argument (name=pFunIdx, pos=1) > # non-const reference to Python immutable type - function could not be called > from Python , messages.W1014 # "operator*" is not supported. See , messages.W1016 # `Py++` does not exports non-const casting operators # Warnings 1020 - 1031 are all about why Py++ generates wrapper for class X , messages.W1023 # Py++` will generate class wrapper - there are few functions that should be # redefined in class wrapper , messages.W1025 # `Py++` will generate class wrapper - class contains "c_" - T* > member variable , messages.W1026 # `Py++` will generate class wrapper - class contains "arr_" - T& > member variable , messages.W1027 # `Py++` will generate class wrapper - class contains "mat_" - > array member variable , messages.W1035 # error. `Py++` can not expose static pointer member variables. , messages.W1036 # error. `Py++` can not expose pointer to Python immutable > member variables. This # could be changed in future. , messages.W1040 # error. The declaration is unexposed, but there are other > declarations, which # refer to it. This could cause "no to_python converter > found" run # time error # This is serious and lead to RuntimeError: `Py++` is going to write different content to the same file , messages.W1047 # There are two or more classes that use same > alias("MatElement"). Duplicated aliases causes # few problems, but the main one > is that some of the classes will not # be exposed to Python.Other classes : > , messages.W1049 # This method could not be overriden in Python - method returns > # reference to local variable! , messages.W1052 # `Py++` will not expose free operator ) logger.debug("Install SRC: ", os.path.abspath(__file__)) logger.debug("Execute from: ", os.getcwd()) sourcedir = os.path.dirname(os.path.abspath(__file__)) sourceHeader = os.path.abspath(sourcedir + "/" + r"pygimli.h") gimliInclude = os.path.dirname( os.path.abspath(sourcedir + "/../src/" + r"gimli.h")) settings.includesPaths.append(gimliInclude) xml_cached_fc = parser.create_cached_source_fc( sourceHeader, settings.module_name + '.cache') import platform defines = ['PYGIMLI_CAST', 'HAVE_BOOST_THREAD_HPP'] caster = 'gccxml' compiler_path = options.clang if platform.system() == 'Windows': if platform.architecture()[0] == '64bit': #compiler_path = 'C:/msys64/mingw64/bin/clang++' if sys.platform == 'darwin': pass else: defines.append('_WIN64') defines.append('MS_WIN64') logger.info('Marking win64 for gccxml') else: pass #compiler_path = 'C:/msys32/mingw32/bin/clang++' if len(compiler_path) == 0: compiler_path = None for define in [settings.gimli_defines, defined_symbols]: if len(define) > 0: defines.append(define) try: if sys.platform == 'win32': # os.name == 'nt' (default on my mingw)results in wrong commandline # for gccxml os.name = 'mingw' casterpath = settings.caster_path.replace('\\', '\\\\') casterpath = settings.caster_path.replace('/', '\\') if 'gccxml' not in casterpath: caster = 'castxml' if '.exe' not in casterpath: casterpath += '\\' + caster + '.exe' else: casterpath = settings.caster_path if 'gccxml' not in casterpath: caster = 'castxml' except Exception as e: logger.info("caster_path=%s" % casterpath) logger.info(str(e)) raise Exception("Problems determine castxml binary") settings.includesPaths.insert(0, os.path.abspath(extraIncludes)) logger.info("caster_path=%s" % casterpath) logger.info("working_directory=%s" % settings.gimli_path) logger.info("include_paths=%s" % settings.includesPaths) logger.info("define_symbols=%s" % defines) logger.info("compiler_path=%s" % compiler_path) logger.info("indexing_suite_version=2") xml_generator_config = parser.xml_generator_configuration_t( xml_generator=caster, xml_generator_path=casterpath, working_directory=settings.gimli_path, include_paths=settings.includesPaths, define_symbols=defines, ignore_gccxml_output=False, cflags="", compiler_path=compiler_path) mb = module_builder.module_builder_t( [xml_cached_fc], indexing_suite_version=2, xml_generator_config=xml_generator_config ) logger.info("Reading of c++ sources done.") mb.classes().always_expose_using_scope = True mb.calldefs().create_with_signature = True global_ns = mb.global_ns global_ns.exclude() main_ns = global_ns.namespace(MAIN_NAMESPACE) main_ns.include() # for c in main_ns.free_functions(): # print(c) # if 'pow' in c.name: # print(c) # print(c.name) # if c.decl_string.startswith('::GIMLI::pow'): # print(c) # print(c.name) # sys.exit() logger.info("Apply handmade wrappers.") try: hand_made_wrappers.apply(mb) except BaseException as e: print(e) logger.info("Apply custom rvalues.") # START manual r-value converters rvalue_converters = [ 'register_pytuple_to_rvector3_conversion', 'register_pysequence_to_rvector_conversion', # 'register_pysequence_to_bvector_conversion', 'register_pysequence_to_indexvector_conversion', 'register_pysequence_to_r3vector_conversion', 'register_pysequence_to_StdVectorRVector3_conversion', # 'register_rvector_to_ndarray_conversion', ] for converter in rvalue_converters: mb.add_declaration_code('void %s();' % converter) mb.add_registration_code('%s();' % converter) # END manual r-value converters custom_rvalue_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'custom_rvalue.cpp') logger.info("Starting to exclude stuff that we don't need " "or that is known to be spurious.") exclude(main_ns.variables, name=[ 'Triangle6_S1', 'Triangle6_S2', 'Triangle6_S3', 'HexahedronFacesID', 'Hexahedron20FacesID', 'TetrahedronFacesID', 'HexahedronSplit5TetID', 'HexahedronSplit6TetID', 'TriPrismFacesID', 'TriPrimSplit3TetID', 'NodeCoordinates', 'EdgeCoordinates', 'TriCoordinates', 'QuadCoordinates', 'TetCoordinates', 'HexCoordinates', 'PrismCoordinates', 'PyramidCoordinates', 'PyramidFacesID', 'Tet10NodeSplit', 'Tet10NodeSplitZienk', 'Hex20NodeSplit', 'Prism15NodeSplit', 'Pyramid13NodeSplit' ] ) exclude(main_ns.free_functions, return_type=[ 'float *', 'float &', "::GIMLI::__VectorExpr< double, " + "GIMLI::__VectorUnaryExprOp< double, " + "GIMLI::VectorIterator< double >, GIMLI::ABS_ > >"], name=[ 'strReplaceBlankWithUnderscore', 'toStr', 'toInt', 'toFloat', 'toDouble', 'str', 'getRowSubstrings', 'getNonEmptyRow', 'getSubstrings', 'abs', 'type'] ) exclude(main_ns.free_operators, name=[''], return_type=['::std::ostream &', '::std::istream &'] ) exclude(main_ns.classes, name=['ABS_', 'ACOT', 'ATAN', 'COS', 'COT', 'EXP', 'ABS_', 'LOG', 'LOG10', 'SIGN', 'SIN', 'SQRT', 'SQR', 'TAN', 'TANH', 'PLUS', 'MINUS', 'MULT', 'DIVID', 'BINASSIGN', 'cerrPtr', 'cerrPtrObject', 'coutPtr', 'coutPtrObject', 'deletePtr', 'edge_', 'distancePair_', 'IPCMessage', 'PythonGILSave', ] ) exclude(main_ns.member_functions, name=['begin', 'end', 'val'], return_type=[''] ) exclude(main_ns.member_operators, symbol=['']) for f in main_ns.declarations: if isinstance(f, decl_wrappers.calldef_wrapper.free_function_t): if (str(f.return_type).find('GIMLI::VectorExpr') != -1): f.exclude() ex = ['::GIMLI::MatrixElement', '::GIMLI::__VectorUnaryExprOp', '::GIMLI::__VectorBinaryExprOp', '::GIMLI::__ValVectorExprOp', '::GIMLI::__VectorValExprOp', '::GIMLI::__VectorExpr', '::GIMLI::Expr', '::GIMLI::InversionBase', 'GIMLI::MatrixElement', 'GIMLI::__VectorUnaryExprOp', 'GIMLI::__VectorBinaryExprOp', 'GIMLI::__ValVectorExprOp', 'GIMLI::__VectorValExprOp', 'GIMLI::__VectorExpr', 'GIMLI::Expr', 'GIMLI::InversionBase', 'std::vector<unsigned long', 'std::vector<bool', 'std::vector<double', ] for c in main_ns.free_functions(): for e in ex: if c.decl_string.find(e) > -1: try: c.exclude() logger.debug("Exclude: " + str(c)) except BaseException as _: logger.debug("Fail to exclude: " + str(c)) for c in main_ns.classes(): for e in ex: if c.decl_string.startswith(e): try: c.exclude() logger.debug("Exclude: " + c.name) except BaseException as _: logger.debug("Fail to exclude: " + c.name) try: for mem in c.variables(): try: mem.exclude() # logger.info("Exclude: " + str(mem)) except BaseException as _: logger.debug("Fail to exclude: " + str(mem)) except BaseException as _: # print(c, "has no member functions") pass try: for mem in c.constructors(): for e in ex: if mem.decl_string.find(e) > -1: try: mem.exclude() # logger.info("Exclude: " + str(mem)) except BaseException as _: logger.debug("Fail to exclude: " + str(mem)) for mem in c.member_functions(): for e in ex: if mem.decl_string.find(e) > -1: try: mem.exclude() # logger.info("Exclude: " + str(mem)) except BaseException as _: logger.debug("Fail to exclude: " + str(mem)) except BaseException as _: # print(c, "has no member functions") pass # print('#'*100) # print(c, c.name) if c.name.startswith('Vector<unsigned long>'): # print(' ', c.name) for mem in c.constructors(): # print("mem", mem, mem.decl_string) if mem.decl_string.find('( ::GIMLI::Index )') > -1: logger.debug("Exclude: " + str(mem)) mem.exclude() # print("mem", mem) try: mb.calldefs(access_type_matcher_t('protected')).exclude() mb.calldefs(access_type_matcher_t('private')).exclude() except BaseException as _: pass # setMemberFunctionCallPolicieByReturn(mb, [ '::GIMLI::Node &' # , '::GIMLI::Cell &' # , '::GIMLI::Boundary &' # , '::GIMLI::Shape &' # , '::GIMLI::Node *' # , '::GIMLI::Cell *' # , '::GIMLI::Boundary *' # , '::GIMLI::Shape *' # ] # , call_policies.reference_existing_object) setMemberFunctionCallPolicieByReturn( mb, ['::std::string *', 'float *', 'double *', 'int *', 'long *', 'long int *', 'long long int *', 'unsigned int *', 'long unsigned int *', 'unsigned long long int *', 'long long unsigned int *', '::GIMLI::Index *', '::GIMLI::SIndex *', 'bool *'], call_policies.return_pointee_value) setMemberFunctionCallPolicieByReturn(mb, ['::std::string &', 'float &', 'double &', 'int &', 'long &', 'long int &', 'long long int &', 'unsigned int &', 'long unsigned int &', 'long long unsigned int &', 'unsigned long long int &', '::GIMLI::Index &', '::GIMLI::SIndex &', 'bool &' ], call_policies.return_by_value) # setMemberFunctionCallPolicieByReturn(mb, # ['::GIMLI::VectorIterator<double> &'] # , call_policies.copy_const_reference) # setMemberFunctionCallPolicieByReturn(mb, [ # , 'double &' ] # , call_policies.reference_existing_object) # call_policies.return_value_policy(call_policies.reference_existing_object) # call_policies.return_value_policy(call_policies.copy_non_const_reference) # call_policies.return_value_policy(call_policies.copy_const_reference) # addAutoConversions(mb) # excludeMemberByReturn(main_ns, ['::DCFEMLib::SparseMatrix<double> &']) # fun = mb.global_ns.member_functions('begin', allow_empty=True) # for f in fun: # f.exclude() # excludeFreeFunctionsByName(main_ns, ['strReplaceBlankWithUnderscore' # 'toStr', 'toInt', 'toFloat', 'toDouble', # 'getRowSubstrings', 'getNonEmptyRow', 'getSubstrings' ]) # excludeFreeFunctionsByReturn(main_ns, [ 'float *', 'float &' ]) # fun = ns.free_operators(return_type=funct, allow_empty=True) # excludeMemberOperators(main_ns, ['++', '--', '*']) # exclude all that does not match any predefined callpolicie excludeRest = True if excludeRest: mem_funs = mb.calldefs() for mem_fun in mem_funs: if mem_fun.call_policies: continue if not mem_fun.call_policies and \ (declarations.is_reference(mem_fun.return_type) or declarations.is_pointer(mem_fun.return_type)): # print mem_fun # mem_fun.exclude() mem_fun.call_policies = call_policies.return_value_policy( call_policies.reference_existing_object) # mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.return_pointee_value) # mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.return_opaque_pointer) # mem_fun.call_policies = \ # call_policies.return_value_policy(call_policies.copy_non_const_reference) logger.info("Create api documentation from Doxgen comments.") # Now it is the time to give a name to our module from doxygen import doxygen_doc_extractor extractor = doxygen_doc_extractor() logger.info("Create code creator.") mb.build_code_creator(settings.module_name, doc_extractor=extractor) # It is common requirement in software world-each file should have license # mb.code_creator.license = '//Boost Software # License(http://boost.org/more/license_info.html)' # I don't want absolute includes within code mb.code_creator.user_defined_directories.append(os.path.abspath('.')) # And finally we can write code to the disk def ignore(val): pass logger.info("Create bindings code.") mb.split_module('./generated', on_unused_file_found=ignore) additional_files = [ os.path.join( os.path.abspath(os.path.dirname(__file__)), 'custom_rvalue.cpp'), os.path.join( os.path.abspath(os.path.dirname(__file__)), 'generators.h'), os.path.join( os.path.abspath(os.path.dirname(__file__)), 'tuples.hpp')] logger.info("Add additional files.") for sourcefile in additional_files: p, filename = os.path.split(sourcefile) destfile = os.path.join('./generated', filename) if not samefile(sourcefile, destfile): shutil.copy(sourcefile, './generated') logger.info("Updated " + filename + "as it was missing or out of date")
def filter_declarations( mb ): global_ns = mb.global_ns global_ns.exclude() ogrenewt_ns = global_ns.namespace( 'BasicJoints' ) ogrenewt_ns.include() ogrenewt_ns = global_ns.namespace( 'PrebuiltCustomJoints' ) ogrenewt_ns.include() ogrenewt_ns = global_ns.namespace( 'CollisionPrimitives' ) ogrenewt_ns.include() temp_ns = global_ns.namespace( 'Converters' ) temp_ns.include() temp_ns = global_ns.namespace( 'CollisionTools' ) temp_ns.include() temp_ns = global_ns.namespace( 'MomentOfInertia' ) temp_ns.include() ogrenewt_ns = global_ns.namespace( 'OgreNewt' ) ogrenewt_ns.include() ## these need to be excluded due to callback functions - Have been wrapped ogrenewt_ns.class_( "World" ).member_functions("setLeaveWorldCallback").exclude() ogrenewt_ns.class_( "Body" ).member_functions("addBouyancyForce").exclude() ogrenewt_ns.class_( "Body" ).member_functions("setAutoactiveCallback").exclude() ogrenewt_ns.class_( "Body" ).member_functions("setCustomForceAndTorqueCallback").exclude() ogrenewt_ns.class_( "Body" ).member_functions("setCustomTransformCallback").exclude() ogrenewt_ns.class_( "BodyIterator" ).member_functions("go").exclude() global_ns.namespace( 'BasicJoints' ).class_( "Hinge" ).member_functions("setCallback").exclude() global_ns.namespace( 'BasicJoints' ).class_( "Slider" ).member_functions("setCallback").exclude() global_ns.namespace( 'BasicJoints' ).class_( "Universal" ).member_functions("setCallback").exclude() ## Replaced these with 'useful' functions in the handwrappers - take and return python objects ogrenewt_ns.class_( "Body" ).member_functions("setUserData").exclude() ogrenewt_ns.class_( "Joint" ).member_functions("setUserData").exclude() ogrenewt_ns.class_( "Body" ).member_functions("getUserData").exclude() ogrenewt_ns.class_( "Joint" ).member_functions("getUserData").exclude() ## This one needs a list of vertices given to it ogrenewt_ns.class_( "TreeCollision" ).member_functions("addPoly").exclude() # ConvexHull has an overloaded constructor that takes 5 args, one is a pointer to a list of vectors which we can't # handle, so we created a helper function caller createConvexHull that takes a python list instead. mb.global_ns.namespace ('OgreNewt').class_('ConvexHull').constructor(arg_types=[None,None,None,None,None]).exclude() ### and we need the free functions for func in ogrenewt_ns.free_functions (): ## print "FREE Func:", func.name func.include() ## Exclude protected and private that are not pure virtual query = declarations.access_type_matcher_t( 'private' ) \ & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) ogrenewt_ns.calldefs( query, allow_empty=True ).exclude() ## Some varibles that we really do need and aren't exposed by default.. cls = ogrenewt_ns.class_("ContactCallback") cls.variable('m_body0').include() cls.variable('m_body1').include() cls.variable('m_contact').include() cls.variable('m_material').include() global_ns.namespace( 'Ogre' ).class_('AxisAlignedBox').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Radian').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('SceneNode').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('IndexData').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('SceneManager').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Vector3').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Matrix4').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Degree').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Quaternion').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Node').include(already_exposed=True) global_ns.namespace( 'Ogre' ).class_('Serializer').include(already_exposed=True)
def emitClassAttributes(c): global hSrc, cppSrc, chsSrc #chsSrc += '-- *** Attributes\n' query = declarations.access_type_matcher_t('public') for ma in c.vars(allow_empty=True, function=query, recursive=False): emitAttrBinding(c, ma)
builder.decl( "::std::vector<lc3_subroutine_call_info, std::allocator<lc3_subroutine_call_info> >" ).include() builder.decl( "::std::vector<lc3_trap_call_info, std::allocator<lc3_trap_call_info> >" ).include() builder.decl( "::std::map<unsigned short, lc3_blackbox_info, std::less<unsigned short>, std::allocator<std::pair<const unsigned short, lc3_blackbox_info> > >" ).include() builder.decl( "::std::map<unsigned short, lc3_breakpoint_info, std::less<unsigned short>, std::allocator<std::pair<const unsigned short, lc3_breakpoint_info> > >" ).include() builder.decl( "::std::map<unsigned short, lc3_watchpoint_info, std::less<unsigned short>, std::allocator<std::pair<const unsigned short, lc3_watchpoint_info> > >" ).include() builder.decl( "::std::map<unsigned short, lc3_memory_stats, std::less<unsigned short>, std::allocator<std::pair<const unsigned short, lc3_memory_stats> > >" ).include() # Don't export accessors builder.classes().add_properties(exclude_accessors=True) # Enclude protected and private methods. builder.calldefs(declarations.access_type_matcher_t('protected')).exclude() builder.calldefs(declarations.access_type_matcher_t('private')).exclude() # Define a name for the module builder.build_code_creator(module_name="pylc3") # Writes the C++ interface file builder.write_module('PyLC3Gen.cpp')
def filter_declarations( mb ): global_ns = mb.global_ns global_ns.exclude() ode_ns = global_ns ## Ode doesn't have it's own namespace.. .namespace( 'ode' ) for cls in ode_ns.classes(): # # print "Checking ", cls.decl_string try: if cls.decl_string[2]=='d' and cls.decl_string[3].isupper(): # # print "Including Class:", cls.name cls.include() except: pass ## and the dxXXclasses for cls in ode_ns.classes(): # # print "Checking ", cls.decl_string if cls.decl_string[2:4]=='dx' and cls.decl_string[4].isupper(): # # print "Including dxClass:", cls.name cls.include() ## and we'll need the free functions as well for funcs in ode_ns.free_functions (): # # print "FREE Func:", funcs.name if funcs.name[0]=='d' and funcs.name[1].isupper(): # # print "Including Function", funcs.name funcs.include() for var in ode_ns.variables (): # # print "Checking Variable:", var.name if len(var.name) > 2: if var.name[0]=='d' and var.name[1].isupper(): # # print "Including variable", var.name var.include() for var in ode_ns.typedefs (): # # print "Checking typedef:", var.name if len(var.name) > 2: if var.name[0]=='d' and var.name[1].isupper(): # # print "Including typedef", var.name var.include() # print "Member Func:", funcs.name # if funcs.name[0]=='d': # print "Including Member Function", funcs.name # funcs.include() ## these either don't exist in the source or have strange arguments ignore=( "dGeomGetBodyNext", "dGeomMoved", "dPrintMatrix", "dWorldGetAutoDisableAngularAverageThreshold", "dWorldGetAutoDisableLinearAverageThreshold", "dWorldSetAutoDisableAngularAverageThreshold", "dWorldSetAutoDisableLinearAverageThreshold" , "dJointAddPUTorque", "dGeomTriMeshGetTriangle" ) for cls in ignore: try: ode_ns.free_function(cls).exclude() except: pass # # # in hand wrappers to handle pyobjects... ode_ns.class_( "dGeom" ).member_functions( "getData").exclude() ode_ns.class_( "dGeom" ).member_functions( "setData").exclude() ode_ns.class_( "dBody" ).member_functions( "setData").exclude() ode_ns.class_( "dBody" ).member_functions( "getData").exclude() ode_ns.class_( "dSpace" ).member_functions( "collide").exclude() ode_ns.class_( "dFixedJoint" ).member_functions( "create").exclude() ## Exclude protected and private that are not pure virtual ### need to be careful here as it removes free functions query = ( declarations.access_type_matcher_t( 'private' ) | declarations.access_type_matcher_t( 'protected' ) )\ & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) non_public_non_pure_virtual = ode_ns.calldefs( query ) # # print "TO EXCLUDE:", non_public_non_pure_virtual non_public_non_pure_virtual.exclude() #For some reason Py++ does not honor call policies in this case. #You will have to expose them by hand dContactGeom = ode_ns.class_( 'dContactGeom' ) g12 = dContactGeom.variables( lambda d: d.name in ('g1', 'g2' ) ) g12.exclude() #g12.getter_call_policies = call_policies.return_value_policy( call_policies.return_opaque_pointer ) ode_ns.class_( 'dBox' ).noncopyable = True ode_ns.class_( 'dCapsule' ).noncopyable = True ode_ns.class_( 'dGeom' ).noncopyable = True ode_ns.class_( 'dGeomTransform' ).noncopyable = True ode_ns.class_( 'dPlane' ).noncopyable = True ode_ns.class_( 'dQuadTreeSpace' ).noncopyable = True ode_ns.class_( 'dRay' ).noncopyable = True ode_ns.class_( 'dSphere' ).noncopyable = True
def write(self, work_dir): if (len(self.class_decls) != len(self.class_full_names)): message = 'Not enough class decls added to do write.' raise ValueError(message) for idx, full_name in enumerate(self.class_full_names): short_name = self.class_short_names[idx] class_decl = self.class_decls[idx] self.hpp_string = "" self.cpp_string = "" # Add the cpp file header self.add_cpp_header(full_name, short_name) # Check for struct-enum pattern if declarations.is_struct(class_decl): enums = class_decl.enumerations(allow_empty=True) if len(enums) == 1: replacements = { 'class': class_decl.name, 'enum': enums[0].name } self.cpp_string += 'void register_{class}_class(py::module &m){{\n'.format( **replacements) self.cpp_string += ' py::class_<{class}> myclass(m, "{class}");\n'.format( **replacements) self.cpp_string += ' py::enum_<{class}::{enum}>(myclass, "{enum}")\n'.format( **replacements) for eachval in enums[0].values: replacements = { 'class': class_decl.name, 'enum': enums[0].name, 'val': eachval[0] } self.cpp_string += ' .value("{val}", {class}::{enum}::{val})\n'.format( **replacements) self.cpp_string += " .export_values();\n}\n" # Set up the hpp self.add_hpp(short_name) # Do the write self.write_files(work_dir, short_name) continue # Define any virtual function overloads methods_needing_override = self.add_virtual_overides( class_decl, short_name) # Add overrides if needed overrides_string = "" if len(methods_needing_override) > 0: overrides_string = ', ' + short_name + '_Overloads' # Add smart ptr support if needed smart_pointer_handle = self.class_info.hierarchy_attribute( 'smart_ptr_type') ptr_support = "" if self.has_shared_ptr and smart_pointer_handle is not None: ptr_support = ', ' + smart_pointer_handle + '<' + short_name + ' > ' # Add base classes if needed bases = "" for eachBase in class_decl.bases: cleaned_base = eachBase.related_class.name.replace(" ", "") exposed = any(cleaned_base in t.replace(" ", "") for t in self.exposed_class_full_names) public = not eachBase.access_type == "private" if exposed and public: bases += ', ' + eachBase.related_class.name + " " # Add the class refistration class_definition_dict = { 'short_name': short_name, 'overrides_string': overrides_string, 'ptr_support': ptr_support, 'bases': bases } class_definition_template = self.wrapper_templates[ "class_definition"] self.cpp_string += class_definition_template.format( **class_definition_dict) # Add constructors #if not self.is_abstract and not class_decl.is_abstract: # No constructors for classes with private pure virtual methods! ppv_class = False for eachMemberFunction in class_decl.member_functions( allow_empty=True): if eachMemberFunction.virtuality == "pure virtual" and eachMemberFunction.access_type == "private": ppv_class = True break if not ppv_class: query = declarations.access_type_matcher_t('public') for eachConstructor in class_decl.constructors( function=query, allow_empty=True): writer = constructor_writer.CppConsturctorWrapperWriter( self.class_info, eachConstructor, class_decl, self.wrapper_templates, short_name) self.cpp_string = writer.add_self(self.cpp_string) # Add public member functions query = declarations.access_type_matcher_t('public') for eachMemberFunction in class_decl.member_functions( function=query, allow_empty=True): exlcuded = False if self.class_info.excluded_methods is not None: exlcuded = (eachMemberFunction.name in self.class_info.excluded_methods) if not exlcuded: writer = method_writer.CppMethodWrapperWriter( self.class_info, eachMemberFunction, class_decl, self.wrapper_templates, short_name) self.cpp_string = writer.add_self(self.cpp_string) # Any custom generators if self.class_info.custom_generator is not None: self.cpp_string += self.class_info.custom_generator.get_class_cpp_def_code( short_name) # Close the class definition self.cpp_string += ' ;\n}\n' # Set up the hpp self.add_hpp(short_name) # Do the write self.write_files(work_dir, short_name)
def redefined_funcs(self): """ returns list of member functions that should be defined in the class wrapper It comes useful in 3 tier hierarchy: .. code-block:: c++ struct base{ virtual void do_nothing() = 0; }; struct derived{ virtual void do_something() = 0; }; struct concrete{ virtual void do_nothing(){} virtual void do_something(){} }; The wrapper for class `derived`, should define `do_nothing` function, otherwise the generated code will not compile """ if isinstance(self._redefined_funcs, list): return self._redefined_funcs all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable) all_protected = declarations.access_type_matcher_t( 'protected') & all_included all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL) all_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.VIRTUAL ) \ & ( declarations.access_type_matcher_t( 'public' ) \ | declarations.access_type_matcher_t( 'protected' )) all_not_pure_virtual = ~all_pure_virtual query = all_protected | all_pure_virtual mf_query = query | all_virtual relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]')) funcs = [] defined_funcs = [] for base in self.recursive_bases: if base.access == ACCESS_TYPES.PRIVATE: continue base_cls = base.related_class funcs.extend( base_cls.member_functions(mf_query, recursive=False, allow_empty=True)) funcs.extend( base_cls.member_operators(relevant_opers & query, recursive=False, allow_empty=True)) defined_funcs.extend( base_cls.member_functions(all_not_pure_virtual, recursive=False, allow_empty=True)) defined_funcs.extend( base_cls.member_operators(all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True)) not_reimplemented_funcs = set() is_same_function = declarations.is_same_function for f in funcs: cls_fs = self.calldefs(name=f.name, recursive=False, allow_empty=True) for cls_f in cls_fs: if is_same_function(f, cls_f): break else: #should test whether this function has been added or not for f_impl in not_reimplemented_funcs: if is_same_function(f, f_impl): if declarations.is_base_and_derived( f_impl.parent, f.parent): #add function from the most derived class not_reimplemented_funcs.remove(f_impl) not_reimplemented_funcs.add(f) break else: #should test whether this function is implemented in base class if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL: not_reimplemented_funcs.add(f) else: for f_defined in defined_funcs: if is_same_function(f, f_defined): break else: not_reimplemented_funcs.add(f) functions = filter( lambda f: (False == f.ignore and True == f.exportable) or all_pure_virtual(f), list(not_reimplemented_funcs)) #Boost.Python is not able to call for non-virtual function, from the base #class if there is a virtual function with the same within base class #See override_bug tester for more information def buggy_bpl_filter(f): if f.parent is self: return False if f.access_type != ACCESS_TYPES.PUBLIC: return False if f.virtuality != VIRTUALITY_TYPES.NOT_VIRTUAL: return False #we need to check that we don't have "same" function in this class this_funs = self.decls(name=f.name, decl_type=declarations.calldef_t, recursive=False, allow_empty=True) for this_f in this_funs: if is_same_function(this_f, f): #there is already the function in the class, so no need to redefined it return False else: return True tmp = {} # id : f for redefined_f in functions: #redefined is virtual, I am not interested in virtual functions for rfo in redefined_f.overloads: if id(rfo) in tmp: continue if buggy_bpl_filter(rfo): tmp[id(rfo)] = rfo functions.extend(tmp.values()) functions.sort(cmp=lambda f1, f2: cmp((f1.name, f1.location.as_tuple( )), (f2.name, f2.location.as_tuple()))) self._redefined_funcs = functions return self._redefined_funcs
def filter_declarations(self, mb): mb.global_ns.exclude() mb.global_ns.namespace('pyplusplus', recursive=False).include() boost_ns = mb.global_ns.namespace('boost', recursive=False) boost_ns.namespace('posix_time', recursive=False).include() boost_ns.namespace('date_time', recursive=False).include() boost_ns.namespace('gregorian', recursive=False).include() boost_ns.namespace('local_time', recursive=False).include() boost_ns.classes( lambda decl: decl.name.startswith('constrained_value<')).include() ## Exclude protected and private that are not pure virtual query = ~declarations.access_type_matcher_t( 'public' ) \ & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) non_public_non_pure_virtual = boost_ns.calldefs(query) non_public_non_pure_virtual.exclude() for name in ['month_str_to_ushort', 'from_stream_type', 'parse_date']: boost_ns.calldefs( lambda decl: decl.name.startswith(name)).exclude() to_be_removed = [ 'c_time', 'duration_traits_long', 'duration_traits_adapted', 'posix_time_system_config' #TODO find out link bug , 'millisec_posix_time_system_config' ] boost_ns.classes(lambda decl: decl.name in to_be_removed).exclude() starts_with = [ 'time_resolution_traits<', 'counted_time_rep<', 'date_facet<', 'period_formatter<', 'date_generator_formatter<', 'special_values_formatter<' ] for name in starts_with: boost_ns.classes(lambda decl: decl.name.startswith(name)).exclude() ends_with = ['_impl', '_config'] for name in ends_with: boost_ns.classes(lambda decl: decl.name.endswith(name)).exclude() boost_ns.classes( lambda decl: decl.alias.endswith('formatter')).exclude() #boost.date_time has problem to create local_[micro]sec_clock #variable, it has nothing to do with Py++ empty_classes = ['local_microsec_clock', 'local_sec_clock'] for alias in empty_classes: class_ = boost_ns.class_(lambda decl: decl.alias == alias) class_.exclude() class_.ignore = False for alias in ['microsec_clock', 'second_clock']: class_ = boost_ns.class_(lambda decl: decl.alias == alias) class_.calldefs().create_with_signature = True tdi = mb.class_(lambda decl: decl.alias == 'time_duration_impl') tdi_init = tdi.constructor(arg_types=[None, None, None, None], recursive=False) tdi_init.ignore = True #next declarations are not exported, but Py++ writes warnings about them: boost_ns.operators('<<').exclude() boost_ns.operators('>>').exclude() boost_ns.operators('=').exclude() #next function uses non public class in its definition. microsec_clocks = boost_ns.classes( lambda decl: decl.name.startswith('microsec_clock<')) for mc in microsec_clocks: mc.member_functions('create_time').exclude() #TODO: add FT #next function takes reference to int. This function could not be called #from Python. Function transformation feature solves this problem tz_db_base = boost_ns.class_( lambda decl: decl.name.startswith('tz_db_base<')) tz_db_base.member_functions('split_rule_spec').exclude()
def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions('haveSolution').exclude() self.ompl_ns.class_('PRM').member_functions('growRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() self.ompl_ns.class_('PRM').member_functions('expandRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # exclude solve() methods that take a "const PlannerTerminationCondition &" # as first argument; only keep the solve() that just takes a double argument self.ompl_ns.member_functions('solve', arg_types=['::ompl::base::PlannerTerminationCondition const &']).exclude() # add wrappers for boost::function types self.add_boost_function('unsigned int()', 'NumNeighborsFn', 'Number of neighbors function') # self.add_boost_function('std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_boost_function('bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())') # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a know limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.add_wrapper_code('ompl::base::PlannerStatus solve(const ompl::base::PlannerTerminationCondition& ptc);') PRM_cls.add_declaration_code(open('PRM.SingleThreadSolve.cpp','r').read()) PRM_cls.add_registration_code('def("solve", &PRM_wrapper::solve)') PRM_cls.add_registration_code('def("solve", timed_solve_function_type(&ompl::base::Planner::solve))') # Py++ seems to get confused by virtual methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['EST', 'KPIECE1', 'BKPIECE1', 'LBKPIECE1', 'PRM', 'LazyRRT', 'RRT', 'RRTConnect', 'TRRT', 'SBL']: if planner!='PRM': # PRM overrides setProblemDefinition, so we don't need to add this code self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner) # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This can # be equal to an unsigned long or unsigned int, depending on architecture (or version of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename('KStarStrategy') except: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename('KStarStrategy')
def redefined_funcs( self ): """returns list of member functions that should be defined in class wrapper It comes useful in 3 tier hierarchy: struct base{ virtual void do_nothing() = 0; }; struct derived{ virtual void do_something() = 0; }; struct concrete{ virtual void do_nothing(){} virtual void do_something(){} }; derived_wrapper should define do_nothing function, otherwise the generated code will not compile """ if isinstance( self._redefined_funcs, list ): return self._redefined_funcs all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable ) all_protected = declarations.access_type_matcher_t( 'protected' ) & all_included all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL ) all_not_pure_virtual = ~all_pure_virtual query = all_protected | all_pure_virtual relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]') ) funcs = set() defined_funcs = set() for base in self.recursive_bases: if base.access == ACCESS_TYPES.PRIVATE: continue base_cls = base.related_class funcs.update( base_cls.member_functions( query, recursive=False, allow_empty=True ) ) funcs.update( base_cls.member_operators( relevant_opers & query, recursive=False, allow_empty=True ) ) defined_funcs.update( base_cls.member_functions( all_not_pure_virtual, recursive=False, allow_empty=True ) ) defined_funcs.update( base_cls.member_operators( all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True ) ) not_reimplemented_funcs = set() is_same_function = declarations.is_same_function for f in funcs: cls_fs = self.calldefs( name=f.name, recursive=False, allow_empty=True ) for cls_f in cls_fs: if is_same_function( f, cls_f ): break else: #should test whether this function has been added or not for f_impl in not_reimplemented_funcs: if is_same_function( f, f_impl ): if declarations.is_base_and_derived( f_impl.parent, f.parent ): #add function from the most derived class not_reimplemented_funcs.remove( f_impl ) not_reimplemented_funcs.add( f ) break else: #should test whether this function is implemented in base class if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL: not_reimplemented_funcs.add( f ) else: for f_defined in defined_funcs: if is_same_function( f, f_defined ): break else: not_reimplemented_funcs.add( f ) functions = list( not_reimplemented_funcs ) functions.sort( cmp=lambda f1, f2: cmp( ( f1.name, f1.location.as_tuple() ) , ( f2.name, f2.location.as_tuple() ) ) ) self._redefined_funcs = functions return self._redefined_funcs
def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) # print debug info self.replace_member_functions(self.ompl_ns.member_functions('printDebug')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions('maybeConstructSolution').exclude() self.ompl_ns.class_('PRM').member_functions('growRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() self.ompl_ns.class_('PRM').member_functions('expandRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # add wrappers for boost::function types self.add_boost_function('unsigned int()', 'NumNeighborsFn', 'Number of neighbors function') # self.add_boost_function('std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_boost_function('bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())') # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['EST', 'KPIECE1', 'BKPIECE1', 'LBKPIECE1', 'PRM', 'LazyPRM', 'LazyPRMstar', 'PDST', 'LazyRRT', 'RRT', 'RRTConnect', 'TRRT', 'RRTstar', 'LBTRRT', 'SBL', 'SPARS', 'SPARStwo', 'STRIDE', 'FMT', 'BITstar']: try: cls = self.ompl_ns.class_(planner) except: continue self.ompl_ns.class_(planner).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )""") if planner!='PRM': # PRM overrides setProblemDefinition, so we don't need to add this code self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner) # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a known limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.member_function('solve').exclude() PRM_cls.add_wrapper_code(""" virtual ::ompl::base::PlannerStatus solve( ::ompl::base::PlannerTerminationCondition const & ptc ) { if( bp::override func_solve = this->get_override( "solve" ) ) return func_solve( boost::ref(ptc) ); else{ return default_solve( boost::ref(ptc) ); } } ::ompl::base::PlannerStatus default_solve( ::ompl::base::PlannerTerminationCondition const & ptc ); """) PRM_cls.add_declaration_code(open('PRM.SingleThreadSolve.cpp','r').read()) # This needs to be the last registration code added to the PRM_cls to the ugly hack below. PRM_cls.add_registration_code("""def("solve", (::ompl::base::PlannerStatus(::ompl::geometric::PRM::*)( ::ompl::base::PlannerTerminationCondition const &))(&PRM_wrapper::solve), (::ompl::base::PlannerStatus(PRM_wrapper::*)( ::ompl::base::PlannerTerminationCondition const & ))(&PRM_wrapper::default_solve), bp::arg("ptc") ); // HACK ALERT: closing brace destroys bp::scope, so that PRMstar is not a nested class of PRM } { // wrapper for PRMstar, derived from single-threaded PRM_wrapper bp::class_<PRMstar_wrapper, bp::bases< PRM_wrapper >, boost::noncopyable >("PRMstar", bp::init< ompl::base::SpaceInformationPtr const & >( bp::arg("si") ) ) """) # Add wrapper code for PRM* PRM_cls.add_declaration_code(""" class PRMstar_wrapper : public PRM_wrapper { public: PRMstar_wrapper(const ompl::base::SpaceInformationPtr &si) : PRM_wrapper(si, true) { setName("PRMstar"); params_.remove("max_nearest_neighbors"); } }; """) # LazyPRM's Vertex type is void* so exclude addMilestone which has return type void* self.ompl_ns.class_('LazyPRM').member_function('addMilestone').exclude() # avoid difficulties in exporting the return type std::vector<base::PlannerDataPtr> # do this for all multithreaded planners for planner in ['SPARS', 'SPARStwo']: cls = self.ompl_ns.class_(planner) cls.constructor(arg_types=["::ompl::base::SpaceInformationPtr const &"]).exclude() cls.add_registration_code('def(bp::init<ompl::base::SpaceInformationPtr const &>(bp::arg("si")))') cls.add_wrapper_code(""" {0}_wrapper(::ompl::base::SpaceInformationPtr const &si) : ompl::geometric::{0}(si), bp::wrapper<ompl::geometric::{0}>() {{ OMPL_WARN("%s: this planner uses multiple threads and might crash if your StateValidityChecker, OptimizationObjective, etc., are allocated within Python.", getName().c_str()); }} """.format(planner)) # used in SPARS self.std_ns.class_('deque<ompl::base::State*>').rename('dequeState') # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This can # be equal to an unsigned long or unsigned int, depending on architecture (or version of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename('KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned long, ompl::base::State*>').rename('mapVertexToState') except: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename('KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned int, ompl::base::State*>').rename('mapVertexToState') try: # Exclude some functions from BIT* that cause some Py++ compilation problems: self.ompl_ns.class_('BITstar').member_functions('getEdgeQueue').exclude() #I don't know why this doesn't work. self.ompl_ns.class_('BITstar').member_functions('getVertexQueue').exclude() #I don't know why this doesn't work. except: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) #self.ompl_ns.namespace('util').exclude() # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) # print debug info self.replace_member_functions(self.ompl_ns.member_functions('printDebug')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions('maybeConstructSolution').exclude() self.ompl_ns.class_('PRM').member_functions('growRoadmap', \ function=declarations.access_type_matcher_t('protected')).exclude() self.ompl_ns.class_('PRM').member_functions('expandRoadmap', \ function=declarations.access_type_matcher_t('protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # add wrappers for std::function types self.add_function_wrapper('unsigned int()', \ 'NumNeighborsFn', 'Number of neighbors function') # self.add_function_wrapper( # 'std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_function_wrapper( 'bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails to compile, most likely because of a bug in # Py++'s generation of exposed_decl.pypp.txt. self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( \ 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, ' \ 'bp::return_value_policy< bp::copy_const_reference >())') self.std_ns.class_('vector< std::shared_ptr<ompl::geometric::BITstar::Vertex> >').exclude() self.std_ns.class_('vector<const ompl::base::State *>').exclude() # exclude deprecated API function self.ompl_ns.free_function('getDefaultPlanner').exclude() # Using nullptr as a default value in method arguments causes # problems with Boost.Python. # See https://github.com/boostorg/python/issues/60 self.ompl_ns.class_('PathSimplifier').add_declaration_code('#define nullptr NULL\n') # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. planners = [p.related_class for p in self.ompl_ns.class_('Planner').recursive_derived] for planner in planners: planner.add_registration_code( 'def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))' \ '(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )') if planner.name != 'PRM': # PRM overrides setProblemDefinition, so we don't need to add this code planner.add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner.name) planner.add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner.name) # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a known limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.member_function('solve').exclude() PRM_cls.add_wrapper_code(""" virtual ::ompl::base::PlannerStatus solve( ::ompl::base::PlannerTerminationCondition const & ptc ) { if( bp::override func_solve = this->get_override( "solve" ) ) return func_solve( boost::ref(ptc) ); else{ return default_solve( boost::ref(ptc) ); } } ::ompl::base::PlannerStatus default_solve( ::ompl::base::PlannerTerminationCondition const & ptc ); """) PRM_cls.add_declaration_code(open(join(dirname(__file__), \ 'PRM.SingleThreadSolve.cpp'), 'r').read()) # This needs to be the last registration code added to the PRM_cls to the ugly hack below. PRM_cls.add_registration_code("""def("solve", (::ompl::base::PlannerStatus(::ompl::geometric::PRM::*)( ::ompl::base::PlannerTerminationCondition const &))(&PRM_wrapper::solve), (::ompl::base::PlannerStatus(PRM_wrapper::*)( ::ompl::base::PlannerTerminationCondition const & ))(&PRM_wrapper::default_solve), bp::arg("ptc") ); // HACK ALERT: closing brace destroys bp::scope, // so that PRMstar is not a nested class of PRM } { // wrapper for PRMstar, derived from single-threaded PRM_wrapper bp::class_<PRMstar_wrapper, bp::bases< PRM_wrapper >, boost::noncopyable >("PRMstar", bp::init< ompl::base::SpaceInformationPtr const & >( bp::arg("si") ) ) """) # Add wrapper code for PRM* PRM_cls.add_declaration_code(""" class PRMstar_wrapper : public PRM_wrapper { public: PRMstar_wrapper(const ompl::base::SpaceInformationPtr &si) : PRM_wrapper(si, true) { setName("PRMstar"); params_.remove("max_nearest_neighbors"); } }; """) # LazyPRM's Vertex type is void* so exclude addMilestone which has return type void* self.ompl_ns.class_('LazyPRM').member_function('addMilestone').exclude() # avoid difficulties in exporting the return type std::vector<base::PlannerDataPtr> # do this for all multithreaded planners for planner in ['SPARS', 'SPARStwo']: cls = self.ompl_ns.class_(planner) cls.constructor(arg_types=["::ompl::base::SpaceInformationPtr const &"]).exclude() cls.add_registration_code( 'def(bp::init<ompl::base::SpaceInformationPtr const &>(bp::arg("si")))') cls.add_wrapper_code(""" {0}_wrapper(::ompl::base::SpaceInformationPtr const &si) : ompl::geometric::{0}(si), bp::wrapper<ompl::geometric::{0}>() {{ OMPL_WARN("%s: this planner uses multiple threads and might crash if your StateValidityChecker, OptimizationObjective, etc., are allocated within Python.", getName().c_str()); }} """.format(planner)) # exclude methods that use problematic types cls = self.ompl_ns.class_('SPARS') cls.member_function('addPathToSpanner').exclude() cls.member_function('computeDensePath').exclude() self.ompl_ns.class_('SPARStwo').member_function('findCloseRepresentatives').exclude() # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This # can be equal to an unsigned long or unsigned int, depending on architecture (or version # of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>').rename( 'NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename('KStarStrategy') except declaration_not_found_t: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename( 'NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename('KStarStrategy') try: # Exclude some functions from BIT* that cause some Py++ compilation problems # (#I don't know why this doesn't work): self.ompl_ns.class_('BITstar').member_functions('getEdgeQueue').exclude() self.ompl_ns.class_('BITstar').member_functions('getVertexQueue').exclude() except declaration_not_found_t: pass
def get_header_info(self): """ PyGCCXML header code parser magic happens here! : returns the parsed header data in python dict : return dict keys: namespace, class, io_signature, make, properties, methods : Can be used as an CLI command or an extenal API """ gr = self.modname.split('-')[0] module = self.modname.split('-')[-1] generator_path, generator_name = utils.find_xml_generator() xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, compiler='gcc') decls = parser.parse( [self.target_file], xml_generator_config) global_namespace = declarations.get_global_namespace(decls) # namespace try: self.parsed_data['namespace'] = [] ns = global_namespace.namespace(gr) if ns is None: raise BlockToolException main_namespace = ns.namespace(module) if main_namespace is None: raise BlockToolException('namespace cannot be none') self.parsed_data['namespace'] = [gr, module] if main_namespace.declarations: for _namespace in main_namespace.declarations: if isinstance(_namespace, declarations.namespace_t): if Constants.KERNEL not in str(_namespace): main_namespace = _namespace self.parsed_data['namespace'].append( str(_namespace).split('::')[-1].split(' ')[0]) except RuntimeError: raise BlockToolException( 'Invalid namespace format in the block header file') # class try: self.parsed_data['class'] = '' for _class in main_namespace.declarations: if isinstance(_class, declarations.class_t): main_class = _class self.parsed_data['class'] = str(_class).split('::')[ 2].split(' ')[0] except RuntimeError: raise BlockToolException( 'Block header namespace {} must consist of a valid class instance'.format(module)) # io_signature, message_ports self.parsed_data['io_signature'] = {} self.parsed_data['message_port'] = {} if os.path.isfile(self.impl_file) and exist_comments(self): self.parsed_data['io_signature'] = io_signature( self.impl_file) self.parsed_data['message_port'] = message_port( self.impl_file) read_comments(self) elif os.path.isfile(self.impl_file) and not exist_comments(self): self.parsed_data['io_signature'] = io_signature( self.impl_file) self.parsed_data['message_port'] = message_port( self.impl_file) if self.addcomments: add_comments(self) elif not os.path.isfile(self.impl_file) and exist_comments(self): read_comments(self) else: self.parsed_data['io_signature'] = { "input": [], "output": [] } self.parsed_data['message_port'] = self.parsed_data['io_signature'] # make try: self.parsed_data['make'] = {} self.parsed_data['make']['arguments'] = [] query_m = declarations.custom_matcher_t( lambda mem_fun: mem_fun.name.startswith('make')) query_make = query_m & declarations.access_type_matcher_t('public') make_func = main_class.member_functions(function=query_make, allow_empty=True, header_file=self.target_file) criteria = declarations.calldef_matcher(name='make') _make_fun = declarations.matcher.get_single(criteria, main_class) _make_fun = str(_make_fun).split( 'make')[-1].split(')')[0].split('(')[1].lstrip().rstrip().split(',') if make_func: for arg in make_func[0].arguments: for _arg in _make_fun: if str(arg.name) in _arg: make_arguments = { "name": str(arg.name), "dtype": str(arg.decl_type), "default": "" } if re.findall(r'[-+]?\d*\.\d+|\d+', _arg): make_arguments['default'] = re.findall( r'[-+]?\d*\.\d+|\d+', _arg)[0] elif re.findall(r'\"(.+?)\"', _arg): make_arguments['default'] = re.findall( r'\"(.+?)\"', _arg)[0] elif "true" in _arg: make_arguments['default'] = "True" elif "false" in _arg: make_arguments['default'] = "False" self.parsed_data['make']['arguments'].append( make_arguments.copy()) except RuntimeError: self.parsed_data['make'] = {} self.parsed_data['make']['arguments'] = [] # setters try: self.parsed_data['methods'] = [] query_methods = declarations.access_type_matcher_t('public') setters = main_class.member_functions(function=query_methods, allow_empty=True, header_file=self.target_file) getter_arguments = [] if setters: for setter in setters: if str(setter.name).startswith('set_') and setter.arguments: setter_args = { "name": str(setter.name), "arguments_type": [] } for argument in setter.arguments: args = { "name": str(argument.name), "dtype": str(argument.decl_type) } getter_arguments.append(args['name']) setter_args['arguments_type'].append(args.copy()) self.parsed_data['methods'].append(setter_args.copy()) except RuntimeError: self.parsed_data['methods'] = [] # getters try: self.parsed_data['properties'] = [] query_properties = declarations.access_type_matcher_t('public') getters = main_class.member_functions(function=query_properties, allow_empty=True, header_file=self.target_file) if getters: for getter in getters: if not getter.arguments or getter.has_const: getter_args = { "name": str(getter.name), "dtype": str(getter.return_type), "read_only": True } if getter_args['name'] in getter_arguments: getter_args["read_only"] = False self.parsed_data['properties'].append( getter_args.copy()) except RuntimeError: self.parsed_data['properties'] = [] # documentation try: _index = None header_file = codecs.open(self.target_file, 'r', 'cp932') self.parsed_data['docstring'] = re.compile( r'//.*?$|/\*.*?\*/', re.DOTALL | re.MULTILINE).findall( header_file.read())[2:] header_file.close() for doc in self.parsed_data['docstring']: if Constants.BLOCKTOOL in doc: _index = self.parsed_data['docstring'].index(doc) if _index is not None: self.parsed_data['docstring'] = self.parsed_data['docstring'][: _index] except: self.parsed_data['docstring'] = [] return self.parsed_data
def redefined_funcs( self ): """ returns list of member functions that should be defined in the class wrapper It comes useful in 3 tier hierarchy: .. code-block:: c++ struct base{ virtual void do_nothing() = 0; }; struct derived{ virtual void do_something() = 0; }; struct concrete{ virtual void do_nothing(){} virtual void do_something(){} }; The wrapper for class `derived`, should define `do_nothing` function, otherwise the generated code will not compile """ if isinstance( self._redefined_funcs, list ): return self._redefined_funcs all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable ) all_protected = declarations.access_type_matcher_t( 'protected' ) & all_included all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL ) all_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.VIRTUAL ) \ & ( declarations.access_type_matcher_t( 'public' ) \ | declarations.access_type_matcher_t( 'protected' )) all_not_pure_virtual = ~all_pure_virtual query = all_protected | all_pure_virtual mf_query = query | all_virtual relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]') ) funcs = [] defined_funcs = [] for base in self.recursive_bases: if base.access == ACCESS_TYPES.PRIVATE: continue base_cls = base.related_class funcs.extend( base_cls.member_functions( mf_query, recursive=False, allow_empty=True ) ) funcs.extend( base_cls.member_operators( relevant_opers & query, recursive=False, allow_empty=True ) ) defined_funcs.extend( base_cls.member_functions( all_not_pure_virtual, recursive=False, allow_empty=True ) ) defined_funcs.extend( base_cls.member_operators( all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True ) ) not_reimplemented_funcs = set() is_same_function = declarations.is_same_function for f in funcs: cls_fs = self.calldefs( name=f.name, recursive=False, allow_empty=True ) for cls_f in cls_fs: if is_same_function( f, cls_f ): break else: #should test whether this function has been added or not for f_impl in not_reimplemented_funcs: if is_same_function( f, f_impl ): if declarations.is_base_and_derived( f_impl.parent, f.parent ): #add function from the most derived class not_reimplemented_funcs.remove( f_impl ) not_reimplemented_funcs.add( f ) break else: #should test whether this function is implemented in base class if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL: not_reimplemented_funcs.add( f ) else: for f_defined in defined_funcs: if is_same_function( f, f_defined ): break else: not_reimplemented_funcs.add( f ) functions = [f for f in list( not_reimplemented_funcs ) if ( False == f.ignore and True == f.exportable ) or all_pure_virtual( f )] #Boost.Python is not able to call for non-virtual function, from the base #class if there is a virtual function with the same within base class #See override_bug tester for more information def buggy_bpl_filter( f ): if f.parent is self: return False if f.access_type != ACCESS_TYPES.PUBLIC: return False if f.virtuality != VIRTUALITY_TYPES.NOT_VIRTUAL: return False #we need to check that we don't have "same" function in this class this_funs = self.decls( name=f.name , decl_type=declarations.calldef_t , recursive=False , allow_empty=True ) for this_f in this_funs: if is_same_function( this_f, f ): #there is already the function in the class, so no need to redefined it return False else: return True tmp = {} # id : f for redefined_f in functions: #redefined is virtual, I am not interested in virtual functions for rfo in redefined_f.overloads: if id(rfo) in tmp: continue if buggy_bpl_filter( rfo ): tmp[ id(rfo) ] = rfo functions.extend( list(tmp.values()) ) functions.sort( key=lambda f: ( f.name, f.location.as_tuple() ) ) self._redefined_funcs = functions return self._redefined_funcs
def filter_declarations(self, mb): mb.global_ns.exclude() mb.global_ns.namespace("pyplusplus", recursive=False).include() boost_ns = mb.global_ns.namespace("boost", recursive=False) boost_ns.namespace("posix_time", recursive=False).include() boost_ns.namespace("date_time", recursive=False).include() boost_ns.namespace("gregorian", recursive=False).include() boost_ns.namespace("local_time", recursive=False).include() boost_ns.classes(lambda decl: decl.name.startswith("constrained_value<")).include() ## Exclude protected and private that are not pure virtual query = ~declarations.access_type_matcher_t("public") & ~declarations.virtuality_type_matcher_t( declarations.VIRTUALITY_TYPES.PURE_VIRTUAL ) non_public_non_pure_virtual = boost_ns.calldefs(query) non_public_non_pure_virtual.exclude() for name in ["month_str_to_ushort", "from_stream_type", "parse_date"]: boost_ns.calldefs(lambda decl: decl.name.startswith(name)).exclude() to_be_removed = [ "c_time", "duration_traits_long", "duration_traits_adapted", "posix_time_system_config", # TODO find out link bug "millisec_posix_time_system_config", ] boost_ns.classes(lambda decl: decl.name in to_be_removed).exclude() starts_with = [ "time_resolution_traits<", "counted_time_rep<", "date_facet<", "period_formatter<", "date_generator_formatter<", "special_values_formatter<", ] for name in starts_with: boost_ns.classes(lambda decl: decl.name.startswith(name)).exclude() ends_with = ["_impl", "_config"] for name in ends_with: boost_ns.classes(lambda decl: decl.name.endswith(name)).exclude() boost_ns.classes(lambda decl: decl.alias.endswith("formatter")).exclude() # boost.date_time has problem to create local_[micro]sec_clock # variable, it has nothing to do with Py++ empty_classes = ["local_microsec_clock", "local_sec_clock"] for alias in empty_classes: class_ = boost_ns.class_(lambda decl: decl.alias == alias) class_.exclude() class_.ignore = False for alias in ["microsec_clock", "second_clock"]: class_ = boost_ns.class_(lambda decl: decl.alias == alias) class_.calldefs().create_with_signature = True tdi = mb.class_(lambda decl: decl.alias == "time_duration_impl") tdi_init = tdi.constructor(arg_types=[None, None, None, None], recursive=False) tdi_init.ignore = True # next declarations are not exported, but Py++ writes warnings about them: boost_ns.operators("<<").exclude() boost_ns.operators(">>").exclude() boost_ns.operators("=").exclude() # next function uses non public class in its definition. microsec_clocks = boost_ns.classes(lambda decl: decl.name.startswith("microsec_clock<")) for mc in microsec_clocks: mc.member_functions("create_time").exclude() # TODO: add FT # next function takes reference to int. This function could not be called # from Python. Function transformation feature solves this problem tz_db_base = boost_ns.class_(lambda decl: decl.name.startswith("tz_db_base<")) tz_db_base.member_functions("split_rule_spec").exclude()