L'ideaUtilizzando GHC API per compilare sorgenti Haskell a Core e Core a binario
Ciao! Voglio creare un programma, che genererà Haskell Core e userà GHC API per compilarlo ulteriormente in un eseguibile. Ma prima di farlo, voglio costruire un esempio molto semplice, mostrando come possiamo semplicemente compilare i sorgenti di Haskell in CORE e poi nel file binario.
Il problema
Ho letto un sacco di documentazione e provato molti metodi da GHC Api, ma per ora senza successo. Ho iniziato con Official GHC Api introduction e ho compilato correttamente gli esempi. Gli esempi mostrano l'utilizzo delle seguenti funzioni: parseModule
, typecheckModule
, desugarModule
, getNamesInScope
e getModuleGraph
ma non copre la fase di compilazione finale. D'altra parte, ci sono alcune funzioni nell'API, i cui nomi sembrano correlati al problema, ad esempio HscMain.{hscCompileOneShot, hscCompileBatch} o GHC.{compileToCoreModule, compileCoreToObj}. Ho cercato di usarle, ma si verificano errori di esecuzione, come in questo esempio:
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()
che può essere compilato con ghc -package ghc Main.hs
e che provoca il seguente errore durante il runtime:
Main: panic! (the 'impossible' happened)
(GHC version 7.8.3 for x86_64-unknown-linux):
expectJust mkStubPaths
che naturalmente può essere il risultato di un utilizzo API errato, in particolare, a causa della riga compileCoreToObj False coreMod "foo" "bar"
, dove la stringa è solo casuale, perché la documentazione non dice molto su di essi. Se esaminiamo le fonti, sembra che il primo sia il nome dell'output e il secondo sia "extCore_filename", qualunque esso sia.
Un'altra cosa preoccupante è il commento nella documentazione accanto alla funzione compileCoreToObj
:
[...] Questo è solo finora stato testato con un singolo modulo autonomo.
Ma spero che non introduca ulteriori problemi.
La domanda
Qual è il miglior modo possibile per creare questa soluzione? Come possiamo creare un esempio di lavoro minimale, che caricherà i sorgenti di haskell, li compilerà nel CORE e quindi compilerà il core per l'eseguibile finale (usando l'API GHC). Il passaggio intermedio è necessario per un'ulteriore sostituzione da parte del CORE personalizzato.
Come un lato-domanda - è attualmente possibile fornire GHC con file principali esterni o questa funzione non è ancora implementata e dovrà costruire Core manualmente, utilizzando GHC.Api (relative a: Compiling to GHC Core)
Aggiornamento
sono stato finalmente in grado di creare un piccolo esempio che permette il caricamento di un modulo e compilarlo per .hi
e .o
file.Questa non è una soluzione per il problema, perché non mi permette di sostituire il centro e non collegare i file oggetto in eseguibili ancora:
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()
Gli sviluppatori della rete [mailing list GHC] (https://www.haskell.org/mailman/listinfo/ghc-devs) sono probabilmente quelli con le risposte che stai cercando. – gxtaillon
Credo che ci sia stato recentemente un lavoro su come consentire ai plugin di effettuare passaggi di trasformazione core-to-core all'interno della pipeline di GHC; non esattamente quello che vuoi però. Forse potresti spiegare brevemente perché vuoi fare questo preciso flusso di lavoro? –
@ChristianConkle Non voglio il plugin 'CORE -> CORE'. Sto creando il mio linguaggio personalizzato e voglio compilarlo al core e quindi utilizzare la pipeline di GHC. Scusa per non essere chiaro. –