Импорт известной функции из уже скомпилированного двоичного файла, используя API или подсказку GHC

У меня есть модуль 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".

Это функция, которая компилирует данный модуль и возвращает, была ли успешной компиляция или нет. Он использует defaultRunGhc вспомогательная функция, которая определяется как:

import GHC.Paths (libdir)

defaultRunGhc :: Ghc a -> IO a
defaultRunGhc = defaultErrorHandler defaultDynFlags . runGhc (Just libdir)

А теперь функция для извлечения значения из скомпилированного модуля. Исходный код модуля не обязательно должен присутствовать на этом этапе.

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)

И это все!

plugins Пакет в любом случае проблематичен. Вы можете вместо этого взглянуть на подсказку.

Другие вопросы по тегам