def profile_project(): include_std_header = os.path.join(autoconfig.data_directory, 'include_std.hpp') reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path)) reader.read_files([include_std_header])
def parse(self): xml_generator_config = parser.xml_generator_configuration_t(xml_generator_path=self.castxml_binary, xml_generator="castxml", cflags="-std=c++11", include_paths=self.source_includes) print ("INFO: Parsing Code") decls = parser.parse([self.wrapper_header_collection], xml_generator_config, compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE) # Get access to the global namespace self.global_ns = declarations.get_global_namespace(decls) # Clean decls to only include those for which file locations exist print ("INFO: Cleaning Decls") query = declarations.custom_matcher_t(lambda decl: decl.location is not None) decls_loc_not_none = self.global_ns.decls(function=query) # Identify decls in our source tree def check_loc(loc): return (self.source_root in loc) or ("wrapper_header_collection" in loc) source_decls = [decl for decl in decls_loc_not_none if check_loc(decl.location.file_name)] self.source_ns = declarations.namespace_t("source", source_decls) print ("INFO: Optimizing Decls") self.source_ns.init_optimizer()
def _setEnvironment(self): # gccxml_09_path = os.path.join('/', 'usr', 'bin', 'castxml') ---> CASTXML will be used for C++11 syntax. # gccxml_09_path = os.path.join('/', 'usr', 'bin', 'gccxml') generator_path = os.path.join('/', 'usr', 'bin', 'castxml') generator_name = 'castxml' # generator_path, generator_name = pygccxml.utils.find_xml_generator() # Configure GCC-XML parser # config = parser.gccxml_configuration_t( # gccxml_path=gccxml_09_path, compiler='g++') xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path = generator_path, xml_generator = generator_name, ) #Location where sources files are stored and will be written. # headerFilesDirectory = os.path.join(currentModuleDirectoryPath, '..', 'headerFiles') # generatedFilesDirectory = os.path.join(currentModuleDirectoryPath, '..', 'generatedFiles') #The directory where header files reside. # self._file_directory = self._headerFilesDirectory + "\\" #Parsing source file self._decls = pygccxml.parser.parse([os.path.join(self._file_directory, self._file_name)], xml_generator_config)
def profile_project2(): he = r"2003\Vc7\PlatformSDK\Include\windows.h" include_std_header = r"D:\Program Files\Microsoft Visual Studio .NET " + he reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path)) reader.read_files([include_std_header])
def __parse_declarations(self, files, xml_generator_config, compilation_mode, cache, indexing_suite_version): if None is xml_generator_config: xml_generator_config = parser.xml_generator_configuration_t() if None is compilation_mode: compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE start_time = timer() self.logger.debug('parsing files - started') reader = parser.project_reader_t(xml_generator_config, cache, decl_wrappers.dwfactory_t()) decls = reader.read_files(files, compilation_mode) self.logger.debug('parsing files - done( %f seconds )' % (timer() - start_time)) self.logger.debug('settings declarations defaults - started') global_ns = decls_package.matcher.get_single( decls_package.namespace_matcher_t(name='::'), decls) if indexing_suite_version != 1: for cls in global_ns.classes(allow_empty=True): cls.indexing_suite_version = indexing_suite_version for cls in global_ns.decls( decl_type=decls_package.class_declaration_t, allow_empty=True): cls.indexing_suite_version = indexing_suite_version start_time = timer() self.__apply_decls_defaults(decls) self.logger.debug( 'settings declarations defaults - done( %f seconds )' % (timer() - start_time)) return global_ns
def parse_files(path, files): # Find the location of the xml generator (castxml or gccxml) #generator_path, generator_name = utils.find_xml_generator() #print("GENER " + generator_path) # Configure the xml generator args = { 'include_paths':[path], 'keep_xml': True } if(xml_generator != None): args['xml_generator'] =xml_generator if(xml_generator_path != None): args['xml_generator_path'] =xml_generator_path xml_generator_config = parser.xml_generator_configuration_t(**args) # not sure this actually does anything when compilation_mode is set to "ALL_AT_ONCE" def cache_file(filename): return parser.file_configuration_t( data=filename, content_type=parser.CONTENT_TYPE.CACHED_SOURCE_FILE, cached_source_file=filename.replace(path, "tmp/xml")+".xml") cached_files = [cache_file(f) for f in files] project_reader = parser.project_reader_t(xml_generator_config) decls = project_reader.read_files( cached_files, compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE) return declarations.get_global_namespace(decls)
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 __parse_declarations( self, files, xml_generator_config, compilation_mode, cache, indexing_suite_version ): if None is xml_generator_config: xml_generator_config = parser.xml_generator_configuration_t() if None is compilation_mode: compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE start_time = time.clock() self.logger.debug( 'parsing files - started' ) reader = parser.project_reader_t( xml_generator_config, cache, decl_wrappers.dwfactory_t() ) decls = reader.read_files( files, compilation_mode ) self.logger.debug( 'parsing files - done( %f seconds )' % ( time.clock() - start_time ) ) self.logger.debug( 'settings declarations defaults - started' ) global_ns = decls_package.matcher.get_single( decls_package.namespace_matcher_t( name='::' ) , decls ) if indexing_suite_version != 1: for cls in global_ns.classes(): cls.indexing_suite_version = indexing_suite_version for cls in global_ns.decls(decl_type=decls_package.class_declaration_t): cls.indexing_suite_version = indexing_suite_version start_time = time.clock() self.__apply_decls_defaults(decls) self.logger.debug( 'settings declarations defaults - done( %f seconds )' % ( time.clock() - start_time ) ) return global_ns
def parse_big_file(): path = os.path.join(autoconfig.data_directory, 'big.xml') reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.xml_generator_path)) reader.read_files([parser.create_gccxml_fc(path)]) reader.read_files([parser.create_gccxml_fc(path)]) reader.read_files([parser.create_gccxml_fc(path)])
def profile_project(): include_std_header = os.path.join( autoconfig.data_directory, 'include_std.hpp') reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path)) reader.read_files([include_std_header])
def test_on_big_file(file_name, count): file_name = os.path.join(autoconfig.data_directory, file_name) for i in range(count): reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path)) decls = reader.read_files([parser.create_gccxml_fc(file_name)]) global_ns = declarations.get_global_namespace(decls) global_ns.init_optimizer()
def test_project_on_include_std_dot_hpp(): include_std_header = os.path.join(autoconfig.data_directory, 'include_std.hpp') clock_prev = time.perf_counter() dcache = parser.file_cache_t(dcache_file_name) reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_files([include_std_header]) dcache.flush() clock_now = time.perf_counter() print(('without cache: %f seconds' % (clock_now - clock_prev))) clock_prev = time.perf_counter() dcache = parser.file_cache_t(dcache_file_name) reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_files([include_std_header]) clock_now = time.perf_counter() print(('with cache : %f seconds' % (clock_now - clock_prev)))
def test_on_windows_dot_h(): he = r"2003\Vc7\PlatformSDK\Include\windows.h" windows_header = r"D:\Program Files\Microsoft Visual Studio .NET " + he clock_prev = time.perf_counter() dcache = parser.file_cache_t(dcache_file_name) reader = parser.source_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_file(windows_header) dcache.flush() clock_now = time.perf_counter() print(('without cache: %f seconds' % (clock_now - clock_prev))) clock_prev = time.perf_counter() dcache = parser.file_cache_t(dcache_file_name) reader = parser.source_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_file(windows_header) clock_now = time.perf_counter() print(('with cache : %f seconds' % (clock_now - clock_prev)))
def test_source_on_include_std_dot_hpp(): include_std_header = os.path.join(autoconfig.data_directory, 'include_std.hpp') clock_prev = timeit.default_timer() dcache = parser.file_cache_t(dcache_file_name) reader = parser.source_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_file(include_std_header) dcache.flush() clock_now = timeit.default_timer() print('without cache: %f seconds' % (clock_now - clock_prev)) clock_prev = timeit.default_timer() dcache = parser.file_cache_t(dcache_file_name) reader = parser.source_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_file(include_std_header) clock_now = timeit.default_timer() print('with cache : %f seconds' % (clock_now - clock_prev))
def __parse_declarations( self, files, xml_generator_config, compilation_mode=None, cache=None ): if None is xml_generator_config: xml_generator_config = parser.xml_generator_configuration_t() if None is compilation_mode: compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE start_time = time.clock() self.logger.debug( 'parsing files - started' ) reader = parser.project_reader_t( xml_generator_config, cache, decl_wrappers.dwfactory_t() ) decls = reader.read_files( files, compilation_mode ) self.logger.debug( 'parsing files - done( %f seconds )' % ( time.clock() - start_time ) ) return decls_package.matcher.get_single( decls_package.namespace_matcher_t( name='::' ) , decls )
def test_on_windows_dot_h(): he = r"2003\Vc7\PlatformSDK\Include\windows.h" windows_header = r"D:\Program Files\Microsoft Visual Studio .NET " + he clock_prev = time.clock() dcache = parser.file_cache_t(dcache_file_name) reader = parser.source_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_file(windows_header) dcache.flush() clock_now = time.clock() print('without cache: %f seconds' % (clock_now - clock_prev)) clock_prev = time.clock() dcache = parser.file_cache_t(dcache_file_name) reader = parser.source_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_file(windows_header) clock_now = time.clock() print('with cache : %f seconds' % (clock_now - clock_prev))
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_project_on_include_std_dot_hpp(): include_std_header = os.path.join( autoconfig.data_directory, 'include_std.hpp') clock_prev = time.clock() dcache = parser.file_cache_t(dcache_file_name) reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_files([include_std_header]) dcache.flush() clock_now = time.clock() print('without cache: %f seconds' % (clock_now - clock_prev)) clock_prev = time.clock() dcache = parser.file_cache_t(dcache_file_name) reader = parser.project_reader_t( parser.xml_generator_configuration_t( xml_generator_path=autoconfig.generator_path), dcache) reader.read_files([include_std_header]) clock_now = time.clock() print('with cache : %f seconds' % (clock_now - clock_prev))
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 __parse_declarations(self, files, xml_generator_config, compilation_mode=None, cache=None): if None is xml_generator_config: xml_generator_config = parser.xml_generator_configuration_t() if None is compilation_mode: compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE start_time = timer() self.logger.debug('parsing files - started') reader = parser.project_reader_t(xml_generator_config, cache, decl_wrappers.dwfactory_t()) decls = reader.read_files(files, compilation_mode) self.logger.debug('parsing files - done( %f seconds )' % (timer() - start_time)) return decls_package.matcher.get_single( decls_package.namespace_matcher_t(name='::'), decls)
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 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 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 __init__( self , files , includes , symbols , is_client = False ): symbols = list(basesymbols + symbols) includepaths = incl_paths + includes includepaths = list(map(lambda p: p.replace('\\', '/'), includepaths)) includepaths = list(filter(os.path.normpath, includepaths)) self.definedsymbols = symbols self.includes = includepaths xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path='/usr/bin/castxml' , working_directory='.' , include_paths=includepaths , define_symbols=symbols , undefine_symbols=usymbols , start_with_declarations=None #, ignore_gccxml_output=False , cflags=cflags , compiler_path='gcc-4.7' , xml_generator='castxml' ) module_builder.module_builder_t.__init__( self , files , xml_generator_config=xml_generator_config , cache=None , optimize_queries=True , encoding='ascii' , compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE )
def generate_wrappers(args): module_name = args[1] work_dir = args[2] header_collection = args[3] castxml_binary = args[4] includes = args[5:] xml_generator_config = parser.xml_generator_configuration_t(xml_generator_path=castxml_binary, xml_generator="castxml", compiler = "gnu", compiler_path="/usr/bin/c++", include_paths=includes) builder = module_builder.module_builder_t([header_collection], xml_generator_path = castxml_binary, xml_generator_config = xml_generator_config, start_with_declarations = ['chaste'], include_paths = includes, indexing_suite_version=2) messages.disable(messages.W1040) # unexposed declaration messages.disable(messages.W1031) # user to expose non public member function # Don't wrap std library builder.global_ns.namespace('std').exclude() # Set up the builder for each module builder = do_module(module_name, builder) # Make the wrapper code builder.build_code_creator(module_name="_chaste_project_PyChaste_" + module_name) builder.code_creator.user_defined_directories.append(work_dir + "/dynamic/wrapper_headers/") builder.write_module(work_dir + "/dynamic/" + module_name + ".cpp") # Fix a bug with boost units boost_units_namespace_fix(work_dir + "/dynamic/" + module_name + ".cpp") strip_undefined_call_policies(work_dir + "/dynamic/" + module_name + ".cpp")
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))
#!/usr/bin/python from pygccxml import parser from pygccxml import declarations from pyplusplus import module_builder import sys generator_path = '/usr/bin/castxml' if len(sys.argv) > 1: generator_path = sys.argv[1] # Create configuration for CastXML xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator='castxml', compiler='gnu', compiler_path='/usr/bin/gcc', cflags='-std=c++11 -I../liblc3') # List of all the C++ header of our library header_collection = ["PyLC3.hpp", "../liblc3/lc3_all.hpp"] # Parses the source files and creates a module_builder object builder = module_builder.module_builder_t( header_collection, xml_generator_path='/usr/bin/castxml', xml_generator_config=xml_generator_config) # Debugging #builder.print_declarations() # Whitelist exporting of stuff.
from pygccxml import utils from pygccxml import declarations from pygccxml import parser import pygccxml import sys # 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, include_paths=[str(x[2:]) for x in sys.argv[2:]], cflags=' '.join(str(x) for x in sys.argv[2:])) # Parse the c++ file decls = parser.parse([sys.argv[1]], xml_generator_config) declarations.print_declarations(decls)
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
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) # Get access to the 'ns' namespace ns = global_namespace.namespace("ns")
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()
# Find out the file location within the sources tree this_module_dir_path = os.path.abspath( os.path.dirname(sys.modules[__name__].__file__)) # Add pygccxml package to Python path sys.path.append(os.path.join(this_module_dir_path, '..', '..')) from pygccxml import parser # nopep8 from pygccxml import declarations # nopep8 from pygccxml import utils # nopep8 # 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( xml_generator_path=generator_path, xml_generator=generator_name, compiler="gcc") # Parsing source file decls = parser.parse([this_module_dir_path + '/example.hpp'], config) global_ns = declarations.get_global_namespace(decls) # Get object that describes unittests namespace unittests = global_ns.namespace('unittests') print('"unittests" declarations: \n') declarations.print_declarations(unittests) # Print all base and derived class names for class_ in unittests.classes(): print('class "%s" hierarchy information:' % class_.name)
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 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' compiler_path = None 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: compiler_path='C:/msys32/mingw32/bin/clang++' 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") 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 ) #mb = module_builder.module_builder_t([xml_cached_fc], #xml_generator_path=casterpath, #working_directory=settings.gimli_path, #include_paths=settings.includesPaths, #define_symbols=defines, #indexing_suite_version=2, #compiler_path=compiler_path, #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.") try: hand_made_wrappers.apply(mb) except Exception 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', ] 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) try: mb.calldefs(access_type_matcher_t('protected')).exclude() mb.calldefs(access_type_matcher_t('private')).exclude() except: 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> &']) #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")
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 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 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 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 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 generate_wrappers(args): work_dir = args[1] header_collection = args[2] castxml_binary = args[3] module_name = args[4] includes = args[5:] xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=castxml_binary, xml_generator="castxml", #compiler = "gnu", #compiler_path="/usr/bin/c++", cflags="-std=c++11", include_paths=includes) builder = module_builder.module_builder_t( [header_collection], xml_generator_path=castxml_binary, xml_generator_config=xml_generator_config, start_with_declarations=['chaste'], include_paths=includes, #cflags = "-std=c++11", indexing_suite_version=2, cache=file_cache_t(work_dir + "/dynamic/wrappers/castxml_cache.xml")) messages.disable(messages.W1040) # unexposed declaration messages.disable( messages.W1031) # user to expose non public member function messages.disable(messages.W1023) # user to define some functions messages.disable(messages.W1014) # operator not supported messages.disable(messages.W1036) # can't expose immutable member variables # Don't wrap std or boost library builder.global_ns.namespace('std').exclude() builder.global_ns.namespace('boost').exclude() # Strip out Instantiation 'tricks' in the header file # todo - the first line is presumably no longer necessary builder.free_function("GetPetscMatForWrapper" ).call_policies = call_policies.return_value_policy( call_policies.return_opaque_pointer) builder.free_function("GetPetscMatForWrapper").exclude() builder.free_function("Instantiation").exclude() # Load the classes to be wrapped with open(work_dir + "/dynamic/wrappers/class_data.p", 'rb') as fp: classes = pickle.load(fp) possible_module_names = [module_name] possible_module_names = [ "core", "ode", "pde", "mesh", "cell_based", "tutorial", "visualization" ] if module_name == "All": possible_module_names = [ "core", "ode", "pde", "mesh", "cell_based", "tutorial", "visualization" ] for idx, eachModule in enumerate(possible_module_names): print 'Generating Wrapper Code for: ' + eachModule + ' Module.' if "core" not in eachModule and len(possible_module_names) > 1: builder.register_module_dependency(work_dir + "/dynamic/wrappers/" + possible_module_names[idx - 1]) # Set up the builder for each module print 'Starting Module: ' + eachModule + ' Module.' builder = do_module(eachModule, builder, work_dir + "/dynamic/wrappers/" + eachModule + "/", classes) # Make the wrapper code # builder.build_code_creator(module_name="_chaste_project_PyChaste_" + module_name, # doc_extractor=doxygen_extractor.doxygen_doc_extractor()) builder.build_code_creator(module_name="_chaste_project_PyChaste_" + eachModule) builder.code_creator.user_defined_directories.append(work_dir) builder.code_creator.user_defined_directories.append( work_dir + "/dynamic/wrappers/") builder.code_creator.user_defined_directories.append( work_dir + "/dynamic/wrappers/" + eachModule + "/") builder.code_creator.license = chaste_license file_list = builder.split_module(work_dir + "/dynamic/wrappers/" + eachModule) value_traits_files = [] for eachFile in file_list: if "__value_traits" in eachFile: value_traits_files.append(ntpath.basename(eachFile)) # Manually strip any undefined call policies we have missed. Strictly there should not be any/many. for file in os.listdir(work_dir + "/dynamic/wrappers/" + eachModule + "/"): if file.endswith(".cpp"): strip_undefined_call_policies(work_dir + "/dynamic/wrappers/" + eachModule + "/" + file) # Manually remove some value traits in std headers (https://mail.python.org/pipermail/cplusplus-sig/2008-April/013105.html) for file in os.listdir(work_dir + "/dynamic/wrappers/" + eachModule + "/"): if file.endswith(".cpp"): strip_value_traits( work_dir + "/dynamic/wrappers/" + eachModule + "/" + file, value_traits_files)
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", "INT8_T": "b", "UINT16_T": "H",
for ee in sorted(kernel_prio, key=lambda k: k[1]): if ee[0] in path: prio += ee[1] return prio elif len(files) >1: print(files) print('Error while finding {:}, found no match'.format(header_file)) else: return prio print('Error proccessing header {:}'.format(header)) # main loop if 'xml_generator_configuration_t' in dir(parser): config = parser.xml_generator_configuration_t(include_paths=include_paths, ignore_gccxml_output=False, keep_xml=True, xml_generator='castxml') else: config = parser.config_t(include_paths=include_paths, ignore_gccxml_output=True) decls = parser.parse(all_headers, config, compilation_mode=COMPILATION_MODE.ALL_AT_ONCE) global_ns = declarations.get_global_namespace(decls) # classes in siconos_namespace class_names = dict() # class name of classes with a least a base (for the boost archive # registration) with_base = [] # a typedef table to replace templated class by their typedefs in # macros call
def __init__( self , files , gccxml_path='' , xml_generator_path='' , working_directory='.' , include_paths=None , define_symbols=None , undefine_symbols=None , start_with_declarations=None , compilation_mode=None , cache=None , optimize_queries=True , ignore_gccxml_output=False , indexing_suite_version=1 , cflags="" , encoding='ascii' , compiler=None , gccxml_config=None , xml_generator_config=None): """ :param files: list of files, declarations from them you want to export :type files: list of strings or :class:`parser.file_configuration_t` instances :param xml_generator_path: path to gccxml/castxml binary. If you don't pass this argument, pygccxml parser will try to locate it using your environment PATH variable :type xml_generator_path: str :param include_paths: additional header files location. You don't have to specify system and standard directories. :type include_paths: list of strings :param define_symbols: list of symbols to be defined for preprocessor. :param define_symbols: list of strings :param undefine_symbols: list of symbols to be undefined for preprocessor. :param undefine_symbols: list of strings :param cflags: Raw string to be added to xml generator command line. :param xml_generator_config: instance of pygccxml.parser.xml_generator_configuration_t class, holds xml generator configuration. You can use this argument instead of passing the compiler configuration separately. :param gccxml_path: DEPRECATED :param gccxml_config: DEPRECATED """ module_builder.module_builder_t.__init__( self, global_ns=None, encoding=encoding ) # handle deprecated parameters if not gccxml_path == '' and xml_generator_path == '': xml_generator_path = gccxml_path if gccxml_config and not xml_generator_config: xml_generator_config = gccxml_config if not xml_generator_config: xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=xml_generator_path , working_directory=working_directory , include_paths=include_paths , define_symbols=define_symbols , undefine_symbols=undefine_symbols , start_with_declarations=start_with_declarations , ignore_gccxml_output=ignore_gccxml_output , cflags=cflags , compiler=compiler) #may be in future I will add those directories to user_defined_directories to self.__code_creator. self.__parsed_files = list(map( pygccxml_utils.normalize_path , parser.project_reader_t.get_os_file_names( files ) )) tmp = [os.path.split( file_ )[0] for file_ in self.__parsed_files] self.__parsed_dirs = [_f for _f in tmp if _f] self.global_ns = self.__parse_declarations( files , xml_generator_config , compilation_mode , cache , indexing_suite_version) self.global_ns.decls(recursive=True, allow_empty=True)._code_generator = decl_wrappers.CODE_GENERATOR_TYPES.CTYPES self.__code_creator = None if optimize_queries: self.run_query_optimizer() self.__declarations_code_head = [] self.__declarations_code_tail = [] self.__registrations_code_head = [] self.__registrations_code_tail = []
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 out the c++ 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, castxml_epic_version=1) # The c++ file we want to parse filename = "example.hpp" filename = this_module_dir_path + "/" + filename decls = parser.parse([filename], xml_generator_config) global_namespace = declarations.get_global_namespace(decls) a1 = global_namespace.variable("a1") print(str(a1.decl_type), type(a1.decl_type)) # > 'A', <class 'pygccxml.declarations.cpptypes.declarated_t'> print(declarations.is_elaborated(a1.decl_type)) # > False
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
return self.__aliasStrs def getEnumLines(self): return self.__enumStrs generator_path, generator_name = utils.find_xml_generator() if (generator_name != 'castxml'): print(generator_name + ' does not equal castxml. Please make sure castxml is installed.') sys.exit(1) # Configure the xml generator config = parser.xml_generator_configuration_t(\ xml_generator_path=generator_path,\ xml_generator=generator_name,\ cflags=flags) # find struct in vulkan headers for path in sys.argv[startIdx:]: #print (path) # Parsing source file decls = parser.parse([path], config) global_ns = declarations.get_global_namespace(decls) # generate vulkan type list code # iterate classes and get member information for clas in [ global_ns.classes(), global_ns.enumerations(), global_ns.typedefs() ]: #,global_ns.enumerations():
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")
this_module_dir_path = os.path.abspath( os.path.dirname(sys.modules[__name__].__file__)) # Add pygccxml package to Python path sys.path.append(os.path.join(this_module_dir_path, '..', '..')) from pygccxml import parser # nopep8 from pygccxml import declarations # nopep8 from pygccxml import utils # nopep8 # 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( xml_generator_path=generator_path, xml_generator=generator_name, compiler="gcc") # Parsing source file decls = parser.parse([this_module_dir_path + '/example.hpp'], config) global_ns = declarations.get_global_namespace(decls) # Get object that describes unittests namespace unittests = global_ns.namespace('unittests') print('"unittests" declarations: \n') declarations.print_declarations(unittests) # Print all base and derived class names for class_ in unittests.classes(): print('class "%s" hierarchy information:' % class_.name)