Reputation: 30513
I am trying to load and execute module dynamically,
Below is my code
TestModule.hs
module TestModule
where
evaluate = "Hello !!!"
Invoke.hs
module Invoke
where
import GHC
import DynFlags
import GHC.Paths (libdir)
import Unsafe.Coerce (unsafeCoerce)
import Data.Dynamic
execFnGhc :: String -> String -> Ghc a
execFnGhc modname fn = do
mod <- findModule (mkModuleName modname) Nothing
--setContext [IIModule mod]
GHC.setContext [ GHC.IIDecl $ (GHC.simpleImportDecl . GHC.mkModuleName $ modname) {GHC.ideclQualified = True} ]
value <- compileExpr (modname ++ "." ++ fn)
let value' = (unsafeCoerce value) :: a
return value'
Main2.hs
import GHC.Paths (libdir)
import GHC
import Invoke
-- import TestModule
main :: IO ()
main = runGhc (Just libdir) $ do
str <- execFnGhc "TestModule" "evaluate"
return str
When I try to run the program it show me below error
[root@vps mypproj]# ./Main2
Main2: <command line>: module is not loaded: `TestModule' (./TestModule.hs)
Not sure what I am missing, Can someone please help me resolve this error
Upvotes: 11
Views: 419
Reputation: 26742
I was reading the relevant GHC source code recently, and it looks like findModule
doesn't work on local modules (TestModule.hs
in your case) unless they've already been loaded. (It works on modules in remote packages, however.)
To do GHCi style dynamic loading of compiled modules, your best bet is to use addTarget
and load
. As was mentioned in the comments, you also need to initialize the session dynamic flags. Here is a working version of your code:
module Invoke
where
import GHC
import DynFlags
import GHC.Paths (libdir)
import Unsafe.Coerce (unsafeCoerce)
import Data.Dynamic
execFnGhc :: String -> String -> Ghc String
execFnGhc modname fn = do
dflags <- getDynFlags
setSessionDynFlags dflags
let target = Target (TargetModule (mkModuleName modname)) True Nothing
addTarget target
load (LoadUpTo (mkModuleName modname))
mod <- findModule (mkModuleName modname) Nothing
GHC.setContext [ GHC.IIDecl $ (GHC.simpleImportDecl . GHC.mkModuleName $ modname) {GHC.ideclQualified = True} ]
value <- compileExpr (modname ++ "." ++ fn)
let value' = (unsafeCoerce value) :: String
return value'
What are the parameters of Target
? The first is the module name; the second is whether or not we should be allowed to load object code, or always interpret the module; the last is an optional string buffer which you could use to override the source code in the actual file (it's Nothing
because we don't need this.)
How did I figure this out? I looked at the code that GHCi uses to implement this in the GHC source code, as well as the compiler/main/GHC.hs
. I've found this is the most reliable way to figure out how to get the GHC API to do what you want.
Confusing? The GHC API was not so much designed as accreted...
Upvotes: 0
Reputation: 845
My thought would be the problem has something to do with your path,and that the program silently errors when it can't load "TestModule," then complains that the module is not loaded. Have you tried using execFnGhc with a module that is already loaded, and have you tried loading a module that is in GHC naturally, such as Text.Parsec, then executing something in it?
I'd test myself, but I don't see a GHC.Paths library anywhere :/.
Upvotes: 1