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)
Не уверен, что мне не хватает, может кто-то помочь мне решить эту ошибку.
Ответы
Ответ 1
Моя мысль была бы связана с тем, что проблема имеет какое-то отношение к вашему пути, и что программа без ошибок совершает ошибки, когда она не может загрузить "TestModule", а затем жалуется, что модуль не загружен. Пробовали ли вы использовать execFnGhc с уже загруженным модулем и попробовали ли вы загружать модуль, который находится в GHC, например, Text.Parsec, а затем что-то что-то в нем делать?
Я бы проверил себя, но я не вижу библиотеки GHC.Paths где угодно:/.
Ответ 2
Недавно я читал соответствующий исходный код GHC, и похоже, что findModule
не работает с локальными модулями (TestModule.hs
в вашем случае), если они уже не были загружены. (Однако он работает с модулями в удаленных пакетах.)
Чтобы выполнить динамическую загрузку скомпилированных модулей в стиле GHCi, лучше всего использовать addTarget
и load
. Как уже упоминалось в комментариях, вам также необходимо инициализировать динамические флаги сессии. Вот рабочая версия вашего кода:
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
. Я нашел, что это самый надежный способ выяснить, как заставить API GHC делать то, что вы хотите.
Непонятный? API GHC был не столько сконструирован, как расшифрован...