ghc 7.4.2,动态调用模块

时间:2013-04-05 02:04:54

标签: haskell ghc dynamic-loading

我正在尝试动态加载和执行模块,

以下是我的代码

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

当我尝试运行该程序时,它会向我显示以下错误

[root@vps mypproj]# ./Main2 
Main2: <command line>: module is not loaded: `TestModule' (./TestModule.hs)

不确定我缺少什么,有人可以帮我解决此错误

2 个答案:

答案 0 :(得分:1)

我的想法是问题与你的路径有关,并且当程序无法加载“TestModule”时程序会默默地出错,然后抱怨模块没有加载。您是否尝试将execFnGhc与已加载的模块一起使用,并且您是否尝试过自然地加载GHC中的模块,例如Text.Parsec,然后在其中执行某些操作?

我会测试自己,但我没有在任何地方看到GHC.Paths库:/。

答案 1 :(得分:0)

我最近正在阅读相关的GHC源代码,看起来findModule不适用于本地模块(在您的情况下为TestModule.hs),除非它们已经加载。 (但它适用于远程包中的模块。)

要对编译模块进行GHCi样式动态加载,最好的办法是使用addTargetload。正如评论中提到的,您还需要初始化会话动态标志。这是您的代码的工作版本:

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'

Target的参数是什么?第一个是模块名称;第二个是我们是否应该被允许加载目标代码,或者总是解释模块;最后一个是可选的字符串缓冲区,您可以使用它来覆盖实际文件中的源代码(它是Nothing因为我们不需要它。)

我是怎么想出来的?我查看了GHCi在GHC源代码中实现此代码的代码,以及compiler/main/GHC.hs。我发现这是了解如何让GHC API做你想做的最可靠的方法。

混淆? GHC API的设计并不像增加......