Skip to content

Instantly share code, notes, and snippets.

@worldsayshi
Forked from jhartikainen/DynLoad.hs
Last active February 25, 2022 15:01
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save worldsayshi/8853946 to your computer and use it in GitHub Desktop.
Save worldsayshi/8853946 to your computer and use it in GitHub Desktop.
Example for loading Haskell source code dynamically using the GHC api
-----------------------------------------------------------------------------
-- | Example for loading Haskell source code dynamically using the GHC api
-- Tested on ghc 7.4.2
--
-- Useful links:
-- GHC api:
-- http://www.haskell.org/ghc/docs/latest/html/libraries/ghc/GHC.html
-- Wiki:
-- http://www.haskell.org/haskellwiki/GHC/As_a_library
-----------------------------------------------------------------------------
module DynLoad where
import GHC
import GhcMonad (liftIO)
import GHC.Paths (libdir)
import Name (getOccString)
import Data.Dynamic (fromDyn)
-- | List all exports of this module
-- and evaluate a symbol from a module DynTest
main =
runGhc (Just libdir) $ do
putString ":::Display exports of modules:::"
modSums <- initSession ["DynLoad","DynTest"]
let thisModSum = head modSums
exports <- listExports thisModSum
mapM_ putString exports
putString ":::Evaluate a name from module DynTest:::"
importDecl_RdrName <- parseImportDecl "import DynTest as D"
setContext [IIDecl importDecl_RdrName]
dynVal <- dynCompileExpr "D.aString"
liftIO $ print $ (fromDyn dynVal "nope-nothing")
-- | Init interactive session and load modules
initSession modStrNames = do
dflags <- getSessionDynFlags
setSessionDynFlags $ dflags {
hscTarget = HscInterpreted
, ghcLink = LinkInMemory
}
targets <- mapM
(\modStrName -> do
putString modStrName
target <- guessTarget ("*"++modStrName++".hs") Nothing
return target
) modStrNames
setTargets targets
load LoadAllTargets
modSums <- mapM
(\modStrName -> do
putString modStrName
modSum <- getModSummary $ mkModuleName modStrName
return $ ms_mod modSum
) modStrNames
return modSums
-- | List exported names of this or a sibling module
listExports mod = do
maybeModInfo <- getModuleInfo mod
case maybeModInfo of
(Just modInfo) -> do
let expNames = modInfoExports modInfo
expStrNames = map getOccString expNames
return expStrNames
_ -> return []
-- | Util for printing
putString = liftIO . putStrLn
module DynTest where
aString = "Hello"
@worldsayshi
Copy link
Author

Compiled but untested atm.

@worldsayshi
Copy link
Author

Here's ghc (api) docs (somewhat hard to google):
http://www.haskell.org/platform/doc/2013.2.0.0/ghc-api/GHC.html

@worldsayshi
Copy link
Author

Completely rewritten. Cleaner now. Tested on ghc 7.4.2

@NorfairKing
Copy link

Is there a way to get it to load a module given an absolute path to that module?

@worldsayshi
Copy link
Author

Not sure, haven't tried anything like that. You might want to try setting the importPaths dynflag in the setSessionDynFlags call above to import modules at other paths.

Disclaimer: It was quite a while since I worked with this problem.

@worldsayshi
Copy link
Author

Also, look at the filepath argument to runGhc. Here I use libdir from the ghc-paths package.

@worldsayshi
Copy link
Author

Here's one way of doing it: replace guessTarget ("*"++modStrName++".hs") above with guessTarget ("/full/path/to/my/source/Foobar.hs")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment