11

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

下面是我的代码

测试模块.hs

module TestModule
        where

evaluate = "Hello !!!"

调用.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)

不知道我错过了什么,有人可以帮我解决这个错误吗

4

2 回答 2

1

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

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

于 2013-04-08T03:57:33.390 回答
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 与其说是设计的不如说是增加的……

于 2014-11-21T00:51:44.957 回答