1#===- common.py - Python LLVM Bindings -----------------------*- python -*--===# 2# 3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4# See https://llvm.org/LICENSE.txt for license information. 5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6# 7#===------------------------------------------------------------------------===# 8 9from ctypes import POINTER 10from ctypes import c_void_p 11from ctypes import cdll 12 13import ctypes.util 14import platform 15 16# LLVM_VERSION: sync with PACKAGE_VERSION in CMakeLists.txt 17# but leave out the 'svn' suffix. 18LLVM_VERSION = '10.0.0' 19 20__all__ = [ 21 'c_object_p', 22 'get_library', 23] 24 25c_object_p = POINTER(c_void_p) 26 27class LLVMObject(object): 28 """Base class for objects that are backed by an LLVM data structure. 29 30 This class should never be instantiated outside of this package. 31 """ 32 def __init__(self, ptr, ownable=True, disposer=None): 33 assert isinstance(ptr, c_object_p) 34 35 self._ptr = self._as_parameter_ = ptr 36 37 self._self_owned = True 38 self._ownable = ownable 39 self._disposer = disposer 40 41 self._owned_objects = [] 42 43 def take_ownership(self, obj): 44 """Take ownership of another object. 45 46 When you take ownership of another object, you are responsible for 47 destroying that object. In addition, a reference to that object is 48 placed inside this object so the Python garbage collector will not 49 collect the object while it is still alive in libLLVM. 50 51 This method should likely only be called from within modules inside 52 this package. 53 """ 54 assert isinstance(obj, LLVMObject) 55 56 self._owned_objects.append(obj) 57 obj._self_owned = False 58 59 def from_param(self): 60 """ctypes function that converts this object to a function parameter.""" 61 return self._as_parameter_ 62 63 def __del__(self): 64 if not hasattr(self, '_self_owned') or not hasattr(self, '_disposer'): 65 return 66 67 if self._self_owned and self._disposer: 68 self._disposer(self) 69 70class CachedProperty(object): 71 """Decorator that caches the result of a property lookup. 72 73 This is a useful replacement for @property. It is recommended to use this 74 decorator on properties that invoke C API calls for which the result of the 75 call will be idempotent. 76 """ 77 def __init__(self, wrapped): 78 self.wrapped = wrapped 79 try: 80 self.__doc__ = wrapped.__doc__ 81 except: # pragma: no cover 82 pass 83 84 def __get__(self, instance, instance_type=None): 85 if instance is None: 86 return self 87 88 value = self.wrapped(instance) 89 setattr(instance, self.wrapped.__name__, value) 90 91 return value 92 93def get_library(): 94 """Obtain a reference to the llvm library.""" 95 96 # On Linux, ctypes.cdll.LoadLibrary() respects LD_LIBRARY_PATH 97 # while ctypes.util.find_library() doesn't. 98 # See http://docs.python.org/2/library/ctypes.html#finding-shared-libraries 99 # 100 # To make it possible to run the unit tests without installing the LLVM shared 101 # library into a default linker search path. Always Try ctypes.cdll.LoadLibrary() 102 # with all possible library names first, then try ctypes.util.find_library(). 103 104 names = ['LLVM-' + LLVM_VERSION, 'LLVM-' + LLVM_VERSION + 'svn'] 105 t = platform.system() 106 if t == 'Darwin': 107 pfx, ext = 'lib', '.dylib' 108 elif t == 'Windows': 109 pfx, ext = '', '.dll' 110 else: 111 pfx, ext = 'lib', '.so' 112 113 for i in names: 114 try: 115 lib = cdll.LoadLibrary(pfx + i + ext) 116 except OSError: 117 pass 118 else: 119 return lib 120 121 for i in names: 122 t = ctypes.util.find_library(i) 123 if t: 124 return cdll.LoadLibrary(t) 125 raise Exception('LLVM shared library not found!') 126