使用GHC的API或Hint从已编译的二进制文件导入已知函数

5 haskell hint ghc-api

我有一个模块Target,Target.accessMe里面有一个功能.我以某种方式编译这个模块,然后摆脱源代码.

现在,我必须做一系列神秘的咒语才能动态导入不同的程序Target.accessMe?这个程序accessMe提前知道了类型.另外,请考虑源代码Target不可用的事实.

plugins程序包设法完成此任务,但似乎在使用Windows时遇到严重问题.我已经检查了它plugins的来源,但我很难理解它.

我尝试过使用Hint,但只能找到如何评估我有源代码的代码.

谢谢你的帮助!

小智 2

这个问题的答案已经在其他地方给过我。GHC API 能够做到这一点。这里有两个函数,其中一个用于编译Target.hs,另一个用于访问Target.accessMe(并且不再需要模块的源代码Target)。

import GHC
import DynFlags

compile :: String -> IO SuccessFlag
compile name = defaultRunGhc $ do
  dynflags <- getSessionDynFlags
  let dynflags' = dynflags -- You can change various options here.
  setSessionDynFlags dynflags'

  -- (name) can be "Target.hs", "Target", etc.
  target <- guessTarget name Nothing
  addTarget target
  load LoadAllTargets -- Runs something like "ghc --make".
Run Code Online (Sandbox Code Playgroud)

这是一个编译给定模块并返回编译成功与否的函数。它使用defaultRunGhc定义为的辅助函数:

import GHC.Paths (libdir)

defaultRunGhc :: Ghc a -> IO a
defaultRunGhc = defaultErrorHandler defaultDynFlags . runGhc (Just libdir)
Run Code Online (Sandbox Code Playgroud)

现在是一个用于从编译模块中获取值的函数。此时模块的源代码不需要存在。

import Unsafe.Coerce (unsafeCoerce)

fetch :: String -> String -> IO Int -- Assumes we are fetching an Int value.
fetch name value = defaultRunGhc $ do
  -- Again, you can change various options in dynflags here, as above.
  dynflags <- getSessionDynFlags
  let m = mkModule (thisPackage dynflags) (mkModuleName name)
  setContext [] [(m, Nothing)] -- Use setContext [] [m] for GHC<7.

  fetched <- compileExpr (name ++ "." ++ value) -- Fetching "Target.accessMe".
  return (unsafeCoerce fetched :: Int)
Run Code Online (Sandbox Code Playgroud)

就是这样!