1#===- common.py - Python LLVM Bindings -----------------------*- python -*--===#
2#
3#                     The LLVM Compiler Infrastructure
4#
5# This file is distributed under the University of Illinois Open Source
6# License. See LICENSE.TXT for details.
7#
8#===------------------------------------------------------------------------===#
9
10from ctypes import POINTER
11from ctypes import c_void_p
12from ctypes import cdll
13
14import ctypes.util
15
16__all__ = [
17    'c_object_p',
18    'find_library',
19    'get_library',
20]
21
22c_object_p = POINTER(c_void_p)
23
24class LLVMObject(object):
25    """Base class for objects that are backed by an LLVM data structure.
26
27    This class should never be instantiated outside of this package.
28    """
29    def __init__(self, ptr, ownable=True, disposer=None):
30        assert isinstance(ptr, c_object_p)
31
32        self._ptr = self._as_parameter_ = ptr
33
34        self._self_owned = True
35        self._ownable = ownable
36        self._disposer = disposer
37
38        self._owned_objects = []
39
40    def take_ownership(self, obj):
41        """Take ownership of another object.
42
43        When you take ownership of another object, you are responsible for
44        destroying that object. In addition, a reference to that object is
45        placed inside this object so the Python garbage collector will not
46        collect the object while it is still alive in libLLVM.
47
48        This method should likely only be called from within modules inside
49        this package.
50        """
51        assert isinstance(obj, LLVMObject)
52
53        self._owned_objects.append(obj)
54        obj._self_owned = False
55
56    def from_param(self):
57        """ctypes function that converts this object to a function parameter."""
58        return self._as_parameter_
59
60    def __del__(self):
61        if not hasattr(self, '_self_owned') or not hasattr(self, '_disposer'):
62            return
63
64        if self._self_owned and self._disposer:
65            self._disposer(self)
66
67class CachedProperty(object):
68    """Decorator that caches the result of a property lookup.
69
70    This is a useful replacement for @property. It is recommended to use this
71    decorator on properties that invoke C API calls for which the result of the
72    call will be idempotent.
73    """
74    def __init__(self, wrapped):
75        self.wrapped = wrapped
76        try:
77            self.__doc__ = wrapped.__doc__
78        except: # pragma: no cover
79            pass
80
81    def __get__(self, instance, instance_type=None):
82        if instance is None:
83            return self
84
85        value = self.wrapped(instance)
86        setattr(instance, self.wrapped.__name__, value)
87
88        return value
89
90def find_library():
91    # FIXME should probably have build system define absolute path of shared
92    # library at install time.
93    for lib in ['LLVM-3.1svn', 'libLLVM-3.1svn', 'LLVM', 'libLLVM']:
94        result = ctypes.util.find_library(lib)
95        if result:
96            return result
97
98    return None
99
100def get_library():
101    """Obtain a reference to the llvm library."""
102    lib = find_library()
103    if not lib:
104        raise Exception('LLVM shared library not found!')
105
106    return cdll.LoadLibrary(lib)
107