on 86e32fb help sign in
Idris-dev/src/Util/DynamicLinker.hs
90 lines 2.9 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#elif FREEBSD
26hostDynamicLibExt = "so"
27#else
28hostDynamicLibExt = error $ unwords
29 [ "Undefined file extension for dynamic libraries"
30 , "in Idris' Util.DynamicLinker."
31 ]
32#endif
34data ForeignFun = forall a. Fun { fun_name :: String
35 , fun_handle :: FunPtr a
36 }
38data DynamicLib = Lib { lib_name :: String
39 , lib_handle :: DL
40 }
42instance Eq DynamicLib where
43 (Lib a _) == (Lib b _) = a == b
45#ifndef WINDOWS
46tryLoadLib :: String -> IO (Maybe DynamicLib)
47tryLoadLib lib = do exactName <- doesFileExist lib
48 let filename = if exactName then lib else lib ++ "." ++ hostDynamicLibExt
49 handle <- dlopen filename [RTLD_NOW, RTLD_GLOBAL]
50 if undl handle == nullPtr
51 then return Nothing
52 else return . Just $ Lib lib handle
55tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
56tryLoadFn fn (Lib _ h) = do cFn <- dlsym h fn
57 if cFn == nullFunPtr
58 then return Nothing
59 else return . Just $ Fun fn cFn
60#else
61tryLoadLib :: String -> IO (Maybe DynamicLib)
62tryLoadLib lib = do exactName <- doesFileExist lib
63 let filename = if exactName then lib else lib ++ "." ++ hostDynamicLibExt
64 handle <- loadLibrary filename
65 if handle == nullPtr
66 then return Nothing
67 else return . Just $ Lib lib handle
69tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
70tryLoadFn fn (Lib _ h) = do cFn <- getProcAddress h fn
71 if cFn == nullPtr
72 then return Nothing
73 else return . Just $ Fun fn (castPtrToFunPtr cFn)
74#endif
75#else
76-- no libffi, just add stubbs.
78data DynamicLib = Lib { lib_name :: String
79 , lib_handle :: ()
80 }
81 deriving Eq
83tryLoadLib :: String -> IO (Maybe DynamicLib)
84tryLoadLib lib = do putStrLn $ "WARNING: Cannot load '" ++ lib ++ "' at compile time because Idris was compiled without libffi support."
85 return Nothing
88#endif