packages feed

idris-0.9.9: src/Util/DynamicLinker.hs

-- | Platform-specific dynamic linking support. Add new platforms to this file
-- through conditional compilation.
{-# LANGUAGE ExistentialQuantification, CPP #-}
module Util.DynamicLinker where

import Foreign.LibFFI
import Foreign.Ptr (nullPtr, FunPtr, nullFunPtr,castPtrToFunPtr)
import System.Directory
#ifndef WINDOWS
import System.Posix.DynamicLinker
#else
import System.Win32.DLL
import System.Win32.Types
type DL = HMODULE
#endif

hostDynamicLibExt :: String
#ifdef LINUX
hostDynamicLibExt = "so"
#elif MACOSX
hostDynamicLibExt = "dylib"
#elif WINDOWS
hostDynamicLibExt = "dll"
#else
hostDynamicLibExt = error $ unwords
  [ "Undefined file extension for dynamic libraries"
  , "in Idris' Util.DynamicLinker."
  ]
#endif

data ForeignFun = forall a. Fun { fun_name :: String
                                , fun_handle :: FunPtr a
                                }

data DynamicLib = Lib { lib_name :: String
                      , lib_handle :: DL
                      }

#ifndef WINDOWS
tryLoadLib :: String -> IO (Maybe DynamicLib)
tryLoadLib lib = do exactName <- doesFileExist lib
                    let filename = if exactName then lib else lib ++ "." ++ hostDynamicLibExt
                    handle <- dlopen filename [RTLD_NOW, RTLD_GLOBAL]
                    if undl handle == nullPtr
                      then return Nothing
                      else return . Just $ Lib lib handle


tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
tryLoadFn fn (Lib _ h) = do cFn <- dlsym h fn
                            if cFn == nullFunPtr
                               then return Nothing
                               else return . Just $ Fun fn cFn
#else
tryLoadLib :: String -> IO (Maybe DynamicLib)
tryLoadLib lib = do exactName <- doesFileExist lib
                    let filename = if exactName then lib else lib ++ "." ++ hostDynamicLibExt
                    handle <- loadLibrary filename
                    if handle == nullPtr
                        then return Nothing
                        else return . Just $ Lib lib handle

tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
tryLoadFn fn (Lib _ h) = do cFn <- getProcAddress h fn
                            if cFn == nullPtr
                                then return Nothing
                                else return . Just $ Fun fn (castPtrToFunPtr cFn)
#endif