1-- | Platform-specific dynamic linking support. Add new platforms to this file
2-- through conditional compilation.
3{-# LANGUAGE ExistentialQuantification, CPP #-}
4module Util.DynamicLinker (ForeignFun(..), DynamicLib(..), tryLoadLib, tryLoadFn) where
8import Foreign.Ptr (Ptr(), nullPtr, FunPtr, nullFunPtr, castPtrToFunPtr)
11import System.Posix.DynamicLinker
12import System.FilePath.Posix ((</>))
14import qualified Control.Exception as Exception (catch, IOException)
15import System.Win32.DLL
16import System.Win32.Types
17import System.FilePath.Windows ((</>))
21hostDynamicLibExt :: String
23hostDynamicLibExt = "so"
25hostDynamicLibExt = "dylib"
27hostDynamicLibExt = "dll"
29hostDynamicLibExt = "so"
31hostDynamicLibExt = "so"
33hostDynamicLibExt = error $ unwords
34 [ "Undefined file extension for dynamic libraries"
35 , "in Idris' Util.DynamicLinker."
39data ForeignFun = forall a. Fun { fun_name :: String
40 , fun_handle :: FunPtr a
43data DynamicLib = Lib { lib_name :: String
47instance Eq DynamicLib where
48 (Lib a _) == (Lib b _) = a == b
50firstExisting :: [FilePath] -> IO (Maybe FilePath)
51firstExisting [] = return Nothing
52firstExisting (f:fs) = do exists <- doesFileExist f
57libFileName :: [FilePath] -> String -> IO String
58libFileName dirs lib = do let names = [lib, lib ++ "." ++ hostDynamicLibExt]
59 cwd <- getCurrentDirectory
60 found <- firstExisting $
61 map ("."</>) names ++ [d </> f | d <- cwd:dirs, f <- names]
62 return $ maybe (lib ++ "." ++ hostDynamicLibExt) id found
65tryLoadLib :: [FilePath] -> String -> IO (Maybe DynamicLib)
66tryLoadLib dirs lib = do filename <- libFileName dirs lib
67 handle <- dlopen filename [RTLD_NOW, RTLD_GLOBAL]
68 if undl handle == nullPtr
70 else return . Just $ Lib lib handle
73tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
74tryLoadFn fn (Lib _ h) = do cFn <- dlsym h fn
77 else return . Just $ Fun fn cFn
79tryLoadLib :: [FilePath] -> String -> IO (Maybe DynamicLib)
80tryLoadLib dirs lib = do filename <- libFileName dirs lib
81 handle <- Exception.catch (loadLibrary filename) nullPtrOnException
84 else return . Just $ Lib lib handle
85 where nullPtrOnException :: Exception.IOException -> IO DL
86 nullPtrOnException e = return nullPtr
87 -- `show e` will however give broken error message
89tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
90tryLoadFn fn (Lib _ h) = do cFn <- getProcAddress h fn
93 else return . Just $ Fun fn (castPtrToFunPtr cFn)
96-- no libffi, just add stubbs.
98data DynamicLib = Lib { lib_name :: String
103data ForeignFun = forall a. Fun { fun_name :: String
107tryLoadLib :: [FilePath] -> String -> IO (Maybe DynamicLib)
108tryLoadLib fps lib = do putStrLn $ "WARNING: Cannot load '" ++ lib ++ "' at compile time because Idris was compiled without libffi support."
111tryLoadFn :: String -> DynamicLib -> IO (Maybe ForeignFun)
112tryLoadFn fn lib = do putStrLn $ "WARNING: Cannot load '" ++ fn ++ "' at compile time because Idris was compiled without libffi support."
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list