#===- common.py - Python LLVM Bindings -----------------------*- python -*--===#
#
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#

from ctypes import POINTER
from ctypes import c_void_p
from ctypes import cdll

import ctypes.util

__all__ = [
    'c_object_p',
    'find_library',
    'get_library',
]

c_object_p = POINTER(c_void_p)

class LLVMObject(object):
    """Base class for objects that are backed by an LLVM data structure.

    This class should never be instantiated outside of this package.
    """
    def __init__(self, ptr, ownable=True, disposer=None):
        assert isinstance(ptr, c_object_p)

        self._ptr = self._as_parameter_ = ptr

        self._self_owned = True
        self._ownable = ownable
        self._disposer = disposer

        self._owned_objects = []

    def take_ownership(self, obj):
        """Take ownership of another object.

        When you take ownership of another object, you are responsible for
        destroying that object. In addition, a reference to that object is
        placed inside this object so the Python garbage collector will not
        collect the object while it is still alive in libLLVM.

        This method should likely only be called from within modules inside
        this package.
        """
        assert isinstance(obj, LLVMObject)

        self._owned_objects.append(obj)
        obj._self_owned = False

    def from_param(self):
        """ctypes function that converts this object to a function parameter."""
        return self._as_parameter_

    def __del__(self):
        if not hasattr(self, '_self_owned') or not hasattr(self, '_disposer'):
            return

        if self._self_owned and self._disposer:
            self._disposer(self)

class CachedProperty(object):
    """Decorator that caches the result of a property lookup.

    This is a useful replacement for @property. It is recommended to use this
    decorator on properties that invoke C API calls for which the result of the
    call will be idempotent.
    """
    def __init__(self, wrapped):
        self.wrapped = wrapped
        try:
            self.__doc__ = wrapped.__doc__
        except: # pragma: no cover
            pass

    def __get__(self, instance, instance_type=None):
        if instance is None:
            return self

        value = self.wrapped(instance)
        setattr(instance, self.wrapped.__name__, value)

        return value

def find_library():
    # FIXME should probably have build system define absolute path of shared
    # library at install time.
    for lib in ['LLVM-3.1svn', 'libLLVM-3.1svn', 'LLVM', 'libLLVM']:
        result = ctypes.util.find_library(lib)
        if result:
            return result

    return None

def get_library():
    """Obtain a reference to the llvm library."""
    lib = find_library()
    if not lib:
        raise Exception('LLVM shared library not found!')

    return cdll.LoadLibrary(lib)

@@ -427,16 +427,188 @@
 pes.util
+%0Aimport platform%0A%0A# LLVM_VERSION: sync with PACKAGE_VERSION in autoconf/configure.ac and CMakeLists.txt%0A#               but leave out the 'svn' suffix.%0ALLVM_VERSION = '3.3'
 %0A%0A__all_
@@ -635,28 +635,8 @@
 p',%0A
-    'find_library',%0A
     
@@ -2778,20 +2778,19 @@
 ue%0A%0Adef 
-find
+get
 _library
@@ -2801,73 +2801,331 @@
     
-# FIXME should probably have build system define absolute path of
+%22%22%22Obtain a reference to the llvm library.%22%22%22%0A%0A    # On Linux, ctypes.cdll.LoadLibrary() respects LD_LIBRARY_PATH%0A    # while ctypes.util.find_library() doesn't.%0A    # See http://docs.python.org/2/library/ctypes.html#finding-shared-libraries%0A    #%0A    # To make it possible to run the unit tests without installing the LLVM
  sha
@@ -3146,283 +3146,620 @@
 ary 
-a
+into a defaul
 t 
+l
 in
-stall time.%0A    for lib in %5B'LLVM-3.1svn', 'libLLVM-3.1svn', 'LLVM', 'libLLVM
+ker search path.  Always Try ctypes.cdll.LoadLibrary()%0A    # with all possible library names first, then try ctypes.util.find_library().%0A%0A    names = %5B'LLVM-' + LLVM_VERSION, 'LLVM-' + LLVM_VERSION + 'svn
 '%5D
-:
 %0A    
-    result = ctypes.util.find_library(lib)
+t = platform.system()%0A    if t == 'Darwin':%0A        pfx, ext = 'lib', '.dylib'
 %0A    
-    if result:%0A            return result%0A%0A    return None%0A%0Adef get_library():%0A    %22%22%22Obtain a reference to the llvm library.%22%22%22%0A    lib = 
+elif t == 'Windows':%0A        pfx, ext = '', '.dll'%0A    else:%0A        pfx, ext = 'lib', '.so'%0A%0A    for i in names:%0A        try:%0A            lib = cdll.LoadLibrary(pfx + i + ext)%0A        except OSError:%0A            pass%0A        else:%0A            return lib%0A%0A    for i in names:%0A        t = ctypes.util.
 find
@@ -3771,30 +3771,64 @@
 ary(
+i
 )%0A
+    
     if 
-not lib:%0A    
+t:%0A            return cdll.LoadLibrary(t)%0A
     
@@ -3881,38 +3881,4 @@
 !')%0A
-%0A    return cdll.LoadLibrary(lib)%0A

fix get_library()