gcatch, gbracket, gfinally,
clearWarnings, getWarnings, hasWarnings,
printExceptionAndWarnings, printWarnings,
- handleSourceError,
+ handleSourceError, defaultCallbacks, GhcApiCallbacks(..),
-- * Flags and settings
DynFlags(..), DynFlag(..), Severity(..), HscTarget(..), dopt,
dflags0 <- liftIO $ initDynFlags defaultDynFlags
dflags <- liftIO $ initSysTools mb_top_dir dflags0
- env <- liftIO $ newHscEnv dflags
+ env <- liftIO $ newHscEnv defaultCallbacks dflags
setSession env
clearWarnings
+defaultCallbacks :: GhcApiCallbacks
+defaultCallbacks =
+ GhcApiCallbacks {
+ reportModuleCompilationResult =
+ \_ mb_err -> defaultWarnErrLogger mb_err
+ }
+
-- -----------------------------------------------------------------------------
-- Flags & settings
-- the actual compilation starts (e.g., during dependency analysis).
--
load :: GhcMonad m => LoadHowMuch -> m SuccessFlag
-load how_much =
- loadWithLogger defaultWarnErrLogger how_much
+load how_much = do
+ mod_graph <- depanal [] False
+ load2 how_much mod_graph
-- | A function called to log warnings and errors.
type WarnErrLogger = GhcMonad m => Maybe SourceError -> m ()
-- even if we don't get a fully successful upsweep, the full module
-- graph is still retained in the Session. We can tell which modules
-- were successfully loaded by inspecting the Session's HPT.
- mod_graph <- depanal [] False
- load2 how_much mod_graph logger
+ withLocalCallbacks (\cbs -> cbs { reportModuleCompilationResult =
+ \_ -> logger }) $
+ load how_much
-load2 :: GhcMonad m => LoadHowMuch -> [ModSummary] -> WarnErrLogger
+load2 :: GhcMonad m => LoadHowMuch -> [ModSummary]
-> m SuccessFlag
-load2 how_much mod_graph logger = do
+load2 how_much mod_graph = do
guessOutputFile
hsc_env <- getSession
liftIO $ debugTraceMsg dflags 2 (hang (text "Ready for upsweep")
2 (ppr mg))
(upsweep_ok, hsc_env1, modsUpswept)
- <- upsweep logger
- (hsc_env { hsc_HPT = emptyHomePackageTable })
+ <- upsweep (hsc_env { hsc_HPT = emptyHomePackageTable })
pruned_hpt stable_mods cleanup mg
-- Make modsDone be the summaries for each home module now
upsweep
:: GhcMonad m =>
- WarnErrLogger -- ^ Called to print warnings and errors.
- -> HscEnv -- ^ Includes initially-empty HPT
+ HscEnv -- ^ Includes initially-empty HPT
-> HomePackageTable -- ^ HPT from last time round (pruned)
-> ([ModuleName],[ModuleName]) -- ^ stable modules (see checkStability)
-> IO () -- ^ How to clean up unwanted tmp files
HscEnv, -- With an updated HPT
[ModSummary]) -- Mods which succeeded
-upsweep logger hsc_env old_hpt stable_mods cleanup sccs = do
+upsweep hsc_env old_hpt stable_mods cleanup sccs = do
(res, hsc_env, done) <- upsweep' hsc_env old_hpt [] sccs 1 (length sccs)
return (res, hsc_env, reverse done)
where
= do -- putStrLn ("UPSWEEP_MOD: hpt = " ++
-- show (map (moduleUserString.moduleName.mi_module.hm_iface)
-- (moduleEnvElts (hsc_HPT hsc_env)))
+ let logger = reportModuleCompilationResult (hsc_callbacks hsc_env)
mb_mod_info
<- handleSourceError
- (\err -> do logger (Just err); return Nothing) $ do
+ (\err -> do logger mod (Just err); return Nothing) $ do
mod_info <- upsweep_mod hsc_env old_hpt stable_mods
mod mod_index nmods
- logger Nothing -- log warnings
+ logger mod Nothing -- log warnings
return (Just mod_info)
liftIO cleanup -- Remove unwanted tmp files between compilations
FinderCache, FindResult(..), ModLocationCache,
Target(..), TargetId(..), pprTarget, pprTargetId,
ModuleGraph, emptyMG,
+ -- ** Callbacks
+ GhcApiCallbacks(..), withLocalCallbacks,
-- * Information about modules
ModDetails(..), emptyModDetails,
\end{code}
\begin{code}
--- | HscEnv is like 'Session', except that some of the fields are immutable.
+-- | These functions are called in various places of the GHC API.
+--
+-- API clients can override any of these callbacks to change GHC's default
+-- behaviour.
+data GhcApiCallbacks
+ = GhcApiCallbacks {
+
+ -- | Called by 'load' after the compilating of each module.
+ --
+ -- The default implementation simply prints all warnings and errors to
+ -- @stderr@. Don't forget to call 'clearWarnings' when implementing your
+ -- own call.
+ --
+ -- The first argument is the module that was compiled.
+ --
+ -- The second argument is @Nothing@ if no errors occured, but there may
+ -- have been warnings. If it is @Just err@ at least one error has
+ -- occured. If 'srcErrorMessages' is empty, compilation failed due to
+ -- @-Werror@.
+ reportModuleCompilationResult :: GhcMonad m =>
+ ModSummary -> Maybe SourceError
+ -> m ()
+ }
+
+-- | Temporarily modify the callbacks. After the action is executed all
+-- callbacks are reset (not, however, any other modifications to the session
+-- state.)
+withLocalCallbacks :: GhcMonad m =>
+ (GhcApiCallbacks -> GhcApiCallbacks)
+ -> m a -> m a
+withLocalCallbacks f m = do
+ hsc_env <- getSession
+ let cb0 = hsc_callbacks hsc_env
+ let cb' = f cb0
+ setSession (hsc_env { hsc_callbacks = cb' `seq` cb' })
+ r <- m
+ setSession (hsc_env { hsc_callbacks = cb0 })
+ return r
+
+\end{code}
+
+\begin{code}
+-- | Hscenv is like 'Session', except that some of the fields are immutable.
-- An HscEnv is used to compile a single module from plain Haskell source
-- code (after preprocessing) to either C, assembly or C--. Things like
-- the module graph don't change during a single compilation.
hsc_dflags :: DynFlags,
-- ^ The dynamic flag settings
+ hsc_callbacks :: GhcApiCallbacks,
+ -- ^ Callbacks for the GHC API.
+
hsc_targets :: [Target],
-- ^ The targets (or roots) of the current session
import qualified GHC
import GHC ( DynFlags(..), HscTarget(..),
GhcMode(..), GhcLink(..),
- LoadHowMuch(..), dopt, DynFlag(..) )
+ LoadHowMuch(..), dopt, DynFlag(..),
+ defaultCallbacks )
import CmdLineParser
-- Implementations of the various modes (--show-iface, mkdependHS. etc.)
doShowIface :: DynFlags -> FilePath -> IO ()
doShowIface dflags file = do
- hsc_env <- newHscEnv dflags
+ hsc_env <- newHscEnv defaultCallbacks dflags
showIface hsc_env file
-- ---------------------------------------------------------------------------