Xinus
Xinus

Reputation: 30513

ghc 7.4.2, Dynamically calling modules

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

Answers (2)

Edward Z. Yang
Edward Z. Yang

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

Marshall Conover
Marshall Conover

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

Related Questions