Импорт известной функции из уже скомпилированного двоичного файла, используя 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
Пакет в любом случае проблематичен. Вы можете вместо этого взглянуть на подсказку.