GHC/As a library (up to 6.8)
From HaskellWiki
Using GHC as a library
Contents |
In GHC 6.5 and subsequently you can import GHC as a Haskell library, which lets you write a Haskell program that has access to all of GHC.
This page is a place for everyone to add
- Notes about how to get it working
- Comments about the API
- Suggestions for improvement
and so on.
1 Getting started
You'll need a version of GHC (at least 6.5) that supports the GHC API. The GHC download page offers stable releases and development versions; you can also use CVS (instructions) or darcs (e.g., darcs get --partial http://darcs.haskell.org/ghc).
To use the GHC API you say
import GHCDoing this imports the module GHC from the package ghc. This module exports the "GHC API", which is still in a state of flux. Currently it's not even Haddock-documented. You can see the source code (somewhat documented). There are also other modules of interest as you do more special things.
Here's an example main program that does it Media:Main.hs (good for GHC 6.6). You need to manually change the value of myGhcRoot to point to your GHC directory.
To compile Media:Main.hs, you have to turn on the flag "-package ghc", e.g.
ghc -package ghc Main.hs
2 Common use cases and functions
Assumes GHC 6.6.
2.1 Default exception handling
If you don't handle exceptions yourself, you are recommended to wrap all code inside the wrapper:
defaultErrorHandler :: DynFlags -> IO a -> IO a DynFlags.defaultDynFlags :: DynFlags
This catches exceptions and prints out exception details and exits your program with exit code 1.
Example:
import GHC import DynFlags(defaultDynFlags) main = defaultErrorHandler defaultDynFlags $ do {- stuff in the following subsections -}
2.2 Initialization
First create a session:
newSession :: GhcMode -- BatchCompile | Interactive | MkDepend | ... -> Maybe FilePath -- GHC installation directory -> IO Session -- your seesion; you will need it
The path to your GHC installation directory (e.g., /usr/local/lib/ghc-6.6) is in practice mandatory, even though in theory marked as optional.
The session is configurable by dynamic flags (GHC dynamic flags plus session state; think -O2, -fvia-C, -fglasgow-exts, -package). This can be done with:
getSessionDynFlags :: Session -> IO DynFlags setSessionDynFlags :: Session -> DynFlags -> IO [PackageId] -- important iff dynamic-linking parseDynamicFlags :: DynFlags -- old flags -> [String] -- e.g., all or part of getArgs -> IO (DynFlags, [String]) -- new flags, unknown args
data DynFlags = DynFlags { ..., hscTarget :: HscTarget } -- HscC | HscAsm | HscInterpreted | ...
Examples:
- vanilla compiler, use all defaults (rare but good start)
session <- newSession BatchCompile (Just "/usr/local/lib/ghc-6.6") getSessionDynFlags session >>= setSessionDynFlags session
- compiler with custom flags, easy with parser
session <- newSession BatchCompile (Just "/usr/local/lib/ghc-6.6") f0 <- getSessionDynFlags session (f1,b) <- parseDynamicFlags f0 ["-fglasgow-exts", "-O", "-package", "ghc", "-package Cabal", "foo", "-v", "bar"] -- b = ["foo", "bar"]; the other args are recognized -- in GHC 6.6 "-O" implies "-fvia-C", that kind of thing is automatic here too setSessionDynFlags session f1
- interactive session with interpreter
session <- newSession Interactive (Just "/usr/local/lib/ghc-6.6") f0 <- getSessionDynFlags session setSessionDynFlags session f0{hscTarget = HscInterpreted}
2.3 Load or compile modules
To compile code or load modules, first set one or more targets, then call theguessTarget :: String -- "filename.hs" or "filename.lhs" or "MyModule" -> Maybe Phase -- if not Nothing, specifies starting phase -> IO Target addTarget :: Session -> Target -> IO () setTargets :: Session -> [Target] -> IO () getTargets :: Session -> IO [Target] removeTarget :: Session -> TargetId -> IO () load :: Session -> LoadHowMuch -> IO SuccessFlag data LoadHowMuch = LoadAllTargets | LoadUpTo ModuleName | LoadDependenciesOf ModuleName
defaultCleanupHandler :: DynFlags -> IO a -> IO a
Example:
t <- guessTarget "Main.hs" Nothing addTarget session t -- setTargets session [t] is also good f <- getSessionDynFlags session sf <- defaultCleanupHandler f (load session LoadAllTargets) case sf of Succeeded -> ... Failed -> ...
Dependencies are processed automatically (and silently).
Modules are compiled as per the2.4 Interactive evaluation
Interactive evaluation ala GHCi is done bysetContext :: Session -> [Module] -- their top levels will be visible -> [Module] -- their exports will be visible -> IO () getContext :: Session -> IO ([Module], [Module]) findModule :: Session -> ModuleName -> Maybe PackageId -> IO Module mkModule :: PackageId -> ModuleName -> Module mkModuleName :: String -> ModuleName PackageConfig.stringToPackageId :: String -> PackageId
-- equivalent to GHCi's :m Prelude Control.Monad *Main prelude <- findModule session (mkModuleName "Prelude") Nothing monad <- findModule session (mkModuleName "Control.Monad") Nothing usermod <- findModule session (mkModuleName "Main") Nothing -- we have loaded this setContext session [usermod] [prelude,monad]
Having set a useful context, we're now ready to evaluate.
runStmt :: Session -> String -> IO RunResult data RunResult = RunOk [Name] -- names bound by the expression | RunFailed | RunException GHC.IOBase.Exception -- that's Control.Exception.Exception
Example:
runStmt session "let n = 2 + 2" -- n is bound runStmt session "n" -- 4 is printed (note "it" is bound)
(Interactive evaluation works in BatchCompile mode too! There are still other subtle differences, so this is not recommended.)
2.5 Queries
-- Get module dependency graph getModuleGraph :: Session -> IO ModuleGraph -- ModuleGraph = [ModSummary] -- Get bindings getBindings :: Session -> IO [TyThing]
2.6 Messages
Compiler messages (including progress, warnings, errors) are controlled by verbosity and routed through a callback mechanism. These are fields indata DynFlags = DynFlags { ..., verbosity :: Int, log_action :: Severity -> SrcLoc.SrcSpan -> Outputable.PprStyle -> ErrUtils.Message -> IO () }
You can set the callback to your logger, like
f <- getSessionDynFlags session setSessionDynFlags session f{log_action = my_log_action}
This sets the session's logger, but it will not see exceptions.
If you callmain = defaultErrorHandler defaultDynFlags{log_action = my_log_action} $ do ...
3 Interactive mode example
The file Media:Interactive.hs (also requires Media:MyPrelude.hs) serves as an example for using GHC as a library in interactive mode. It also shows how to replace some of the standard prelude functions with modified versions. See the comments in the code for further information.
4 Using the GHC library from inside GHCi
This works, to some extent. However, beware about loading object code, because there is only a single linker symbol table in the runtime, so GHCi will be sharing the symbol table with the new GHC session.
$ ghci -package ghc Prelude> :m + GHC PackageConfig Prelude GHC> session <- newSession Interactive (Just "/usr/local/lib/ghc-6.6") Prelude GHC> setSessionDynFlags session =<< getSessionDynFlags session Prelude GHC> setContext session [] [mkModule (stringToPackageId "base") (mkModuleName "Prelude")] Prelude GHC> runStmt session "let add1 x = x + 1" Prelude GHC> runStmt session "add1 2" 3
