问题
I'm trying to dynamically compile and load Haskell modules using GHC API. I understand the API fluctuates quite a bit from on one version to another so I'm specifically talking about GHC 7.6.*.
I have tried running the same code on MacOS and Linux. In both cases the Plugin module compiles fine but gives the following error on load: Cannot add module Plugin to context: not interpreted
The problem is similar to the one in this where the module would only load if it was compiled in the same run of the host program.
-- Host.hs: compile with ghc-7.6.*
-- $ ghc -package ghc -package ghc-paths Host.hs
-- Needs Plugin.hs in the same directory.
module Main where
import GHC
import GHC.Paths ( libdir )
import DynFlags
import Unsafe.Coerce
main :: IO ()
main =
defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
result <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
target <- guessTarget "Plugin.hs" Nothing
setTargets [target]
r <- load LoadAllTargets
case r of
Failed -> error "Compilation failed"
Succeeded -> do
setContext [IIModule (mkModuleName "Plugin")]
result <- compileExpr ("Plugin.getInt")
let result' = unsafeCoerce result :: Int
return result'
print result
And the plugin:
-- Plugin.hs
module Plugin where
getInt :: Int
getInt = 33
回答1:
The problem is that you're using IIModule
. This indicates that you want to bring the module and everything in it, including non-exported stuff into the context. It's essentially the same as :load
with an asterisk in GHCi. And as you've noticed, this only works with interpreted code since it let's you "look inside" the module.
But that's not what you need here. What you want is to load it as if you used :module
or an import
declaration, which works with compiled modules. For that, you use IIDecl
which takes an import declaration which you can make with simpleImportDecl
:
setContext [IIDecl $ simpleImportDecl (mkModuleName "Plugin")]
来源:https://stackoverflow.com/questions/16806460/dynamically-loading-compiled-haskell-module-ghc-7-6