on dcd4007 help sign in
Idris-dev/src/Util/DynamicLinker.hs
88 lines 2.8 kB history raw
1-- | Platform-specific dynamic linking support. Add new platforms to this file
2-- through conditional compilation.
3{-# LANGUAGE ExistentialQuantification, CPP #-}
4module Util.DynamicLinker where
6#ifdef IDRIS_FFI
7import Foreign.LibFFI
8import Foreign.Ptr (nullPtr, FunPtr, nullFunPtr,castPtrToFunPtr)
9import System.Directory
10#ifndef WINDOWS
11import System.Posix.DynamicLinker
12#else
13import System.Win32.DLL
14import System.Win32.Types
15type DL = HMODULE
16#endif
18hostDynamicLibExt :: String
19#ifdef LINUX
20hostDynamicLibExt = "so"
21#elif MACOSX
22hostDynamicLibExt = "dylib"
23#elif WINDOWS
24hostDynamicLibExt = "dll"
25#else
26hostDynamicLibExt = error $ unwords
27 [ "Undefined file extension for dynamic libraries"
28 , "in Idris' Util.DynamicLinker."
29 ]
30#endif
32data ForeignFun = forall a. Fun { fun_name :: String
33 , fun_handle :: FunPtr a
34 }
36data DynamicLib = Lib { lib_name :: String
37 , lib_handle :: DL
38 }
40instance Eq DynamicLib where
41 (Lib a _) == (Lib b _) = a == b
43#ifndef WINDOWS
44tryLoadLib :: String -> IO (Maybe DynamicLib)
45tryLoadLib lib = do exactName <- doesFileExist lib
46 let filename = if exactName then lib else lib ++ "." ++ hostDynamicLibExt
47 handle <- dlopen filename [RTLD_NOW, RTLD_GLOBAL]
48 if undl handle == nullPtr
49 then return Nothing
50 else return . Just $ Lib lib handle
53tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
54tryLoadFn fn (Lib _ h) = do cFn <- dlsym h fn
55 if cFn == nullFunPtr
56 then return Nothing
57 else return . Just $ Fun fn cFn
58#else
59tryLoadLib :: String -> IO (Maybe DynamicLib)
60tryLoadLib lib = do exactName <- doesFileExist lib
61 let filename = if exactName then lib else lib ++ "." ++ hostDynamicLibExt
62 handle <- loadLibrary filename
63 if handle == nullPtr
64 then return Nothing
65 else return . Just $ Lib lib handle
67tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
68tryLoadFn fn (Lib _ h) = do cFn <- getProcAddress h fn
69 if cFn == nullPtr
70 then return Nothing
71 else return . Just $ Fun fn (castPtrToFunPtr cFn)
72#endif
73#else
74-- no libffi, just add stubbs.
76data DynamicLib = Lib { lib_name :: String
77 , lib_handle :: ()
78 }
79 deriving Eq
81tryLoadLib :: String -> IO (Maybe DynamicLib)
82tryLoadLib lib = do putStrLn $ "WARNING: Cannot load '" ++ lib ++ "' at compile time because Idris was compiled without libffi support."
83 return Nothing
86#endif