module Language.Haskell.GHC.Simple (
compile, compileWith, compileFold,
module Simple.Types,
getDynFlagsForConfig,
module CoreSyn, module StgSyn, module Module,
module Id, module IdInfo, module Var, module Literal, module DataCon,
module OccName, module Name,
module Type, module TysPrim, module TyCon,
module ForeignCall, module PrimOp,
module DynFlags, module SrcLoc,
module DriverPhases,
ModSummary (..), ModGuts (..),
PkgKey,
pkgKeyString, modulePkgKey
) where
import GHC hiding (Warning)
import GhcMonad (liftIO)
import DynFlags
import HscTypes
import ErrUtils
import Bag
import SrcLoc
import Outputable
import Hooks
import StaticFlags (discardStaticFlags)
import DriverPhases
import DriverPipeline
import StgSyn
import CoreSyn
import Name hiding (varName)
import Type
import TysPrim
import TyCon
import Literal
import Var hiding (setIdExported, setIdNotExported, lazySetIdInfo)
import Id
import IdInfo
import OccName hiding (varName)
import DataCon
import ForeignCall
import PrimOp
import Module
import Data.Binary
import qualified Data.ByteString.Lazy as BS
import Data.IORef
import Data.List (sort, sortBy)
import Control.Monad
import GHC.Paths (libdir)
import System.Directory
import System.FilePath
import System.IO
import System.IO.Unsafe
import Language.Haskell.GHC.Simple.PrimIface as Simple.PrimIface
import Language.Haskell.GHC.Simple.Types as Simple.Types
import Language.Haskell.GHC.Simple.Impl
compile :: (Intermediate a, Binary b)
=> (ModMetadata -> a -> IO b)
-> [String]
-> IO (CompResult [CompiledModule b])
compile = compileWith defaultConfig
compileWith :: (Intermediate a, Binary b)
=> CompConfig
-> (ModMetadata -> a -> IO b)
-> [String]
-> IO (CompResult [CompiledModule b])
compileWith cfg comp = compileFold cfg comp consMod []
consMod :: [CompiledModule a] -> CompiledModule a -> IO [CompiledModule a]
consMod xs x = return (x:xs)
getDynFlagsForConfig :: CompConfig -> IO (DynFlags, [String])
getDynFlagsForConfig cfg = initStaticFlags `seq` do
ws <- newIORef []
runGhc (maybe (Just libdir) Just (cfgGhcLibDir cfg)) $ do
setDFS cfg (discardStaticFlags (cfgGhcFlags cfg)) ws noComp
noComp :: FilePath -> ModSummary -> CgGuts -> CompPipeline ()
noComp _ _ _ = return ()
setDFS :: CompConfig
-> [String]
-> IORef [Warning]
-> (FilePath -> ModSummary -> CgGuts -> CompPipeline ())
-> Ghc (DynFlags, [String])
setDFS cfg flags warns comp = do
dfs <- getSessionDynFlags
(dfs', files2, _dynwarns) <- parseDynamicFlags dfs (map noLoc flags)
let ps = cfgStopPhases cfg
dfs'' = cfgUpdateDynFlags cfg $ dfs' {
log_action = logger (log_action dfs') warns,
hooks = (hooks dfs') {runPhaseHook = Just $ phaseHook ps}
}
case cfgCustomPrimIface cfg of
Just (nfo, strs) -> setPrimIface dfs'' nfo strs
_ -> void $ setSessionDynFlags dfs''
finaldfs <- getSessionDynFlags
return (finaldfs, map unLoc files2)
where
logger deflog warns dfs severity srcspan style msg
| cfgUseGhcErrorLogger cfg = do
logger' deflog warns dfs severity srcspan style msg
case severity of
SevWarning -> deflog dfs severity srcspan style msg
SevError -> deflog dfs severity srcspan style msg
_ -> return ()
| otherwise = do
logger' deflog warns dfs severity srcspan style msg
logger' _ w dfs SevWarning srcspan _style msg = do
liftIO $ atomicModifyIORef' w $ \ws ->
(Warning srcspan (showSDoc dfs msg) : ws, ())
logger' _ _ _ SevError _ _ _ = do
return ()
logger' output _ dfs sev srcspan style msg = do
output dfs sev srcspan style msg
setPrimIface dfs nfo strs = do
void $ setSessionDynFlags dfs {
hooks = (hooks dfs) {ghcPrimIfaceHook = Just $ primIface nfo strs}
}
getSession >>= liftIO . fixPrimopTypes nfo strs
phaseHook _ p@(HscOut src_flavour mod_name result) inp dfs = do
loc <- getLocation src_flavour mod_name
setModLocation loc
let next = hscPostBackendPhase dfs src_flavour (hscTarget dfs)
case result of
HscRecomp cgguts ms -> do
outfile <- phaseOutputFilename next
comp (ml_hi_file loc) ms cgguts
runPhase p inp dfs
_ ->
runPhase p inp dfs
phaseHook stop (RealPhase p) inp _ | p `elem` stop =
return (RealPhase StopLn, inp)
phaseHook _ p inp dfs =
runPhase p inp dfs
writeModCache :: Binary a => CompConfig -> CompiledModule a -> IO ()
writeModCache cfg (CompiledModule m meta) = do
createDirectoryIfMissing True (takeDirectory cachefile)
BS.writeFile cachefile (encode m)
where
ext = cfgCacheFileExt cfg
modfile = moduleNameSlashes (ms_mod_name (mmSummary meta)) <.> ext
cachefile = maybe "" id (cfgCacheDirectory cfg) </> modfile
readModCache :: Binary a => CompConfig -> ModMetadata -> IO (CompiledModule a)
readModCache cfg meta = do
m <- decode `fmap` BS.readFile cachefile
return $ CompiledModule m meta
where
ext = cfgCacheFileExt cfg
modfile = moduleNameSlashes (ms_mod_name (mmSummary meta)) <.> ext
cachefile = maybe "" id (cfgCacheDirectory cfg) </> modfile
compileFold :: (Intermediate a, Binary b)
=> CompConfig
-> (ModMetadata -> a -> IO b)
-> (acc -> CompiledModule b -> IO acc)
-> acc
-> [String]
-> IO (CompResult acc)
compileFold cfg comp f acc files = initStaticFlags `seq` do
warns <- newIORef []
accref <- newIORef acc
tgtref <- newIORef []
recomp <- newIORef []
runGhc (maybe (Just libdir) Just (cfgGhcLibDir cfg)) $ do
(_, files2) <- setDFS cfg dfs warns (comp' accref recomp tgtref)
ecode <- genCode cfg f accref tgtref recomp (files ++ files2)
ws <- liftIO $ readIORef warns
case ecode of
Right (finaldfs, code) ->
return Success {
compResult = code,
compWarnings = ws,
compDynFlags = finaldfs
}
Left es ->
return Failure {
compErrors = es,
compWarnings = ws
}
where
dfs = discardStaticFlags (cfgGhcFlags cfg)
comp' accref recompref tgtref hifile ms cgguts = do
source <- prepare ms cgguts
liftIO $ do
tgts <- readIORef tgtref
let meta = toModMetadata cfg False tgts ms
code <- comp meta source
let cm = CompiledModule code meta
writeModCache cfg cm
atomicModifyIORef' recompref $ \xs -> (ms_mod ms : xs, ())
readIORef accref >>= flip f cm >>= writeIORef accref
initStaticFlags :: [Located String]
initStaticFlags = unsafePerformIO $ fmap fst (parseStaticFlags [])
genCode :: (GhcMonad m, Binary b)
=> CompConfig
-> (a -> CompiledModule b -> IO a)
-> IORef a
-> IORef [Target]
-> IORef [Module]
-> [String]
-> m (Either [Error] (DynFlags, a))
genCode cfg f accref tgtref recompref files = do
dfs <- getSessionDynFlags
merrs <- handleSourceError (maybeErrors dfs) $ do
ts <- mapM (flip guessTarget Nothing) files
liftIO $ writeIORef tgtref ts
setTargets ts
loads <- load LoadAllTargets
mss <- depanal [] False
acc <- liftIO $ readIORef accref
recompiled <- liftIO $ readIORef recompref
let cachedmods = sortBy onModId mss \\ sort recompiled
acc' <- liftIO $ foldM (loadCachedMod ts) acc cachedmods
liftIO $ writeIORef accref acc'
return $ if succeeded loads then Nothing else Just []
case merrs of
Just errs -> return $ Left errs
_ -> do
code <- liftIO $ readIORef accref
return $ Right (dfs, code)
where
onModId m n = ms_mod m `compare` ms_mod n
loadCachedMod tgts acc ms =
readModCache cfg (toModMetadata cfg True tgts ms) >>= f acc
(\\) :: [ModSummary] -> [Module] -> [ModSummary]
msmss@(ms:mss) \\ mmods@(m:mods)
| ms_mod ms == m = mss \\ mmods
| ms_mod ms < m = msmss \\ mods
| otherwise = ms : (mss \\ mmods)
mss \\ [] = mss
[] \\ _ = []
maybeErrors dfs
| cfgUseGhcErrorLogger cfg = \srcerr -> liftIO $ do
let msgs = srcErrorMessages srcerr
printBagOfErrors dfs msgs
return . Just . map (fromErrMsg dfs) $ bagToList msgs
| otherwise =
return . Just . map (fromErrMsg dfs) . bagToList . srcErrorMessages
fromErrMsg :: DynFlags -> ErrMsg -> Error
fromErrMsg dfs e = Error {
errorSpan = errMsgSpan e,
errorMessage = showSDocForUser dfs ctx (errMsgShortDoc e),
errorExtraInfo = showSDocForUser dfs ctx (errMsgExtraInfo e)
}
where
ctx = errMsgContext e