module System.Plugins (load) where import qualified BasicTypes import qualified DynFlags import qualified Encoding import qualified Exception import qualified FastString import qualified GHC import qualified GHC.Exts import qualified GHC.Paths (libdir) import qualified Linker import qualified Module import MonadUtils (liftIO) import qualified Name import qualified ObjLink import qualified OccName import qualified Packages import qualified SrcLoc import qualified Unique import Unsafe.Coerce load :: (String, String, String) -> IO (Maybe a) load symbol@(packageName, moduleName, symbolName) = GHC.defaultErrorHandler DynFlags.defaultDynFlags $ do GHC.runGhc (Just GHC.Paths.libdir) $ do flags <- GHC.getSessionDynFlags GHC.setSessionDynFlags flags (flags, _) <- liftIO $ Packages.initPackages flags liftIO $ Linker.initDynLinker flags let packageId = Module.fsToPackageId (FastString.mkFastString packageName) Exception.ghandle (\(GHC.CmdLineError _) -> do liftIO $ putStrLn $ "Unknown package " ++ packageName ++ "." return Nothing) (do liftIO $ Linker.linkPackages flags [packageId] Exception.ghandle (\(GHC.ProgramError string) -> do if (hasPrefix string "Failed to load interface ") then liftIO $ putStrLn $ "Unknown module " ++ moduleName ++ " in package " ++ packageName ++ "." else liftIO $ putStrLn $ "Unknown symbol " ++ symbolName ++ " in module " ++ moduleName ++ " in package " ++ packageName ++ "." return Nothing) (do session <- GHC.getSession let name = Name.mkExternalName (Unique.mkBuiltinUnique 0) (Module.mkModule packageId (Module.mkModuleName moduleName)) (OccName.mkVarOcc symbolName) SrcLoc.noSrcSpan result <- liftIO $ Linker.getHValue session name return $ Just $ unsafeCoerce result)) encodeSymbol :: (String, String, String) -> String encodeSymbol (packageName, moduleName, symbolName) = (Encoding.zEncodeString packageName) ++ "_" ++ (Encoding.zEncodeString moduleName) ++ "_" ++ (Encoding.zEncodeString symbolName) ++ "_closure" hasPrefix :: String -> String -> Bool hasPrefix string prefix = take (length prefix) string == prefix