使用GHC API将Haskell源代码编译为CORE和CORE
理念
你好! 我想创建一个程序,它将生成Haskell Core,并使用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
函数旁边的文档中的compileCoreToObj
:
[...]迄今为止只有一个独立的模块进行了测试。
但我希望它不会引入任何进一步的问题。
这个问题
创建此解决方案的最佳方式是什么? 我们如何创建一个最小化的工作示例,它将加载haskell源代码,将它们编译到CORE中,然后将内核编译为最终可执行文件(使用GHC API)。 中间步骤需要由定制CORE进一步替换。
作为一个侧面问题 - 目前是否可以向GHC提供外部核心文件,或者此功能尚未实现,我将不得不手动构建核心,使用GHC.Api(与编译为GHC核心相关)
更新
我终于能够创建一个小例子,允许加载一个模块并将其编译为.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 ()
生成核心的文本表示在这里不是问题,因为它可以以多种方式进行。 您可以使用-fext-core
标志来生成.hcr
文件,并使用例如extcore处理它们。 还有其他可以转储内核的软件包,例如ghc-core或ghc-core-html。
这里的主要问题是将ghc-core加载到ghc
。 据我所知,它得到了支持,但现在不支持,因为对它的使用兴趣不高,随着时间的推移它变得过时了。
我们可以在这里尝试的最好方法是深入挖掘ghc
内部,找到使用ghc-core的地方并尝试在那里修改它。 也许我们也可以尝试创建一个ghc插件并用它修改核心。
简短的回答:一旦你必须对象文件,你使用你选择的C编译器来编译一个主存根并链接到一个可执行文件中。
如果你有目标文件,GHC最后的步骤是在链接器和C编译器中完成。 例如,通过为简单的hello_world设置-verbose标志和-keep-tmp文件,在构建对象之后,最后三步是:
'/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,[],[])"
这有点糟糕,但看起来这些是链接器标志列表,最后传入GHC的一些gobbledygook。 我不确定链接器未定义的所有东西,并且查看链接器标志将成为您最大的功课。 你将不得不修改这些标志吗? 也许,也许只有依赖关系发生变化。
链接地址: http://www.djcxy.com/p/7523.html上一篇: Using GHC API to compile Haskell sources to CORE and CORE to binary