summaryrefslogtreecommitdiff
path: root/compiler/main/DriverPipeline.hs
diff options
context:
space:
mode:
authorAustin Seipp <austin@well-typed.com>2013-09-22 18:47:35 -0500
committerAustin Seipp <austin@well-typed.com>2013-09-22 18:47:38 -0500
commit6f799899aa7cd9c59c9ebf9c9709f9423d93d307 (patch)
treebed11393db25e594d9525471a01c69dd98a9b355 /compiler/main/DriverPipeline.hs
parentea2af9b21d6e772e3adc8806044557b504b84795 (diff)
downloadhaskell-6f799899aa7cd9c59c9ebf9c9709f9423d93d307.tar.gz
Restructure compilation pipeline to allow hooks
This commit exposes GHC's internal compiler pipeline through a `Hooks` module in the GHC API. It currently allows you to hook: * Foreign import/exports declarations * The frontend up to type checking * The one shot compilation mode * Core compilation, and the module iface * Linking and the phases in DriverPhases.hs * Quasiquotation Authored-by: Luite Stegeman <stegeman@gmail.com> Authored-by: Edsko de Vries <edsko@well-typed.com> Signed-off-by: Austin Seipp <austin@well-typed.com>
Diffstat (limited to 'compiler/main/DriverPipeline.hs')
-rw-r--r--compiler/main/DriverPipeline.hs154
1 files changed, 41 insertions, 113 deletions
diff --git a/compiler/main/DriverPipeline.hs b/compiler/main/DriverPipeline.hs
index 048896c009..035d5778d6 100644
--- a/compiler/main/DriverPipeline.hs
+++ b/compiler/main/DriverPipeline.hs
@@ -23,17 +23,26 @@ module DriverPipeline (
compileOne, compileOne',
link,
+ -- Exports for hooks to override runPhase and link
+ PhasePlus(..), CompPipeline(..), PipeEnv(..), PipeState(..),
+ phaseOutputFilename, getPipeState, getPipeEnv,
+ hscPostBackendPhase, getLocation, setModLocation, setDynFlags,
+ runPhase, exeFileName,
+ mkExtraObjToLinkIntoBinary, mkNoteObjsToLinkIntoBinary,
+ maybeCreateManifest, runPhase_MoveBinary,
+ linkingNeeded, checkLinkInfo
) where
#include "HsVersions.h"
+import PipelineMonad
import Packages
import HeaderInfo
import DriverPhases
import SysTools
import HscMain
import Finder
-import HscTypes
+import HscTypes hiding ( Hsc )
import Outputable
import Module
import UniqFM ( eltsUFM )
@@ -52,6 +61,7 @@ import LlvmCodeGen ( llvmFixupAsm )
import MonadUtils
import Platform
import TcRnTypes
+import Hooks
import Exception
import Data.IORef ( readIORef )
@@ -283,23 +293,26 @@ link :: GhcLink -- interactive or batch
-- exports main, i.e., we have good reason to believe that linking
-- will succeed.
-link LinkInMemory _ _ _
- = if cGhcWithInterpreter == "YES"
- then -- Not Linking...(demand linker will do the job)
- return Succeeded
- else panicBadLink LinkInMemory
+link ghcLink dflags
+ = lookupHook linkHook l dflags ghcLink dflags
+ where
+ l LinkInMemory _ _ _
+ = if cGhcWithInterpreter == "YES"
+ then -- Not Linking...(demand linker will do the job)
+ return Succeeded
+ else panicBadLink LinkInMemory
-link NoLink _ _ _
- = return Succeeded
+ l NoLink _ _ _
+ = return Succeeded
-link LinkBinary dflags batch_attempt_linking hpt
- = link' dflags batch_attempt_linking hpt
+ l LinkBinary dflags batch_attempt_linking hpt
+ = link' dflags batch_attempt_linking hpt
-link LinkStaticLib dflags batch_attempt_linking hpt
- = link' dflags batch_attempt_linking hpt
+ l LinkStaticLib dflags batch_attempt_linking hpt
+ = link' dflags batch_attempt_linking hpt
-link LinkDynLib dflags batch_attempt_linking hpt
- = link' dflags batch_attempt_linking hpt
+ l LinkDynLib dflags batch_attempt_linking hpt
+ = link' dflags batch_attempt_linking hpt
panicBadLink :: GhcLink -> a
panicBadLink other = panic ("link: GHC not built to link this way: " ++
@@ -499,20 +512,6 @@ doLink dflags stop_phase o_files
-- ---------------------------------------------------------------------------
-data PipelineOutput
- = Temporary
- -- ^ Output should be to a temporary file: we're going to
- -- run more compilation steps on this output later.
- | Persistent
- -- ^ We want a persistent file, i.e. a file in the current directory
- -- derived from the input filename, but with the appropriate extension.
- -- eg. in "ghc -c Foo.hs" the output goes into ./Foo.o.
- | SpecificFile
- -- ^ The output must go into the specific outputFile in DynFlags.
- -- We don't store the filename in the constructor as it changes
- -- when doing -dynamic-too.
- deriving Show
-
-- | Run a compilation pipeline, consisting of multiple phases.
--
-- This is the interface to the compilation pipeline, which runs
@@ -615,83 +614,6 @@ runPipeline' start_phase hsc_env env input_fn
evalP (pipeLoop start_phase input_fn) env state
--- -----------------------------------------------------------------------------
--- The pipeline uses a monad to carry around various bits of information
-
--- PipeEnv: invariant information passed down
-data PipeEnv = PipeEnv {
- pe_isHaskellishFile :: Bool,
- stop_phase :: Phase, -- ^ Stop just before this phase
- src_filename :: String, -- ^ basename of original input source
- src_basename :: String, -- ^ basename of original input source
- src_suffix :: String, -- ^ its extension
- output_spec :: PipelineOutput -- ^ says where to put the pipeline output
- }
-
--- PipeState: information that might change during a pipeline run
-data PipeState = PipeState {
- hsc_env :: HscEnv,
- -- ^ only the DynFlags change in the HscEnv. The DynFlags change
- -- at various points, for example when we read the OPTIONS_GHC
- -- pragmas in the Cpp phase.
- maybe_loc :: Maybe ModLocation,
- -- ^ the ModLocation. This is discovered during compilation,
- -- in the Hsc phase where we read the module header.
- maybe_stub_o :: Maybe FilePath
- -- ^ the stub object. This is set by the Hsc phase if a stub
- -- object was created. The stub object will be joined with
- -- the main compilation object using "ld -r" at the end.
- }
-
-getPipeEnv :: CompPipeline PipeEnv
-getPipeEnv = P $ \env state -> return (state, env)
-
-getPipeState :: CompPipeline PipeState
-getPipeState = P $ \_env state -> return (state, state)
-
-instance HasDynFlags CompPipeline where
- getDynFlags = P $ \_env state -> return (state, hsc_dflags (hsc_env state))
-
-setDynFlags :: DynFlags -> CompPipeline ()
-setDynFlags dflags = P $ \_env state ->
- return (state{hsc_env= (hsc_env state){ hsc_dflags = dflags }}, ())
-
-setModLocation :: ModLocation -> CompPipeline ()
-setModLocation loc = P $ \_env state ->
- return (state{ maybe_loc = Just loc }, ())
-
-setStubO :: FilePath -> CompPipeline ()
-setStubO stub_o = P $ \_env state ->
- return (state{ maybe_stub_o = Just stub_o }, ())
-
-newtype CompPipeline a = P { unP :: PipeEnv -> PipeState -> IO (PipeState, a) }
-
-evalP :: CompPipeline a -> PipeEnv -> PipeState -> IO a
-evalP f env st = liftM snd $ unP f env st
-
-instance Functor CompPipeline where
- fmap = liftM
-
-instance Applicative CompPipeline where
- pure = return
- (<*>) = ap
-
-instance Monad CompPipeline where
- return a = P $ \_env state -> return (state, a)
- P m >>= k = P $ \env state -> do (state',a) <- m env state
- unP (k a) env state'
-
-instance MonadIO CompPipeline where
- liftIO m = P $ \_env state -> do a <- m; return (state, a)
-
-phaseOutputFilename :: Phase{-next phase-} -> CompPipeline FilePath
-phaseOutputFilename next_phase = do
- PipeEnv{stop_phase, src_basename, output_spec} <- getPipeEnv
- PipeState{maybe_loc, hsc_env} <- getPipeState
- let dflags = hsc_dflags hsc_env
- liftIO $ getOutputFilename stop_phase output_spec
- src_basename dflags next_phase maybe_loc
-
-- ---------------------------------------------------------------------------
-- outer pipeline loop
@@ -735,7 +657,7 @@ pipeLoop phase input_fn = do
_
-> do liftIO $ debugTraceMsg dflags 4
(ptext (sLit "Running phase") <+> ppr phase)
- (next_phase, output_fn) <- runPhase phase input_fn dflags
+ (next_phase, output_fn) <- runHookedPhase phase input_fn dflags
r <- pipeLoop next_phase output_fn
case phase of
HscOut {} ->
@@ -748,11 +670,24 @@ pipeLoop phase input_fn = do
return ()
return r
+runHookedPhase :: PhasePlus -> FilePath -> DynFlags
+ -> CompPipeline (PhasePlus, FilePath)
+runHookedPhase pp input dflags =
+ lookupHook runPhaseHook runPhase dflags pp input dflags
+
-- -----------------------------------------------------------------------------
-- In each phase, we need to know into what filename to generate the
-- output. All the logic about which filenames we generate output
-- into is embodied in the following function.
+phaseOutputFilename :: Phase{-next phase-} -> CompPipeline FilePath
+phaseOutputFilename next_phase = do
+ PipeEnv{stop_phase, src_basename, output_spec} <- getPipeEnv
+ PipeState{maybe_loc, hsc_env} <- getPipeState
+ let dflags = hsc_dflags hsc_env
+ liftIO $ getOutputFilename stop_phase output_spec
+ src_basename dflags next_phase maybe_loc
+
getOutputFilename
:: Phase -> PipelineOutput -> String
-> DynFlags -> Phase{-next phase-} -> Maybe ModLocation -> IO FilePath
@@ -801,13 +736,6 @@ getOutputFilename stop_phase output basename dflags next_phase maybe_location
| Just d <- odir = d </> persistent
| otherwise = persistent
-data PhasePlus = RealPhase Phase
- | HscOut HscSource ModuleName HscStatus
-
-instance Outputable PhasePlus where
- ppr (RealPhase p) = ppr p
- ppr (HscOut {}) = text "HscOut"
-
-- -----------------------------------------------------------------------------
-- | Each phase in the pipeline returns the next phase to execute, and the
-- name of the file in which the output was placed.