--
-- Copyright (c) 2004-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
-- GPL version 2 or later (see http://www.gnu.org/copyleft/gpl.html)
--
--
-- | Boot loader for lambdabot.
-- This is a small stub that loads the dynamic code, then jumps to it.
-- It solves the problem of unnecessary code linking. As such, we only
-- want to do plugin-related stuff here.
--
-- We should have no static dependencies on any other part of lambdabot.
--
-- This is the only module that depends on -package plugins.
--
-- Compile with:
-- ghc-6.4 -fglasgow-exts -package plugins -main-is Boot.main Boot.hs
--
module Boot ( main ) where
import qualified Shared as S
import System.Plugins.Load
import Data.Map (Map)
import qualified Data.Map as M hiding (Map)
import Data.IORef
import System.IO.Unsafe ( unsafePerformIO )
import System.Exit ( exitFailure )
lambdabotMain :: [Char]
lambdabotMain = lambdaPath ++ "Main.o" -- entry point into yi lib
-- path to plugins
lambdaPath :: String
lambdaPath = "./dist/build/lambdabot/lambdabot-tmp/"
mainSym :: Symbol
mainSym = "dynmain" -- main entry point
-- | get a handle to Main.dynamic_main, and jump to it. 6.2.2 will need posix.
--
-- todo, link statically and dynamically, a module with a Module type we
-- can convert hs-plugins type to.
--
main :: IO ()
main = do
status <- load lambdabotMain [lambdaPath] [] mainSym
dynmain <- case status of
LoadSuccess _ v -> return (v :: MainType) -- should stick module in ioref
LoadFailure e -> do putStrLn "Unable to load Main, exiting"
mapM_ putStrLn e
exitFailure
dynmain hsplugins
------------------------------------------------------------------------
-- Plugin.Loader wrappers passed over to the
type MainType = S.DynLoad -> IO ()
-- | should insert m into a local IORef, for unload to work
dLoad :: String -> String -> IO (S.Module,a)
dLoad p s = do
mm <- load_ (lambdaPath ++ p) [lambdaPath] s
case mm of
LoadFailure e -> error ("dLoad: "++show e) -- throw this back to DynamicModule
LoadSuccess m v -> do
atomicModifyIORef modules $ \fm -> (M.insert (path m) m fm, ())
return (S.Module (path m),v)
-- | Unload a module, given the path to that module
dUnload :: S.Module -> IO ()
dUnload (S.Module p) = do
mm <- atomicModifyIORef modules $ \fm ->
case M.lookup p fm of
Nothing -> (fm,Nothing) -- fail silently
Just m -> (M.delete p fm, Just m)
case mm of
Nothing -> return ()
Just m -> unload m
--
-- | Dynamic loader package we pass over.
--
hsplugins :: S.DynLoad
hsplugins = S.DynLoad {
S.dynload = dLoad,
S.unload = dUnload
}
--
-- map module paths to hs-plugins' Module type. Saves us linking
-- hs-plugins statically and dynamically (code bloat)
--
modules :: IORef (Map FilePath Module)
modules = unsafePerformIO $ newIORef (M.empty)
{-# NOINLINE modules #-}