Идея
Здравствуйте! Я хочу создать программу, которая будет генерировать Haskell Core и будет использовать API GHC для дальнейшей компиляции в исполняемый файл. Но прежде чем я это сделаю, я хочу построить очень простой пример, показывая, как мы можем просто скомпилировать источники Haskell в CORE, а затем в двоичный файл.
Проблема
Я прочитал много документации и много раз пробовал у GHC Api, но пока безуспешно. Я начал с Официальное введение GHC Api и успешно скомпилировал примеры. В примерах показано использование следующих функций: parseModule
, typecheckModule
, desugarModule
, getNamesInScope
и getModuleGraph
, но не охватывает окончательный этап компиляции. С другой стороны, в api есть некоторые функции, имена которых связаны с проблемой, например HscMain. {HscCompileOneShot, hscCompileBatch} или GHC. {compileToCoreModule, compileCoreToObj}. Я попытался использовать их, но получаю ошибки во время выполнения, как в этом примере:
import GHC
import GHC.Paths ( libdir )
import DynFlags
targetFile = "Test.hs"
main :: IO ()
main = do
res <- example
return ()
example =
defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
let dflags' = foldl xopt_set dflags
[Opt_Cpp, Opt_ImplicitPrelude, Opt_MagicHash]
setSessionDynFlags dflags'
coreMod <- compileToCoreModule targetFile
compileCoreToObj False coreMod "foo" "bar"
return ()
который может быть скомпилирован с помощью ghc -package ghc Main.hs
и который приводит к следующей ошибке во время выполнения:
Main: panic! (the 'impossible' happened)
(GHC version 7.8.3 for x86_64-unknown-linux):
expectJust mkStubPaths
что, конечно же, может быть результатом неправильного использования API, в частности, из-за строки compileCoreToObj False coreMod "foo" "bar"
, поскольку строка является случайной, потому что в документации много говорится о них. Если мы посмотрим на источники, кажется, что первое - это имя вывода, а второе - "extCore_filename", что бы это ни было.
Еще одна тревожная вещь - комментарий в документации рядом с функцией compileCoreToObj
:
[...] До сих пор это было проверено с помощью одного автономного модуля.
Но я надеюсь, что это не приведет к дальнейшим проблемам.
Вопрос
Каков наилучший способ создания этого решения? Как мы можем создать минимальный рабочий пример, который будет загружать источники haskell, компилировать их в CORE и затем компилировать ядро в окончательный исполняемый файл (используя API GHC). Промежуточный шаг необходим для дальнейшей замены пользовательским CORE.
В качестве побочного вопроса - можно ли в настоящее время предоставить GHC внешние файлы ядра, или эта функция еще не реализована, и мне придется строить Core вручную, используя GHC.Api(связанный с: Компиляция в GHC Core)
Обновление
Наконец, я смог создать небольшой пример, позволяющий загрузить модуль и скомпилировать его в файлы .hi
и .o
. Это не решение проблемы, потому что это не позволяет мне заменить CORE и не связывает объектные файлы с исполняемыми файлами:
import GHC
import GHC.Paths ( libdir )
import DynFlags
import Linker
import Module
targetFile = "Test.hs"
main :: IO ()
main = do
res <- example
return ()
example =
defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
let dflags2 = dflags { ghcLink = LinkBinary
, hscTarget = HscAsm
}
let dflags' = foldl xopt_set dflags2
[Opt_Cpp, Opt_ImplicitPrelude, Opt_MagicHash]
setSessionDynFlags dflags'
setTargets =<< sequence [guessTarget "Test.hs" Nothing]
load LoadAllTargets
return ()