def main(): # type: () -> None parser = argparse.ArgumentParser() parser.add_argument("--genpybind-module", dest="module", required=True) parser.add_argument("--genpybind-parse", dest="executable", default="genpybind-parse") parser.add_argument("--genpybind-docstring", dest="docstring") parser.add_argument("--genpybind-include", nargs="+", dest="includes") parser.add_argument("--genpybind-isystem", nargs="+", dest="isystem") parser.add_argument("--genpybind-tag", nargs="+", dest="tags") parser.add_argument("--genpybind-from-ast", dest="from_ast") parser.add_argument('rest', nargs=argparse.REMAINDER) # args, rest_args = parser.parse_known_args() args = parser.parse_args() if args.from_ast: if args.rest: parser.error( "unexpected arguments with --genpybind-from-ast: {}".format(args.rest)) translation_unit = TranslationUnit.from_ast_file(args.from_ast) else: name = tempfile.mkdtemp(prefix="genpybind") ast_file = os.path.join(name, "genpybind.ast") try: rest = args.rest[:] if rest[0] == "--": del rest[0] status = subprocess.call( [args.executable, "-output-file", ast_file] + rest, stdout=sys.stderr) if status != 0: parser.error("genpybind-parse returned status {} when called with\n{}".format( status, rest)) translation_unit = TranslationUnit.from_ast_file(ast_file) finally: shutil.rmtree(name) if translation_unit.diagnostics: for diag in translation_unit.diagnostics: print("//", diag.format()) for diag_ in diag.children: print("//", " ", diag_.format()) toplevel_declarations = gather_declarations(translation_unit.cursor) print(expose_as( toplevel_declarations, module=args.module, doc=args.docstring, isystem=args.isystem, includes=args.includes, tags=args.tags, ))
def test_fail_from_ast_file(self): path = os.path.join(kInputsDir, 'non-existent.ast') try: tu = TranslationUnit.from_ast_file(path) except TranslationUnitLoadError: tu = None self.assertEqual(tu, None)
def test_fail_from_ast_file(): path = os.path.join(kInputsDir, 'non-existent.ast') try: tu = TranslationUnit.from_ast_file(path) except TranslationUnitLoadError: tu = None assert tu == None
def test_fail_from_ast_file(): path = os.path.join(kInputsDir, 'non-existent.ast') try: tu = TranslationUnit.from_ast_file(path) except TranslationUnitLoadError: tu = None assert tu is None
def parse_files(list_of_files: List[str]) -> Tuple[Any, List[Any]]: """ Use Clang to parse the provided list of files, and return a tuple of the Clang index, and the list of compiled ASTs (one for each compilation unit) """ idx = Index.create() t_units = [] # type: List[Any] # To avoid parsing the files all the time, store the parsed ASTs # of each compilation unit in a cache. if not os.path.exists(".cache"): os.mkdir(".cache") for i, filename in enumerate(list_of_files): cache_filename = '.cache/' + os.path.basename(filename) + "_cache" # Have I parsed this file before? if os.path.exists(cache_filename): # Yes, load from cache try: t_units.append( TranslationUnit.from_ast_file( cache_filename, idx)) print("[-] Loading cached AST for", filename) except TranslationUnitLoadError: print("[-] %3d%% Parsing " % ( 100*(i+1)/len(list_of_files)) + filename) t_units.append(idx.parse(filename)) t_units[-1].save(cache_filename) else: # No, parse it now. print("[-] %3d%% Parsing " % ( 100*(i+1)/len(list_of_files)) + filename) t_units.append(idx.parse(filename)) t_units[-1].save(cache_filename) return idx, t_units
def parse_files(list_of_files: List[str]) -> Tuple[Any, List[Any]]: """ Use Clang to parse the provided list of files. """ idx = Index.create() t_units = [] # type: List[Any] # To avoid parsing the files all the time, store the parsed ASTs # of each compilation unit in a cache. if not os.path.exists(".cache"): os.mkdir(".cache") for i, filename in enumerate(list_of_files): cache_filename = '.cache/' + os.path.basename(filename) + "_cache" # Have I parsed this file before? if os.path.exists(cache_filename): # Yes, load from cache try: t_units.append( TranslationUnit.from_ast_file(cache_filename, idx)) logging.info("[-] Loading cached AST for %s", filename) except TranslationUnitLoadError: # pragma: nocover logging.info("[-] %3d%% Parsing %s", (100 * (i + 1) / len(list_of_files)), filename) # pragma: nocover t_units.append(idx.parse(filename)) # pragma: nocover t_units[-1].save(cache_filename) # pragma: nocover else: # No, parse it now. logging.info("[-] %3d%% Parsing %s", (100 * (i + 1) / len(list_of_files)), filename) # ...to adapt to: .... filename, args=['-I ...', '-D ...'] t_units.append(idx.parse(filename)) t_units[-1].save(cache_filename) return idx, t_units
def test_fail_from_ast_file(): path = os.path.join(kInputsDir, 'non-existent.ast') try: index = Index.create() tu = TranslationUnit.from_ast_file(path, index=index) except TranslationUnitLoadError: tu = None assert tu == None
def test_load_pathlike(self): """Ensure TranslationUnits can be constructed from saved files - PathLike variant.""" tu = get_tu('int foo();') self.assertEqual(len(tu.diagnostics), 0) with save_tu(tu) as path: tu2 = TranslationUnit.from_ast_file(filename=path) self.assertEqual(len(tu2.diagnostics), 0) foo = get_cursor(tu2, 'foo') self.assertIsNotNone(foo) # Just in case there is an open file descriptor somewhere. del tu2
def test_load_pathlike(self): """Ensure TranslationUnits can be constructed from saved files - PathLike variant.""" tu = get_tu('int foo();') self.assertEqual(len(tu.diagnostics), 0) with save_tu(tu) as path: tu2 = TranslationUnit.from_ast_file(filename=str_to_path(path)) self.assertEqual(len(tu2.diagnostics), 0) foo = get_cursor(tu2, 'foo') self.assertIsNotNone(foo) # Just in case there is an open file descriptor somewhere. del tu2
def test_load(self): """Ensure TranslationUnits can be constructed from saved files.""" tu = get_tu('int foo();') self.assertEqual(len(tu.diagnostics), 0) with save_tu(tu) as path: self.assertTrue(os.path.exists(path)) self.assertGreater(os.path.getsize(path), 0) tu2 = TranslationUnit.from_ast_file(filename=path) self.assertEqual(len(tu2.diagnostics), 0) foo = get_cursor(tu2, 'foo') self.assertIsNotNone(foo) # Just in case there is an open file descriptor somewhere. del tu2
def test_load(): """Ensure TranslationUnits can be constructed from saved files.""" tu = get_tu('int foo();') assert len(tu.diagnostics) == 0 path = save_tu(tu) assert os.path.exists(path) assert os.path.getsize(path) > 0 tu2 = TranslationUnit.from_ast_file(filename=path) assert len(tu2.diagnostics) == 0 foo = get_cursor(tu2, 'foo') assert foo is not None # Just in case there is an open file descriptor somewhere. del tu2 os.unlink(path)
def main(prog_path, libclang_path, api_header, pch_dst, api_casts_dst, namespace_filter, function_filter, namespace_dst, *libclang_args): accept_from = set(namespace_filter.split(" ")) valid_function_prefixes = set(function_filter.split(" ")) Config.set_library_file(libclang_path) index = Index.create(excludeDecls=True) # We should really want to use a compilation database here, except that it's only supported by makefiles... tu = TranslationUnit.from_ast_file(pch_dst, index) filt = FFIFilter(lambda s: s[0] in accept_from, lambda x: any([x.displayname.startswith(prefix) for prefix in valid_function_prefixes]), solve_template_base_config(index, pch_dst)) code_gen = CodeGen(prog_path, pre_hook = lambda: ("namespace %s {" % (namespace_dst,), 4), post_hook = lambda indent: "}") with open(api_casts_dst, 'w') as out_handle: from os.path import abspath out_handle.write(code_gen(api_header, filt.exposed_types, filt.emit_table_for_TU(tu.cursor)))
def _ast_files_to_callinfo(directory): index = Index(conf.lib.clang_createIndex(False, True)) # don't list comprehend so we can get better error reporting units = [] for path in _ast_files(directory): try: units.append((os.path.abspath(path), TranslationUnit.from_ast_file(path, index))) except Exception as e: print("error parsing {}, python clang version might be different" "from compiled clang version?".format(path)) print(e.args) print(e.message) raise ci = CallInfo() for path, tu in units: for cursor in tu.cursor.get_children(): # seems hacky, probably misses c++ cases # stuff from includes has the include's filename if ((cursor.kind == CursorKind.VAR_DECL) and (cursor.location.file.name == tu.spelling)): ci.add_global(cursor) for path, tu in units: # WARNING: this will fail silently and unexpectedly if # the version of clang that generated the .ast files is # different from the python clang library sys.stderr.write(" processing ast file {}\n".format(path)) sys.stderr.flush() for cursor in tu.cursor.get_children(): if (cursor.kind == CursorKind.FUNCTION_DECL or cursor.kind == CursorKind.VAR_DECL): decl = ci.add_decl(cursor) ci.walk_decl(cursor, decl) return ci
def main(): # type: () -> None parser = argparse.ArgumentParser() parser.add_argument( "--genpybind-module", dest="module", required=True, help="name of the extension module (cf. PYBIND11_MODULE)") parser.add_argument( "--genpybind-parse", dest="executable", default="genpybind-parse", help="name of the tool used to extend/amend the abstract syntax tree") parser.add_argument( "--genpybind-docstring", dest="docstring", help="docstring of the extension module (cf. PYBIND11_MODULE)") parser.add_argument( "--genpybind-include", nargs="+", dest="includes", help="includes to add to the generated bindings file (added in \"\"") parser.add_argument( "--genpybind-isystem", nargs="+", dest="isystem", help="includes to add to the generated bindings file (added in <>)") parser.add_argument( "--genpybind-tag", nargs="+", dest="tags", help= "generate bindings for tagged parts; otherwise tagged parts will be omitted from binding generation" ) parser.add_argument( "--genpybind-from-ast", dest="from_ast", help= "read from already generated abstract syntax tree instead of calling genpybind-parse" ) parser.add_argument("--genpybind-output-files", dest="output_files", required=True, help="Comma-separated list of output file names.") parser.add_argument( 'rest', nargs=argparse.REMAINDER, help= "arguments to genpybind-parse; also including compiler flags for the regular processing of the translation unit corresponding to the header file" ) # args, rest_args = parser.parse_known_args() args = parser.parse_args() if args.from_ast: if args.rest: parser.error( "unexpected arguments with --genpybind-from-ast: {}".format( args.rest)) translation_unit = TranslationUnit.from_ast_file(args.from_ast) else: name = tempfile.mkdtemp(prefix="genpybind") ast_file = os.path.join(name, "genpybind.ast") try: rest = args.rest[:] if rest[0] == "--": del rest[0] status = subprocess.call( [args.executable, "-output-file", ast_file] + rest, stdout=sys.stderr) if status != 0: parser.error( "genpybind-parse returned status {} when called with\n{}". format(status, rest)) translation_unit = TranslationUnit.from_ast_file(ast_file) finally: shutil.rmtree(name) if translation_unit.diagnostics: for diag in translation_unit.diagnostics: print("//", diag.format()) for diag_ in diag.children: print("//", " ", diag_.format()) toplevel_declarations = gather_declarations(translation_unit.cursor) expose_as( toplevel_declarations, module=args.module, doc=args.docstring, isystem=args.isystem, includes=args.includes, tags=args.tags, output_files=args.output_files.split(','), )