{-# LANGUAGE Trustworthy #-} {-# OPTIONS_GHC -Wno-trustworthy-safe #-} ----------------------------------------------------------------------------- -- | -- Module : System.Posix.DynamicLinker.Prim -- Copyright : (c) Volker Stolz 2003 -- License : BSD-style (see the file libraries/base/LICENSE) -- -- Maintainer : vs@foldr.org -- Stability : provisional -- Portability : non-portable (requires POSIX) -- -- @dlopen(3)@ and friends -- Derived from @GModule.chs@ by M.Weber & M.Chakravarty which is part of c2hs. -- I left the API more or less the same, mostly the flags are different. -- ----------------------------------------------------------------------------- module System.Posix.DynamicLinker.Prim ( -- * low level API c_dlopen, c_dlsym, c_dlerror, c_dlclose, -- dlAddr, -- XXX NYI haveRtldNext, haveRtldLocal, packRTLDFlags, RTLDFlags(..), packDL, DL(..), ) where #include "HsUnix.h" import Data.Bits ( (.|.) ) import Foreign.Ptr ( Ptr, FunPtr, nullPtr ) import Foreign.C.Types import Foreign.C.String ( CString ) #if !defined(HAVE_DLFCN_H) import Control.Exception ( throw ) import System.IO.Error ( ioeSetLocation ) import GHC.IO.Exception ( unsupportedOperation ) #endif -- |On some hosts (e.g. SuSe and Ubuntu Linux) @RTLD_NEXT@ (and -- @RTLD_DEFAULT@) are not visible without setting the macro -- @_GNU_SOURCE@. Since we don\'t want to define this macro, you can use -- the function 'haveRtldNext' to check whether the flag `Next` is -- available. Ideally, this will be optimized by the compiler so that it -- should be as efficient as an @#ifdef@. -- -- If you fail to test the flag and use it although it is undefined, -- 'packDL' will throw an error. haveRtldNext :: Bool #ifdef HAVE_RTLDNEXT haveRtldNext = True foreign import ccall unsafe "__hsunix_rtldNext" rtldNext :: Ptr a #else /* HAVE_RTLDNEXT */ haveRtldNext = False #endif /* HAVE_RTLDNEXT */ #ifdef HAVE_RTLDDEFAULT foreign import ccall unsafe "__hsunix_rtldDefault" rtldDefault :: Ptr a #endif /* HAVE_RTLDDEFAULT */ haveRtldLocal :: Bool haveRtldLocal = True {-# DEPRECATED haveRtldLocal "defaults to True" #-} -- |Flags for 'System.Posix.DynamicLinker.dlopen'. data RTLDFlags = RTLD_LAZY | RTLD_NOW | RTLD_GLOBAL | RTLD_LOCAL deriving (Show, Read) foreign import ccall unsafe "dlopen" c_dlopen :: CString -> CInt -> IO (Ptr ()) foreign import ccall unsafe "dlsym" c_dlsym :: Ptr () -> CString -> IO (FunPtr a) foreign import ccall unsafe "dlerror" c_dlerror :: IO CString foreign import ccall unsafe "dlclose" c_dlclose :: (Ptr ()) -> IO CInt packRTLDFlags :: [RTLDFlags] -> CInt packRTLDFlags flags = foldl (\ s f -> (packRTLDFlag f) .|. s) 0 flags packRTLDFlag :: RTLDFlags -> CInt #if defined(HAVE_DLFCN_H) packRTLDFlag RTLD_LAZY = #const RTLD_LAZY packRTLDFlag RTLD_NOW = #const RTLD_NOW packRTLDFlag RTLD_GLOBAL = #const RTLD_GLOBAL packRTLDFlag RTLD_LOCAL = #const RTLD_LOCAL #else {-# WARNING packRTLDFlag "operation will throw 'IOError' \"unsupported operation\" (CPP guard: @#if HAVE_DLFCN_H@)" #-} packRTLDFlag _ = throw (ioeSetLocation unsupportedOperation "packRTLDFlag") #endif // HAVE_DLFCN_H -- |Flags for 'System.Posix.DynamicLinker.dlsym'. Notice that 'Next' -- might not be available on your particular platform! Use -- 'haveRtldNext'. -- -- If 'RTLD_DEFAULT' is not defined on your platform, 'packDL' 'Default' -- reduces to 'nullPtr'. data DL = Null | Next | Default | DLHandle (Ptr ()) deriving (Show) packDL :: DL -> Ptr () packDL Null = nullPtr #ifdef HAVE_RTLDNEXT packDL Next = rtldNext #else packDL Next = error "RTLD_NEXT not available" #endif #ifdef HAVE_RTLDDEFAULT packDL Default = rtldDefault #else packDL Default = nullPtr #endif packDL (DLHandle h) = h