def main(namespace, *headers, outfile=None): 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, cflags='-std=c++14') decls = parser.parse(headers, xml_generator_config) global_namespace = declarations.get_global_namespace(decls[0]) ns = global_namespace.namespace(namespace) if outfile is None: outfile = sys.stdout else: outfile = open(outfile, 'w') def out(s): if not s: return outfile.write(s) outfile.write('\n') out("#include <pybind11/pybind11.h>") out("#include <pybind11/stl.h>") for header in headers: out(f'#include "{header}"') out("namespace py = pybind11;") out(f'PYBIND11_MODULE({namespace}, m){{') out("using namespace pybind11::literals;") for decl in ns.declarations: out(dump_decl(decl)) out('}')
def pygccxml_parser(filename): """ Implementation of pygccxml parser """ generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name) filename = filename decls = parser.parse([filename], xml_generator_config) global_namespace = declarations.get_global_namespace(decls) ns = global_namespace.namespace("sample_namespace") return declarations.print_declarations(ns)
def test_config(self): """Test config setup with wrong xml generator setups.""" # Some code to parse for the example code = "int a;" # Find the location of the xml generator (castxml or gccxml) generator_path, name = utils.find_xml_generator() # No xml generator path config = parser.xml_generator_configuration_t(xml_generator=name) self.assertRaises( RuntimeError, lambda: parser.parse_string(code, config)) # Invalid path config = parser.xml_generator_configuration_t( xml_generator_path="wrong/path", xml_generator=name) self.assertRaises( RuntimeError, lambda: parser.parse_string(code, config)) # None path config = parser.xml_generator_configuration_t( xml_generator_path=None, xml_generator=name) self.assertRaises( RuntimeError, lambda: parser.parse_string(code, config)) # No name config = parser.xml_generator_configuration_t( xml_generator_path=generator_path) self.assertRaises( RuntimeError, lambda: parser.parse_string(code, config)) # Random name config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator="not_a_generator") self.assertRaises( RuntimeError, lambda: parser.parse_string(code, config)) # None name config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=None) self.assertRaises( RuntimeError, lambda: parser.parse_string(code, config))
def test_config(self): """ Test that a missing include directory is printing a warning, not raising an error """ # Some code to parse for the example code = "int a;" # Find the location of the xml generator (castxml or gccxml) generator_path, name = utils.find_xml_generator() # Path given as include director doesn't exist config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=name, include_paths=["doesnt/exist", os.getcwd()]) self.assertWarns(RuntimeWarning, parser.parse_string, code, config)
def test_config(self): """Test config setup with wrong xml generator setups.""" # Some code to parse for the example code = "int a;" # Find the location of the xml generator (castxml or gccxml) generator_path, name = utils.find_xml_generator() # No xml generator path config = parser.xml_generator_configuration_t(xml_generator=name) self.assertRaises(RuntimeError, lambda: parser.parse_string(code, config)) # Invalid path config = parser.xml_generator_configuration_t( xml_generator_path="wrong/path", xml_generator=name) self.assertRaises(RuntimeError, lambda: parser.parse_string(code, config)) # None path config = parser.xml_generator_configuration_t(xml_generator_path=None, xml_generator=name) self.assertRaises(RuntimeError, lambda: parser.parse_string(code, config)) # No name config = parser.xml_generator_configuration_t( xml_generator_path=generator_path) self.assertRaises(RuntimeError, lambda: parser.parse_string(code, config)) # Random name config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator="not_a_generator") self.assertRaises(RuntimeError, lambda: parser.parse_string(code, config)) # None name config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=None) self.assertRaises(RuntimeError, lambda: parser.parse_string(code, config))
def main(): """ Main function to generate Python-C++ binding code """ # Find out the xml generator (gccxml or castxml) generator_path, generator_name = utils.find_xml_generator() compiler = "g++" compiler_path = "/usr/bin/g++" # Create configuration for CastXML xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, compiler=compiler, compiler_path=compiler_path) # Set include dirs and cflags to avoid warnings and errors xml_generator_config.append_cflags("-std=c++11") xml_generator_config.include_paths.append("../include/generated/") # Find all relevant headers header_list = get_list_of_files("../include/generated/") header_list = header_list + get_list_of_files("../include/ad_rss/core/") header_list = header_list + get_list_of_files("../include/ad_rss/physics/") # Parses the source files and creates a module_builder object builder = module_builder.module_builder_t( header_list, xml_generator_path=generator_path, xml_generator_config=xml_generator_config) # Automatically detect properties and associated getters/setters builder.classes().add_properties(exclude_accessors=True) # Define a name for the module builder.build_code_creator(module_name="libad_rss_python") # Writes the C++ interface file builder.write_module('PythonWrapper.cpp')
def try_pygccxml(): from pygccxml import declarations from pygccxml import utils from pygccxml import parser # Find out the c++ parser. This should resolve to the castxml # version installed in Docker. generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, include_paths=["/usr/include/eigen3"], # TODO(eric.cousineau): Why is `compiler_path` necessary? compiler_path=generator_path, start_with_declarations=["ns"], ) t_start = time.time() (global_ns, ) = parser.parse_string(code, config) dt = time.time() - t_start return dt
def main(): defines = [] includes = [] cxxflags = [ '-Wno-unknown-attributes', '-Wno-unused-value', '-Wno-macro-redefined', ] compiler = 'g++' args = sys.argv[1:] while args and args[0].startswith('-'): arg = args.pop(0) if arg.startswith('-I'): include = arg[2:] includes.append(include) elif arg.startswith('-D'): define = arg[2:] defines.append(define) else: sys.stderr.write('error: unknown option %r\n' % arg) sys.exit(1) winsdk = True if winsdk: # Set up Clang compiler flags to use MinGW runtime # http://stackoverflow.com/a/19839946 p = subprocess.Popen( ["x86_64-w64-mingw32-g++", "-x", "c++", "-E", "-Wp,-v", '-', '-fsyntax-only'], stdin=open(os.devnull, 'rt'), stdout=open(os.devnull, 'wt'), stderr=subprocess.PIPE) includes.append('/usr/share/castxml/clang/include') for line in p.stderr: if line.startswith(' '): include = line.strip() if os.path.isdir(include): if os.path.exists(os.path.join(include, 'ia32intrin.h')): # XXX: We must use Clang's intrinsic headers continue includes.append(os.path.normpath(include)) winver = 0x0602 defines += [ # emulate MinGW '__MINGW32__', '_WIN32', '_WIN64', '__declspec(x)=', # Avoid namespace pollution when including windows.h # http://support.microsoft.com/kb/166474 'WIN32_LEAN_AND_MEAN', # Set Windows version to 8.1 '_WIN32_WINNT=0x%04X' % winver, 'WINVER=0x%04X' % winver, 'NTDDI_VERSION=0x%04X0000' % winver, # Prevent headers from requiring a rpcndr.h version beyond MinGW's '__REQUIRED_RPCNDR_H_VERSION__=475', # Avoid C++ helper classes 'D3D10_NO_HELPERS', 'D3D11_NO_HELPERS', 'D3D11_VIDEO_NO_HELPERS', ] # XXX: Change compiler? #compiler = 'cl' # XXX: This doesn't seem to work well cxxflags += [ #'-m32', #'-target', 'x86_64-pc-mingw32', ] sys.stderr.write('Include path:\n') for include in includes: sys.stderr.write(' %s\n' % include) sys.stderr.write('Definitions:\n') for define in defines: sys.stderr.write(' %s\n' % define) import logging utils.loggers.set_level(logging.DEBUG) # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator("castxml") # Configure the xml generator config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, define_symbols = defines, include_paths = includes, cflags = ' '.join(cxxflags), compiler = compiler, #keep_xml = True, ) script_dir = os.path.dirname(__file__) headers = [ os.path.join(script_dir, '..', '..', 'compat', 'winsdk_compat.h'), os.path.join(script_dir, 'cxx2api.h'), ] main_header = args[0] headers.append(main_header) decls = parser.parse(headers, config, parser.COMPILATION_MODE.ALL_AT_ONCE) global_ns = declarations.get_global_namespace(decls) def decl_filter(decl): location = decl.location if location is None: return False return os.path.basename(location.file_name) in map(os.path.basename, args) module, _ = os.path.splitext(main_header) visitor = decl2_dumper_t(module) visitor.start() for decl in global_ns.declarations: if not decl_filter(decl): continue if sys.stdout.isatty(): print('# ' + str(decl)) visitor.decl = decl algorithm.apply_visitor(visitor, decl) visitor.finish()
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 main(): defines = [] includes = [] cxxflags = [ '-Wno-unknown-attributes', '-Wno-unused-value', '-Wno-macro-redefined', ] compiler = 'g++' args = sys.argv[1:] while args and args[0].startswith('-'): arg = args.pop(0) if arg.startswith('-I'): include = arg[2:] includes.append(include) elif arg.startswith('-D'): define = arg[2:] defines.append(define) else: sys.stderr.write('error: unknown option %r\n' % arg) sys.exit(1) winsdk = True if winsdk: # Set up Clang compiler flags to use MinGW runtime if 0: # XXX: This doesn't work # http://stackoverflow.com/a/19839946 p = subprocess.Popen([ "x86_64-w64-mingw32-g++", "-x", "c++", "-E", "-Wp,-v", '-', '-fsyntax-only' ], stdin=open(os.devnull, 'rt'), stdout=open(os.devnull, 'wt'), stderr=subprocess.PIPE) includes.append('/usr/share/castxml/clang/include') for line in p.stderr: if line.startswith(' '): include = line.strip() if os.path.isdir(include): includes.append(os.path.normpath(include)) elif 0: # XXX: This matches what wclang does, but doensn't work neither cxxflags += [ "-target", "x86_64-w64-mingw32", "-nostdinc", "-isystem", "/usr/lib/clang/3.6.0/include", "-isystem", "/usr/x86_64-w64-mingw32/include", "-isystem", "/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++", "-isystem", "/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++/x86_64-w64-mingw32", ] else: # This works somehow, but seems brittle includes += [ '/usr/x86_64-w64-mingw32/include', '/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++', '/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++/x86_64-w64-mingw32', ] winver = 0x0602 defines += [ # emulate MinGW '__MINGW32__', '_WIN32', '_WIN64', '__declspec(x)=', # Avoid namespace pollution when including windows.h # http://support.microsoft.com/kb/166474 'WIN32_LEAN_AND_MEAN', # Set Windows version to 8.1 '_WIN32_WINNT=0x%04X' % winver, 'WINVER=0x%04X' % winver, 'NTDDI_VERSION=0x%04X0000' % winver, # Avoid C++ helper classes 'D3D10_NO_HELPERS', 'D3D11_NO_HELPERS', 'D3D11_VIDEO_NO_HELPERS', ] # XXX: Change compiler? #compiler = 'cl' # XXX: This doesn't seem to work well cxxflags += [ #'-m32', #'-target', 'x86_64-pc-mingw32', ] sys.stderr.write('Include path:\n') for include in includes: sys.stderr.write(' %s\n' % include) sys.stderr.write('Definitions:\n') for define in defines: sys.stderr.write(' %s\n' % define) import logging utils.loggers.set_level(logging.DEBUG) # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator("castxml") # Configure the xml generator config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, define_symbols=defines, include_paths=includes, cflags=' '.join(cxxflags), compiler=compiler, #keep_xml = True, ) script_dir = os.path.dirname(__file__) headers = [ os.path.join(script_dir, '..', '..', 'compat', 'winsdk_compat.h'), os.path.join(script_dir, 'cxx2api.h'), ] main_header = args[0] headers.append(main_header) decls = parser.parse(headers, config, parser.COMPILATION_MODE.ALL_AT_ONCE) global_ns = declarations.get_global_namespace(decls) def decl_filter(decl): location = decl.location if location is None: return False return os.path.basename(location.file_name) in args module, _ = os.path.splitext(main_header) visitor = decl2_dumper_t(module) visitor.start() for decl in global_ns.declarations: if not decl_filter(decl): continue visitor.decl = decl algorithm.apply_visitor(visitor, decl) visitor.finish()
def parse_file(filename, project_source_directory, include_directories, declaration_names, stream): """ Entry point for parsing a file """ # Find out the xml generator (gccxml or castxml) generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator config = parser.xml_generator_configuration_t( start_with_declarations=declaration_names.split(" "), include_paths=include_directories.split(" "), xml_generator_path=generator_path, xml_generator=generator_name, cflags='-std=c++11 -Wc++11-extensions') # Parse source file decls = parser.parse([os.path.abspath(filename)], config, compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE) # grab global namespace try: global_ns = declarations.get_global_namespace(decls) except RuntimeError: return [] # output file preamble fileguard = "pybind_" + \ filename.replace('.', '_').replace('/', '_').replace('-', '_') stream( """//========================================================================= // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //========================================================================= """) stream("#ifndef %s" % fileguard) stream("#define %s" % fileguard) stream("") stream("#include <pybind11/pybind11.h>") stream("") stream("#include \"%s\"" % os.path.relpath( os.path.abspath(filename), os.path.commonprefix([ os.path.abspath(project_source_directory), os.path.abspath(filename) ]))) stream("") includes = get_includes(global_ns, filename, project_source_directory) for include in includes: stream("#include \"%s\"" % include) if includes: stream("") stream("namespace py = pybind11;") stream("") wrapped_objects = {} for enum_ in global_ns.enumerations(allow_empty=True): if enum_.location.file_name != os.path.abspath(filename): continue if enum_.parent and type(enum_.parent).__name__.find('class_t') != -1: continue wrapped_objects[enum_] = parse_free_enumeration(enum_, stream) stream("") for class_ in global_ns.classes(allow_empty=True): if class_.location.file_name != os.path.abspath(filename) or\ class_ in parsed_classes: continue if class_.parent and type( class_.parent).__name__.find('class_t') != -1: continue wrapped_objects[class_] = parse_class(class_, stream) stream("") all_functions = set() overloaded_functions = set() for fn_ in global_ns.free_functions(allow_empty=True): if fn_.location.file_name != os.path.abspath(filename): continue if fn_.name in all_functions: overloaded_functions.add(fn_.name) else: all_functions.add(fn_.name) for fn_ in global_ns.free_functions(allow_empty=True): if fn_.location.file_name != os.path.abspath(filename): continue wrapped_objects[fn_] = parse_free_function( fn_, fn_.name in overloaded_functions, stream) stream("") stream("#endif") parsed_classes.clear() return wrapped_objects
def parse_file(filename): # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator(name='castxml') # Configure the xml generator xml_generator_config = parser.xml_generator_configuration_t( # cflags="-std=gnu++11", cflags="-Wno-c++11-extensions", include_paths=["/Users/markoates/Repos/allegro_flare/include"], xml_generator_path=generator_path, compiler="g++", xml_generator=generator_name) # Parse the c++ file decls = parser.parse([filename], xml_generator_config) # output some GOLD! global_namespace = declarations.get_global_namespace(decls) # Search for functions which return a double. Two functions will be found criteria = declarations.calldef_matcher( #return_type="float", #header_file="/Users/markoates/Repos/allegro_flare/include/allegro_flare/" + filename) header_file=os.path.abspath(filename)) # criteria = declarations.calldef_matcher(return_type=double_type) found_items = declarations.matcher.find(criteria, global_namespace) # populate the table with unique names count = 0 for item in found_items: count = count + 1 cleaned_filename = re.match(r'/Users/markoates/Repos/allegro_flare/(.*)', item.location.file_name).group(1) # create `declaration_type` declaration_type = item.__class__.__name__ if declaration_type[-2:] == "_t": declaration_type = declaration_type[:-2] declaration_type = declaration_type.replace('_', ' ') declaration_type = "%s" % declaration_type # create `declaration` declaration = str(item) declaration = re.match(r'(.*) \[.*\]$', declaration).group(1) # try to extract any preceeding '//' comments above the declaration in_source_documentation = extract_in_source_documentation(item.location.file_name, item.location.line) # get grandparent's name grandparent = item.parent.parent grandparent_name = grandparent.name if grandparent else '' # insert the content into the table parse_cache_make_table_connection.execute("INSERT INTO parsed_declarations VALUES (NULL,?,?,?,?,?,?,?,?,?,?,?,?);", (str(item), item.decl_string, declaration, item.name, declaration_type, str(item.parent.name), str(grandparent_name), item.attributes, cleaned_filename, str(item.location.line), in_source_documentation, "") ) parse_cache_connection.commit() # create a list of unique items unique_item_names = set(); for item in found_items: unique_item_names.update({item.name}) # cross-correlate declarations in the database docs_connection = sqlite3.connect('doc_entries.db') docs_connection.row_factory = sqlite3.Row docs_c = docs_connection.cursor() found_items = 0 unfound_items = 0 for item in unique_item_names: docs_c.execute('SELECT * FROM entries WHERE decl=?', (item, )) entries = docs_c.fetchall() if len(entries) == 0: print item unfound_items += 1 else: print_green(item + " - FOUND") found_items += 1 if unfound_items == 0: print_func = print_green elif found_items == 0: print_func = print_red else: print_func = print_yellow print_func("==============================") print_func(str(found_items) + " items found.") print_func(str(unfound_items) + " matches missing.") print_func("==============================") return
def generate_python_wrapper(header_directories, include_paths, library_name, cpp_filename, declarations, ignore_declarations={}, ignore_files={}): """ Function to generate Python-C++ binding code by calling pygccxml and py++ :param header_directories: directories with headers to create python binding for :type header_directories: list<string> :param include_paths: directories required as includes for the header files :type include_paths: list<string> :param library_name: the output name of the library to be created :type library_name: string :param cpp_filename: the output name of the C++ file to be created :type cpp_filename: string :param declarations: a list of declarations to be used for starting the AST syntax tree. See also pygccxml start_with_declarations or either -fxml-start(gccxml) or -castxml-start(castxml) :type declarations: list<string> :param ignore_declarations: a list of declarations to be ignored when generating C++ code :type ignore_declarations: list<string> :param ignore_files: a list of files to be ignored :type ignore_files: list<string> :return: """ # Find out the xml generator (gccxml or castxml) generator_path, generator_name = utils.find_xml_generator() compiler = "g++" compiler_path = "/usr/bin/g++" # Create configuration for CastXML xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, compiler=compiler, compiler_path=compiler_path, start_with_declarations=declarations) # Set include dirs and cflags to avoid warnings and errors xml_generator_config.append_cflags("-std=c++11") for inc_dir in include_paths: xml_generator_config.include_paths.append(inc_dir) for header_dir in header_directories: xml_generator_config.include_paths.append(header_dir) # Find all relevant headers header_list = list() for header_dir in header_directories: header_list = header_list + get_list_of_files( header_dir, ignore_files=ignore_files) # Parses the source files and creates a module_builder object builder = module_builder.module_builder_t( header_list, xml_generator_path=generator_path, compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE, xml_generator_config=xml_generator_config, indexing_suite_version=2) for ignore_declaration in ignore_declarations: builder.decls(lambda decl: ignore_declaration in decl.name).exclude() # for some reason there is a problem with variables named 'length' # the filename is empty and the line no is set to -1 # therefore the declaration is not processed in the code later on # this is to fix length struct members for decl in builder.decls("length"): if isinstance(decl, decl_wrappers.variable_wrapper.variable_t): if isinstance(decl.parent, decl_wrappers.class_wrapper.class_t): decl.location.file_name = decl.parent.location.file_name decl.location.line = decl.parent.location.line + 1 decl.ignore = False # Automatically detect properties and associated getters/setters builder.classes().add_properties(exclude_accessors=True) # Define a name for the module builder.build_code_creator(module_name=library_name) # Writes the C++ interface file builder.write_module(cpp_filename)
def main(): defines = [] includes = [] cxxflags = ["-Wno-unknown-attributes", "-Wno-unused-value", "-Wno-macro-redefined"] compiler = "g++" args = sys.argv[1:] while args and args[0].startswith("-"): arg = args.pop(0) if arg.startswith("-I"): include = arg[2:] includes.append(include) elif arg.startswith("-D"): define = arg[2:] defines.append(define) else: sys.stderr.write("error: unknown option %r\n" % arg) sys.exit(1) winsdk = True if winsdk: # Set up Clang compiler flags to use MinGW runtime if 0: # XXX: This doesn't work # http://stackoverflow.com/a/19839946 p = subprocess.Popen( ["x86_64-w64-mingw32-g++", "-x", "c++", "-E", "-Wp,-v", "-", "-fsyntax-only"], stdin=open(os.devnull, "rt"), stdout=open(os.devnull, "wt"), stderr=subprocess.PIPE, ) includes.append("/usr/share/castxml/clang/include") for line in p.stderr: if line.startswith(" "): include = line.strip() if os.path.isdir(include): includes.append(os.path.normpath(include)) elif 0: # XXX: This matches what wclang does, but doensn't work neither cxxflags += [ "-target", "x86_64-w64-mingw32", "-nostdinc", "-isystem", "/usr/lib/clang/3.6.0/include", "-isystem", "/usr/x86_64-w64-mingw32/include", "-isystem", "/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++", "-isystem", "/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++/x86_64-w64-mingw32", ] else: # This works somehow, but seems brittle includes += [ "/usr/x86_64-w64-mingw32/include", "/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++", "/usr/lib/gcc/x86_64-w64-mingw32/4.9-win32/include/c++/x86_64-w64-mingw32", ] winver = 0x0602 defines += [ # emulate MinGW "__MINGW32__", "_WIN32", "_WIN64", "__declspec(x)=", # Avoid namespace pollution when including windows.h # http://support.microsoft.com/kb/166474 "WIN32_LEAN_AND_MEAN", # Set Windows version to 8.1 "_WIN32_WINNT=0x%04X" % winver, "WINVER=0x%04X" % winver, "NTDDI_VERSION=0x%04X0000" % winver, # Avoid C++ helper classes "D3D10_NO_HELPERS", "D3D11_NO_HELPERS", "D3D11_VIDEO_NO_HELPERS", ] # XXX: Change compiler? # compiler = 'cl' # XXX: This doesn't seem to work well cxxflags += [ #'-m32', #'-target', 'x86_64-pc-mingw32', ] sys.stderr.write("Include path:\n") for include in includes: sys.stderr.write(" %s\n" % include) sys.stderr.write("Definitions:\n") for define in defines: sys.stderr.write(" %s\n" % define) import logging utils.loggers.set_level(logging.DEBUG) # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator("castxml") # Configure the xml generator config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, define_symbols=defines, include_paths=includes, cflags=" ".join(cxxflags), compiler=compiler, # keep_xml = True, ) script_dir = os.path.dirname(__file__) headers = [os.path.join(script_dir, "..", "..", "compat", "winsdk_compat.h"), os.path.join(script_dir, "cxx2api.h")] main_header = args[0] headers.append(main_header) decls = parser.parse(headers, config, parser.COMPILATION_MODE.ALL_AT_ONCE) global_ns = declarations.get_global_namespace(decls) def decl_filter(decl): location = decl.location if location is None: return False return os.path.basename(location.file_name) in args module, _ = os.path.splitext(main_header) visitor = decl2_dumper_t(module) visitor.start() for decl in global_ns.declarations: if not decl_filter(decl): continue visitor.decl = decl algorithm.apply_visitor(visitor, decl) visitor.finish()
def parse_file(filename, project_source_directory, include_directories, declaration_names, stream): """ Entry point for parsing a file """ # Find out the xml generator (gccxml or castxml) generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator config = parser.xml_generator_configuration_t( start_with_declarations=declaration_names.split(" "), include_paths=include_directories.split(" "), xml_generator_path=generator_path, xml_generator=generator_name, cflags='-std=c++11 -Wc++11-extensions') # Parse source file decls = parser.parse([os.path.abspath(filename)], config) # grab global namespace try: global_ns = declarations.get_global_namespace(decls) except RuntimeError: return [] # output file preamble fileguard = "pybind_" + filename.replace('.', '_').replace('/', '_') stream("""//========================================================================= // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //========================================================================= """) stream("#ifndef %s" % fileguard) stream("#define %s" % fileguard) stream("") stream("#include <pybind11/pybind11.h>") stream("") stream("#include \"%s\"" % os.path.relpath(os.path.abspath(filename), os.path.commonprefix( [os.path.abspath(project_source_directory), os.path.abspath(filename)]))) stream("") includes = get_includes(global_ns, filename, project_source_directory) for include in includes: stream("#include \"%s\"" % include) if includes: stream("") stream("namespace py = pybind11;") stream("") wrapped_objects = {} for enum_ in global_ns.enumerations(allow_empty=True): if enum_.location.file_name != os.path.abspath(filename): continue if enum_.parent and type(enum_.parent).__name__.find('class_t') != -1: continue wrapped_objects[enum_] = parse_free_enumeration(enum_, stream) stream("") for class_ in global_ns.classes(allow_empty=True): if class_.location.file_name != os.path.abspath(filename) or\ class_ in parsed_classes: continue if class_.parent and type(class_.parent).__name__.find('class_t') != -1: continue wrapped_objects[class_] = parse_class(class_, stream) stream("") all_functions = set() overloaded_functions = set() for fn_ in global_ns.free_functions(allow_empty=True): if fn_.location.file_name != os.path.abspath(filename): continue if fn_.name in all_functions: overloaded_functions.add(fn_.name) else: all_functions.add(fn_.name) for fn_ in global_ns.free_functions(allow_empty=True): if fn_.location.file_name != os.path.abspath(filename): continue wrapped_objects[fn_] = parse_free_function( fn_, fn_.name in overloaded_functions, stream) stream("") stream("#endif") parsed_classes.clear() return wrapped_objects
def get_header_info(self, namespace_to_parse): """ 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 """ module = self.modname.split('-')[-1] self.parsed_data['module_name'] = module self.parsed_data['filename'] = self.filename import hashlib hasher = hashlib.md5() with open(self.target_file, 'rb') as file_in: buf = file_in.read() hasher.update(buf) self.parsed_data['md5hash'] = hasher.hexdigest() # Right now if pygccxml is not installed, it will only handle the make function # TODO: extend this to other publicly declared functions in the h file if not PYGCCXML_AVAILABLE: self.parsed_data['parser'] = 'simple' (params, iosig, blockname) = self._parse_cc_h(self.target_file) self.parsed_data['target_namespace'] = namespace_to_parse namespace_dict = {} namespace_dict['name'] = "::".join(namespace_to_parse) class_dict = {} class_dict['name'] = blockname mf_dict = { "name": "make", "return_type": "::".join(namespace_to_parse + [blockname, "sptr"]), "has_static": "1" } args = [] for p in params: arg_dict = { "name": p['key'], "dtype": p['type'], "default": p['default'] } args.append(arg_dict) mf_dict["arguments"] = args class_dict["member_functions"] = [mf_dict] namespace_dict["classes"] = [class_dict] self.parsed_data["namespace"] = namespace_dict return self.parsed_data else: self.parsed_data['parser'] = 'pygccxml' 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', undefine_symbols=['__PIE__'], define_symbols=self.define_symbols, cflags='-std=c++17 -fPIC') decls = parser.parse([self.target_file], xml_generator_config) global_namespace = declarations.get_global_namespace(decls) # namespace # try: main_namespace = global_namespace for ns in namespace_to_parse: main_namespace = main_namespace.namespace(ns) if main_namespace is None: raise BlockToolException('namespace cannot be none') self.parsed_data['target_namespace'] = namespace_to_parse self.parsed_data['namespace'] = self.parse_namespace( main_namespace) # except RuntimeError: # raise BlockToolException( # 'Invalid namespace format in the block header file') # namespace return self.parsed_data
def parse_file(filename): # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator(name='castxml') # Configure the xml generator xml_generator_config = parser.xml_generator_configuration_t( # cflags="-std=gnu++11", cflags="-Wno-c++11-extensions", include_paths=["/Users/markoates/Repos/allegro_flare/include"], xml_generator_path=generator_path, compiler="g++", xml_generator=generator_name) # Parse the c++ file decls = parser.parse([filename], xml_generator_config) # output some GOLD! global_namespace = declarations.get_global_namespace(decls) # Search for functions which return a double. Two functions will be found criteria = declarations.calldef_matcher( #return_type="float", #header_file="/Users/markoates/Repos/allegro_flare/include/allegro_flare/" + filename) header_file=os.path.abspath(filename)) # criteria = declarations.calldef_matcher(return_type=double_type) found_items = declarations.matcher.find(criteria, global_namespace) # populate the table with unique names count = 0 for item in found_items: count = count + 1 #print item.location.file_name + " : " + str(item.location.line) cleaned_filename = re.match( r'/Users/markoates/Repos/allegro_flare/(.*)', item.location.file_name).group(1) # create `declaration_type` declaration_type = item.__class__.__name__ if declaration_type[-2:] == "_t": declaration_type = declaration_type[:-2] declaration_type = declaration_type.replace('_', ' ') declaration_type = "%s" % declaration_type # create `declaration` declaration = str(item) declaration = re.match(r'(.*) \[.*\]$', declaration).group(1) parse_cache_make_table_connection.execute( "INSERT INTO parsed_declarations VALUES (NULL,?,?,?,?,?,?,?,?,?,?,?,?);", (str(item), item.decl_string, declaration, item.name, declaration_type, str(item.parent.name), str( item.top_parent.name), item.attributes, cleaned_filename, str(item.location.line), "", "")) parse_cache_connection.commit() # create a list of unique items unique_item_names = set() for item in found_items: unique_item_names.update({item.name}) # cross-correlate declarations in the database docs_connection = sqlite3.connect('doc_entries.db') docs_connection.row_factory = sqlite3.Row docs_c = docs_connection.cursor() found_items = 0 unfound_items = 0 for item in unique_item_names: docs_c.execute('SELECT * FROM entries WHERE decl=?', (item, )) entries = docs_c.fetchall() if len(entries) == 0: print item unfound_items += 1 else: print_green(item + " - FOUND") found_items += 1 if unfound_items == 0: print_func = print_green elif found_items == 0: print_func = print_red else: print_func = print_yellow print_func("==============================") print_func(str(found_items) + " items found.") print_func(str(unfound_items) + " matches missing.") print_func("==============================") return
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 generate_python_wrapper(header_directories, include_paths, library_name, cpp_filename, declarations, main_namespace="", ignore_declarations={}, ignore_files={}): """ Function to generate Python-C++ binding code by calling pygccxml and py++ :param header_directories: directories with headers to create python binding for :type header_directories: list<string> :param include_paths: directories required as includes for the header files :type include_paths: list<string> :param library_name: the output name of the library to be created :type library_name: string :param cpp_filename: the output name of the C++ file to be created :type cpp_filename: string :param declarations: a list of declarations to be used for starting the AST syntax tree. See also pygccxml start_with_declarations or either -fxml-start(gccxml) or -castxml-start(castxml) :type declarations: list<string> :param ignore_declarations: a list of declarations to be ignored when generating C++ code :type ignore_declarations: list<string> :param ignore_files: a list of files to be ignored :type ignore_files: list<string> :return: """ warnings.filterwarnings(action="once", category=DeprecationWarning) # Find out the xml generator (gccxml or castxml) generator_path, generator_name = utils.find_xml_generator() compiler = "g++" compiler_path = "/usr/bin/g++" # Create configuration for CastXML xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, compiler=compiler, compiler_path=compiler_path, start_with_declarations=declarations) # Set include dirs and cflags to avoid warnings and errors xml_generator_config.append_cflags("-std=c++11") for inc_dir in include_paths: xml_generator_config.include_paths.append(inc_dir) for header_dir in header_directories: xml_generator_config.include_paths.append(header_dir) # Find all relevant headers header_list = list() for header_dir in header_directories: header_list = header_list + get_list_of_files( header_dir, ignore_files=ignore_files) # Parses the source files and creates a module_builder object builder = module_builder.module_builder_t( header_list, xml_generator_path=generator_path, compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE, xml_generator_config=xml_generator_config, indexing_suite_version=2) # for some reason there is a problem with variables named 'length' # the filename is empty and the line no is set to -1 # therefore the declaration is not processed in the code later on # this is to fix length struct members for decl in builder.decls("length"): if isinstance(decl, decl_wrappers.variable_wrapper.variable_t): if isinstance(decl.parent, decl_wrappers.class_wrapper.class_t): if decl.ignore: decl.location.file_name = decl.parent.location.file_name decl.location.line = decl.parent.location.line + 1 decl.ignore = False if main_namespace != "": if main_namespace.startswith("::"): main_namespace = main_namespace[2:] top_namespace_split = main_namespace.find(":") top_namespace = "" if top_namespace_split > 1: top_namespace = main_namespace[:top_namespace_split + 2] print( "Main namespace defined, namespace filtering enabled: top-namespace '{}' main-namespace '{}'" .format(top_namespace, main_namespace)) for decl in builder.decls(): for ignore_declaration in ignore_declarations: if ignore_declaration in decl.name or ignore_declaration in decl.alias: decl.exclude() decl.ignore = True decl.already_exposed = True # print("declaration to ignore found: {} (alias {})".format(decl, decl.alias)) break if main_namespace != "": if isinstance( decl, decl_wrappers.class_wrapper.class_t) or isinstance( decl, decl_wrappers.class_wrapper. class_declaration_t) or isinstance( decl, decl_wrappers.typedef_wrapper.typedef_t): decl_full_string = "{}".format(decl) if main_namespace in decl_full_string: # namespace present, ok # print("typedef/class main namespace found: {}".format(decl_full_string)) continue if decl_full_string in main_namespace: # declaration is a parent of main namespace, ok # print("typedef/class declaration of upper level namespace found: {}".format(decl_full_string)) continue if top_namespace != "" and not top_namespace in decl_full_string: # global or std defaults, ok # print("typedef/class outside top namespace found: {}".format(decl_full_string)) continue # print("typedef/class outside of main namespace found. Ignoring: {}".format(decl_full_string)) decl.exclude() decl.ignore = True decl.already_exposed = True # debug declarations # builder.print_declarations() # Automatically detect properties and associated getters/setters builder.classes().add_properties(exclude_accessors=True) # Define a name for the module builder.build_code_creator(module_name=library_name) # Writes the C++ interface file if os.path.exists(cpp_filename): os.remove(cpp_filename) builder.write_module(cpp_filename) print("generate_python_wrapper(): {} written.".format(cpp_filename))
from pygccxml import utils from pygccxml import declarations from pygccxml import parser import os import sys import warnings warnings.simplefilter("error", Warning) # Find out the file location within the sources tree this_module_dir_path = os.path.abspath( os.path.dirname(sys.modules[__name__].__file__)) # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name) # The c++ file we want to parse filename = "example.hpp" filename = this_module_dir_path + "/" + filename # Parse the c++ file decls = parser.parse([filename], xml_generator_config) # Get access to the global namespace global_namespace = declarations.get_global_namespace(decls)
if b'\x00' in dat: length = dat.index(b'\x00') return dat[:length] else: return dat[:16] def get_formatted(self, data): return repr(data)[1:] with open(os.path.join(os.path.dirname(__file__), "../stm/src/common/slots.h"), "r") as f: full_text = f.read() # parse the file gp, gn = utils.find_xml_generator() xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=gp, xml_generator=gn) declarations_in_file = parser.parse_string(full_text, xml_generator_config) def _convert_opaque_to_token(x): """ convert either a string from re or a value from pygccxml to a struct token """ if type(x) is str: return { "BOOL": "?", "UINT8_T": "B",
# See http://www.boost.org/LICENSE_1_0.txt from pygccxml import utils from pygccxml import declarations from pygccxml import parser import os import sys import warnings warnings.simplefilter("error", Warning) # Find out the file location within the sources tree this_module_dir_path = os.path.abspath( os.path.dirname(sys.modules[__name__].__file__)) # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name) # The c++ file we want to parse filename = "example.hpp" filename = this_module_dir_path + "/" + filename # Parse the c++ file decls = parser.parse([filename], xml_generator_config) # Get access to the global namespace global_namespace = declarations.get_global_namespace(decls)
def __init__(self, license='//greetings earthling', cpp_revision=201103): self.license = license logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser( description='Generate Python Bindings') parser.add_argument('-I', '--include', dest='includes', action='append') parser.add_argument('-D', '--define', dest='defines', action='append') parser.add_argument('-o', '--output_dir', dest='output_dir', action='store') parser.add_argument('-M', '--module_name', dest='module_name', action='store') parser.add_argument('--dep_module', dest='dep_modules', action='append', default=[]) parser.add_argument('--decl_db', dest='decl_dbs', action='append', default=[]) parser.add_argument('sources', nargs='+') self.args = parser.parse_args() # Find the location of the xml generator (castxml or gccxml) generator_path, generator_name = utils.find_xml_generator() # Configure the xml generator xml_generator_config = gccxmlparser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name, include_paths=self.args.includes, define_symbols=self.args.defines) self.mb = pyplusplus.module_builder.module_builder_t( self.args.sources, working_directory=os.path.abspath(os.path.curdir), indexing_suite_version=2, cplusplus_revision=cpp_revision, xml_generator_config=xml_generator_config) self.number_of_files = -1 try: os.makedirs(self.args.output_dir) except OSError: pass with open(os.path.join(self.args.output_dir, 'generate.sh'), 'w') as f: f.writelines([ '#!/bin/sh\n', 'export PYTHONPATH="{}"\n'.format( os.pathsep.join(sys.path).replace('"', '\\"').strip(':')), 'ipython $@ -- {}\n'.format(' \\\n'.join(sys.argv)) ]) for cls in self.mb.classes(allow_empty=True): cls.redefine_operators = False # Register dependency modules so that already exposed declarations are # known to us decl_db_ext = '.exposed_decl.pypp.txt' for decl_db in self.args.decl_dbs: if not os.path.exists(decl_db): raise ValueError('Couldn\'t find "%s"' % decl_db) if not decl_db.endswith(decl_db_ext): raise ValueError('Invalid file ending on "%s", expected "%s"' % (decl_db, decl_db_ext)) module = os.path.basename(decl_db)[:-len(decl_db_ext)] self.mb.register_module_dependency(decl_db, module) # Store the aliases of already exposed declarations self.already_exposed_aliases = [(d, d.alias) for d in self.mb.global_ns.decls() if d.already_exposed] for module in self.args.dep_modules: self.mb.add_registration_code('bp::import("%s");' % module, False)