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