#LIBCLANG_FILENAME = '/home/vstinner/llvm-project/_build/lib/libclang.so' LIBCLANG_FILENAME = "/usr/lib64/llvm6.0/lib/libclang.so" from ctypes import c_char_p, c_void_p, c_int, Structure, POINTER, c_ulong, cdll import unittest c_object_p = POINTER(c_void_p) def b(x): if isinstance(x, bytes): return x return x.encode('utf8') class ClangObject(object): def __init__(self, obj): assert isinstance(obj, c_object_p) and obj self.obj = self._as_parameter_ = obj def from_param(self): return self._as_parameter_ class _CXUnsavedFile(Structure): _fields_ = [("name", c_char_p), ("contents", c_char_p), ('length', c_ulong)] class Cursor(Structure): _fields_ = [("_kind_id", c_int), ("xdata", c_int), ("data", c_void_p * 3)] class Index(ClangObject): pass class TranslationUnit(ClangObject): def __init__(self, ptr): ClangObject.__init__(self, ptr) def from_source(lib, index): source = """ class test_class { public: void public_member_function(); protected: void protected_member_function(); private: void private_member_function(); }; """ filename = 't.cpp' args = ['-std=c++11'] unsaved_files=[(filename, source)] options=0 args_array = (c_char_p * len(args))(*[b(x) for x in args]) unsaved_array = None if len(unsaved_files) > 0: unsaved_array = (_CXUnsavedFile * len(unsaved_files))() for i, (name, contents) in enumerate(unsaved_files): if hasattr(contents, "read"): contents = contents.read() contents = b(contents) unsaved_array[i].name = b(name) unsaved_array[i].contents = contents unsaved_array[i].length = len(contents) func = lib.clang_parseTranslationUnit func.argtypes = [Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int] func.restype = c_object_p ptr = func(index, filename.encode('utf8'), args_array, len(args), unsaved_array, len(unsaved_files), options) if not ptr: raise Exception assert isinstance(index, Index) return TranslationUnit(ptr) def test_access_specifiers(): lib = cdll.LoadLibrary(LIBCLANG_FILENAME) # define the class her to get 'lib' variable in __del__ class _CXString(Structure): _fields_ = [("spelling", c_char_p), ("free", c_int)] def __del__(self): print("_CXString del: obj id=%x" % id(self)) func = lib.clang_disposeString func.argtypes = [_CXString] func(self) func = lib.clang_getTranslationUnitCursor func.argtypes = [TranslationUnit] func.restype = Cursor func2 = lib.clang_getCursorSpelling func2.argtypes = [Cursor] func2.restype = _CXString func3 = lib.clang_createIndex func3.argtypes = [c_int, c_int] func3.restype = c_object_p index = Index(func3(False, 0)) tu = from_source(lib, index) cursor = func(tu) print("spelling") spelling = func2(cursor) print("spelling = None") spelling = None print("spelling = None ---") cursor = None func = lib.clang_disposeIndex func.argtypes = [Index] func(index) index = tu.index = None func = lib.clang_disposeTranslationUnit func.argtypes = [TranslationUnit] func(tu) tu = None if __name__ == "__main__": test_access_specifiers()