Использование GHC API для компиляции исходников Haskell в CORE и CORE в двоичный файл
Идея
Здравствуйте! Я хочу создать программу, которая будет генерировать ядро Haskell и использовать GHC API для дальнейшей компиляции в исполняемый файл. Но прежде чем я сделаю это, я хочу построить очень простой пример, показывающий, как мы можем просто скомпилировать исходники 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, а затем компилировать ядро в конечный исполняемый файл (используя GHC API). Промежуточный шаг необходим для дальнейшей замены на пользовательский CORE.
В качестве дополнительного вопроса - возможно ли в настоящее время предоставить GHC внешние файлы ядра, или эта функция еще не реализована, и мне придется создавать ядро вручную, используя 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 ()
2 ответа
Генерация текстового представления ядра здесь не проблема, потому что это можно сделать несколькими способами. Ты можешь использовать -fext-core
флаг для генерации .hcr
файлы и работать с ними, например, с помощью extcore. Существуют также другие пакеты, которые могут создавать дамп ядра, например, ghc-core или ghc-core-html.
Основной проблемой здесь является загрузка ghc-core в ghc
, Насколько я знаю, это было поддержано, но сейчас нет, потому что было мало интереса к его использованию, и со временем оно устарело.
Лучшее, что мы можем попробовать здесь, это копать больше в ghc
внутренности, найдите места, где используется ghc-core, и попробуйте изменить его там. Может быть, мы также можем попробовать создать плагин GHC и изменить ядро с ним.
Краткий ответ: как только вам понадобится объектный файл, вы используете компилятор c по вашему выбору для компиляции главной заглушки и ссылки на исполняемый файл.
Если у вас есть объектный файл, то последние шаги, которые должен выполнить GHC, выполняются в компоновщике и компиляторе C. Например, установив флаг -verbose и -keep-tmp-files для простого hello_world, последние три шага для меня после создания объектов были следующими:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-c' '/tmp/ghc29076_0/ghc29076_0.c' '-o' '/tmp/ghc29076_0/ghc29076_0.o' '-DTABLES_NEXT_TO_CODE' '-I/usr/lib/ghc/include'
*** C Compiler:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-c' '/tmp/ghc29076_0/ghc29076_0.s' '-o' '/tmp/ghc29076_0/ghc29076_1.o' '-DTABLES_NEXT_TO_CODE' '-I/usr/lib/ghc/include'
*** Linker:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-o' 'hello' 'hello.o' '-L/usr/lib/ghc/base-4.6.0.1' '-L/usr/lib/ghc/integer-gmp-0.5.0.0' '-L/usr/lib/ghc/ghc-prim-0.3.0.0' '-L/usr/lib/ghc' '/tmp/ghc29076_0/ghc29076_0.o' '/tmp/ghc29076_0/ghc29076_1.o' '-lHSbase-4.6.0.1' '-lHSinteger-gmp-0.5.0.0' '-lgmp' '-lHSghc-prim-0.3.0.0' '-lHSrts' '-lffi' '-lm' '-lrt' '-ldl' '-u' 'ghczmprim_GHCziTypes_Izh_static_info' '-u' 'ghczmprim_GHCziTypes_Czh_static_info' '-u' 'ghczmprim_GHCziTypes_Fzh_static_info' '-u' 'ghczmprim_GHCziTypes_Dzh_static_info' '-u' 'base_GHCziPtr_Ptr_static_info' '-u' 'ghczmprim_GHCziTypes_Wzh_static_info' '-u' 'base_GHCziInt_I8zh_static_info' '-u' 'base_GHCziInt_I16zh_static_info' '-u' 'base_GHCziInt_I32zh_static_info' '-u' 'base_GHCziInt_I64zh_static_info' '-u' 'base_GHCziWord_W8zh_static_info' '-u' 'base_GHCziWord_W16zh_static_info' '-u' 'base_GHCziWord_W32zh_static_info' '-u' 'base_GHCziWord_W64zh_static_info' '-u' 'base_GHCziStable_StablePtr_static_info' '-u' 'ghczmprim_GHCziTypes_Izh_con_info' '-u' 'ghczmprim_GHCziTypes_Czh_con_info' '-u' 'ghczmprim_GHCziTypes_Fzh_con_info' '-u' 'ghczmprim_GHCziTypes_Dzh_con_info' '-u' 'base_GHCziPtr_Ptr_con_info' '-u' 'base_GHCziPtr_FunPtr_con_info' '-u' 'base_GHCziStable_StablePtr_con_info' '-u' 'ghczmprim_GHCziTypes_False_closure' '-u' 'ghczmprim_GHCziTypes_True_closure' '-u' 'base_GHCziPack_unpackCString_closure' '-u' 'base_GHCziIOziException_stackOverflow_closure' '-u' 'base_GHCziIOziException_heapOverflow_closure' '-u' 'base_ControlziExceptionziBase_nonTermination_closure' '-u' 'base_GHCziIOziException_blockedIndefinitelyOnMVar_closure' '-u' 'base_GHCziIOziException_blockedIndefinitelyOnSTM_closure' '-u' 'base_ControlziExceptionziBase_nestedAtomically_closure' '-u' 'base_GHCziWeak_runFinalizzerBatch_closure' '-u' 'base_GHCziTopHandler_flushStdHandles_closure' '-u' 'base_GHCziTopHandler_runIO_closure' '-u' 'base_GHCziTopHandler_runNonIO_closure' '-u' 'base_GHCziConcziIO_ensureIOManagerIsRunning_closure' '-u' 'base_GHCziConcziSync_runSparks_closure' '-u' 'base_GHCziConcziSignal_runHandlers_closure'
Глядя на эти первые два файла, мы видим, что файл c просто:
#include "Rts.h"
extern StgClosure ZCMain_main_closure;
int main(int argc, char *argv[])
{
RtsConfig __conf = defaultRtsConfig;
__conf.rts_opts_enabled = RtsOptsSafeOnly;
return hs_main(argc, argv, &ZCMain_main_closure,__conf);
}
Не похоже, что это должно сильно измениться от проекта к проекту.
Файл сборки:
.section .debug-ghc-link-info,"",@note
.ascii "([\"-lHSbase-4.6.0.1\",\"-lHSinteger-gmp-0.5.0.0\",\"-lgmp\",\"-lHSghc-prim-0.3.0.0\",\"-lHSrts\",\"-lffi\ ",\"-lm\",\"-lrt\",\"-ldl\",\"-u\",\"ghczmprim_GHCziTypes_Izh_static_info\",\"-u\",\"ghczmprim_GHCziTypes_Czh_static _info\",\"-u\",\"ghczmprim_GHCziTypes_Fzh_static_info\",\"-u\",\"ghczmprim_GHCziTypes_Dzh_static_info\",\"-u\",\"bas e_GHCziPtr_Ptr_static_info\",\"-u\",\"ghczmprim_GHCziTypes_Wzh_static_info\",\"-u\",\"base_GHCziInt_I8zh_static_info \",\"-u\",\"base_GHCziInt_I16zh_static_info\",\"-u\",\"base_GHCziInt_I32zh_static_info\",\"-u\",\"base_GHCziInt_I64z h_static_info\",\"-u\",\"base_GHCziWord_W8zh_static_info\",\"-u\",\"base_GHCziWord_W16zh_static_info\",\"-u\",\"base _GHCziWord_W32zh_static_info\",\"-u\",\"base_GHCziWord_W64zh_static_info\",\"-u\",\"base_GHCziStable_StablePtr_stati c_info\",\"-u\",\"ghczmprim_GHCziTypes_Izh_con_info\",\"-u\",\"ghczmprim_GHCziTypes_Czh_con_info\",\"-u\",\"ghczmpri m_GHCziTypes_Fzh_con_info\",\"-u\",\"ghczmprim_GHCziTypes_Dzh_con_info\",\"-u\",\"base_GHCziPtr_Ptr_con_info\",\"-u\ ",\"base_GHCziPtr_FunPtr_con_info\",\"-u\",\"base_GHCziStable_StablePtr_con_info\",\"-u\",\"ghczmprim_GHCziTypes_Fal se_closure\",\"-u\",\"ghczmprim_GHCziTypes_True_closure\",\"-u\",\"base_GHCziPack_unpackCString_closure\",\"-u\",\"b ase_GHCziIOziException_stackOverflow_closure\",\"-u\",\"base_GHCziIOziException_heapOverflow_closure\",\"-u\",\"base _ControlziExceptionziBase_nonTermination_closure\",\"-u\",\"base_GHCziIOziException_blockedIndefinitelyOnMVar_closur e\",\"-u\",\"base_GHCziIOziException_blockedIndefinitelyOnSTM_closure\",\"-u\",\"base_ControlziExceptionziBase_neste dAtomically_closure\",\"-u\",\"base_GHCziWeak_runFinalizzerBatch_closure\",\"-u\",\"base_GHCziTopHandler_flushStdHan dles_closure\",\"-u\",\"base_GHCziTopHandler_runIO_closure\",\"-u\",\"base_GHCziTopHandler_runNonIO_closure\",\"-u\" ,\"base_GHCziConcziIO_ensureIOManagerIsRunning_closure\",\"-u\",\"base_GHCziConcziSync_runSparks_closure\",\"-u\",\" base_GHCziConcziSignal_runHandlers_closure\"],[],Nothing,RtsOptsSafeOnly,False,[],[])"
Что ж, это немного хуже, но похоже, что это список флагов компоновщика с каким-то gobbledygook, который был передан в GHC в конце. Я не уверен, что все то, что компоновщик не определил, и просмотр флагов компоновщика будет вашей самой большой домашней работой. Вам придется изменить эти флаги? Возможно, а может быть, только если зависимости изменятся.