アイデア
こんにちは!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"
ドキュメントではあまり説明されていないため、文字列が単なるランダムなものである line が原因である可能性があります。ソースを調べると、最初のものは出力名で、2番目のものは「extCore_filename」であるように見えます。
もう 1 つの懸念事項は、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 ()