2013-04-05 50 views
11

我试图加载和动态执行模块,GHC 7.4.2,动态调用模块

下面是我的代码

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 

当我尝试运行它,它告诉我下面的错误

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

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

+0

我对此并不了解很多,但是看起来你可以用[plugins](http://hackage.haskell)更容易地做到这一点。 org/package/plugins)包。 – Almanildo 2013-04-11 08:54:59

回答

1

我的想法是这个问题有什么处理你的路径,当程序无法加载“TestModule”时,程序默默地出错,然后抱怨模块没有加载。你有没有尝试过使用execFnGhc加载了一个已经加载的模块,并且你尝试过加载GHC中的模块,比如Text.Parsec,然后在其中执行一些东西?

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

+0

我试过列表长度,str <-execFnGhc“Data.List”“length [1,2,3]”,但它抛出异常为“Main:Main:panic!(发生'不可能') (GHC版本7.4.2 x86_64的未知Linux的): \t没有包状态尚未:致电GHC.setSessionDynFlags 请报告这是一个错误GHC:http://www.haskell.org/ghc/reportabug “ – Xinus 2013-04-21 10:00:56

+0

从错误,它看起来像你可以使用execFnGhc之前,你需要为GHC设置“会话标志”。试着看看GHC的类型。setSessionFlags,并可能看到“GHC.getSessionFlags”是否存在;它看起来像GHC需要更多的信息才能调用事物。 – 2013-04-22 19:36:56

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的参数是什么?首先是模块名称;第二个是应该允许我们加载目标代码,还是总是解释模块;最后一个是可选的字符串缓冲区,您可以使用它来覆盖实际文件中的源代码(因为我们不需要这个文件,所以它可以用来替代源代码。)

我怎么知道这一点?我查看了GHCi在GHC源代码中使用的代码以及compiler/main/GHC.hs。我发现这是找出如何让GHC API做你想做的事的最可靠的方法。

混乱? GHC API并没有像增加的那样设计太多......