summaryrefslogtreecommitdiff
path: root/compiler/GHC/Driver/Pipeline.hs
diff options
context:
space:
mode:
authorDivam <dfordivam@gmail.com>2021-04-19 13:49:30 +0900
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-05-25 05:50:51 -0400
commitf243acf4d7322a15e9eb6e432c490a4d6db741df (patch)
treef01d9ab4799043931488fa3c97a0ce75a3e4c7c1 /compiler/GHC/Driver/Pipeline.hs
parenta3665a7aa5db8a77809b8e2246b8cd7eee86935c (diff)
downloadhaskell-f243acf4d7322a15e9eb6e432c490a4d6db741df.tar.gz
Refactor driver code; de-duplicate and split APIs (#14095, !5555)
This commit does some de-duplication of logic between the one-shot and --make modes, and splitting of some of the APIs so that its easier to do the fine-grained parallelism implementation. This is the first part of the implementation plan as described in #14095 * compileOne now uses the runPhase pipeline for most of the work. The Interpreter backend handling has been moved to the runPhase. * hscIncrementalCompile has been broken down into multiple APIs. * haddock submodule bump: Rename of variables in html-test ref: This is caused by a change in ModDetails in case of NoBackend. Now the initModDetails is used to recreate the ModDetails from interface and in-memory ModDetails is not used.
Diffstat (limited to 'compiler/GHC/Driver/Pipeline.hs')
-rw-r--r--compiler/GHC/Driver/Pipeline.hs431
1 files changed, 234 insertions, 197 deletions
diff --git a/compiler/GHC/Driver/Pipeline.hs b/compiler/GHC/Driver/Pipeline.hs
index c4de774033..f8ad427dc2 100644
--- a/compiler/GHC/Driver/Pipeline.hs
+++ b/compiler/GHC/Driver/Pipeline.hs
@@ -71,6 +71,7 @@ import GHC.Linker.Types
import GHC.Utils.Outputable
import GHC.Utils.Error
+import GHC.Utils.Fingerprint
import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
import GHC.Utils.Misc
@@ -87,9 +88,11 @@ import GHC.Data.StringBuffer ( hGetStringBuffer, hPutStringBuffer )
import GHC.Data.Maybe ( expectJust )
import GHC.Iface.Make ( mkFullIface )
+import GHC.Runtime.Loader ( initializePlugins )
import GHC.Types.Basic ( SuccessFlag(..) )
import GHC.Types.Error ( singleMessage, getMessages )
+import GHC.Types.Name.Env
import GHC.Types.Target
import GHC.Types.SrcLoc
import GHC.Types.SourceFile
@@ -110,6 +113,7 @@ import System.FilePath
import System.IO
import Control.Monad
import qualified Control.Monad.Catch as MC (handle)
+import Data.IORef
import Data.List ( isInfixOf, intercalate )
import Data.Maybe
import Data.Version
@@ -137,7 +141,7 @@ preprocess hsc_env input_fn mb_input_buf mb_phase =
MC.handle handler $
fmap Right $ do
massertPpr (isJust mb_phase || isHaskellSrcFilename input_fn) (text input_fn)
- (dflags, fp, mb_iface) <- runPipeline anyHsc hsc_env (input_fn, mb_input_buf, fmap RealPhase mb_phase)
+ (dflags, fp, mb_iface, mb_linkable) <- runPipeline anyHsc hsc_env (input_fn, mb_input_buf, fmap RealPhase mb_phase)
Nothing
-- We keep the processed file for the whole session to save on
-- duplicated work in ghci.
@@ -146,6 +150,7 @@ preprocess hsc_env input_fn mb_input_buf mb_phase =
[]{-no foreign objects-}
-- We stop before Hsc phase so we shouldn't generate an interface
massert (isNothing mb_iface)
+ massert (isNothing mb_linkable)
return (dflags, fp)
where
srcspan = srcLocSpan $ mkSrcLoc (mkFastString input_fn) 1 1
@@ -205,18 +210,8 @@ compileOne' m_tc_result mHscMessage
source_modified0
= do
- let logger = hsc_logger hsc_env0
- let tmpfs = hsc_tmpfs hsc_env0
debugTraceMsg logger dflags1 2 (text "compile: input file" <+> text input_fnpp)
- -- Run the pipeline up to codeGen (so everything up to, but not including, STG)
- (status, plugin_hsc_env) <- hscIncrementalCompile
- always_do_basic_recompilation_check
- m_tc_result mHscMessage
- hsc_env summary source_modified mb_old_iface (mod_index, nmods)
- -- Use an HscEnv updated with the plugin info
- let hsc_env' = plugin_hsc_env
-
let flags = hsc_dflags hsc_env0
in do unless (gopt Opt_KeepHiFiles flags) $
addFilesToClean tmpfs TFL_CurrentModule $
@@ -225,101 +220,29 @@ compileOne' m_tc_result mHscMessage
addFilesToClean tmpfs TFL_GhcSession $
[ml_obj_file $ ms_location summary]
- case (status, bcknd) of
- (HscUpToDate iface hmi_details, _) ->
- -- TODO recomp014 triggers this assert. What's going on?!
- -- assert (isJust mb_old_linkable || isNoLink (ghcLink dflags) )
- return $! HomeModInfo iface hmi_details mb_old_linkable
- (HscNotGeneratingCode iface hmi_details, NoBackend) ->
- let mb_linkable = if isHsBootOrSig src_flavour
- then Nothing
- -- TODO: Questionable.
- else Just (LM (ms_hs_date summary) this_mod [])
- in return $! HomeModInfo iface hmi_details mb_linkable
- (HscNotGeneratingCode _ _, _) -> panic "compileOne HscNotGeneratingCode"
- (_, NoBackend) -> panic "compileOne NoBackend"
- (HscUpdateBoot iface hmi_details, Interpreter) ->
- return $! HomeModInfo iface hmi_details Nothing
- (HscUpdateBoot iface hmi_details, _) -> do
- touchObjectFile logger dflags object_filename
- return $! HomeModInfo iface hmi_details Nothing
- (HscUpdateSig iface hmi_details, Interpreter) -> do
- let !linkable = LM (ms_hs_date summary) this_mod []
- return $! HomeModInfo iface hmi_details (Just linkable)
- (HscUpdateSig iface hmi_details, _) -> do
- output_fn <- getOutputFilename logger tmpfs next_phase
- (Temporary TFL_CurrentModule) basename dflags
- next_phase (Just location)
-
- -- #10660: Use the pipeline instead of calling
- -- compileEmptyStub directly, so -dynamic-too gets
- -- handled properly
- _ <- runPipeline StopLn hsc_env'
- (output_fn,
- Nothing,
- Just (HscOut src_flavour
- mod_name (HscUpdateSig iface hmi_details)))
- (Just basename)
- Persistent
- (Just location)
- []
- o_time <- getModificationUTCTime object_filename
- let !linkable = LM o_time this_mod [DotO object_filename]
- return $! HomeModInfo iface hmi_details (Just linkable)
- (HscRecomp { hscs_guts = cgguts,
- hscs_mod_location = mod_location,
- hscs_partial_iface = partial_iface,
- hscs_old_iface_hash = mb_old_iface_hash
- }, Interpreter) -> do
- -- In interpreted mode the regular codeGen backend is not run so we
- -- generate a interface without codeGen info.
- final_iface <- mkFullIface hsc_env' partial_iface Nothing
- -- Reconstruct the `ModDetails` from the just-constructed `ModIface`
- -- See Note [ModDetails and --make mode]
- hmi_details <- liftIO $ initModDetails hsc_env' summary final_iface
- liftIO $ hscMaybeWriteIface logger dflags True final_iface mb_old_iface_hash (ms_location summary)
-
- (hasStub, comp_bc, spt_entries) <- hscInteractive hsc_env' cgguts mod_location
-
- stub_o <- case hasStub of
- Nothing -> return []
- Just stub_c -> do
- stub_o <- compileStub hsc_env' stub_c
- return [DotO stub_o]
-
- let hs_unlinked = [BCOs comp_bc spt_entries]
- unlinked_time = ms_hs_date summary
- -- Why do we use the timestamp of the source file here,
- -- rather than the current time? This works better in
- -- the case where the local clock is out of sync
- -- with the filesystem's clock. It's just as accurate:
- -- if the source is modified, then the linkable will
- -- be out of date.
- let !linkable = LM unlinked_time (ms_mod summary)
- (hs_unlinked ++ stub_o)
- return $! HomeModInfo final_iface hmi_details (Just linkable)
- (HscRecomp{}, _) -> do
- output_fn <- getOutputFilename logger tmpfs next_phase
- (Temporary TFL_CurrentModule)
- basename dflags next_phase (Just location)
- -- We're in --make mode: finish the compilation pipeline.
- (_, _, Just iface) <- runPipeline StopLn hsc_env'
- (output_fn,
- Nothing,
- Just (HscOut src_flavour mod_name status))
- (Just basename)
- Persistent
- (Just location)
- []
- -- The object filename comes from the ModLocation
- o_time <- getModificationUTCTime object_filename
- let !linkable = LM o_time this_mod [DotO object_filename]
- -- See Note [ModDetails and --make mode]
- details <- initModDetails hsc_env' summary iface
- return $! HomeModInfo iface details (Just linkable)
+ plugin_hsc_env <- initializePlugins hsc_env
+
+ let runPostTc = compileOnePostTc plugin_hsc_env summary
+
+ case m_tc_result of
+ Just tc_result
+ | not always_do_basic_recompilation_check -> do
+ runPostTc (FrontendTypecheck tc_result) emptyMessages Nothing
+ _ -> do
+ status <- hscRecompStatus mHscMessage plugin_hsc_env summary
+ source_modified mb_old_iface (mod_index, nmods)
+
+ case status of
+ HscUpToDate iface -> do
+ massert ( isJust mb_old_linkable || isNoLink (ghcLink dflags) )
+ -- See Note [ModDetails and --make mode]
+ details <- initModDetails plugin_hsc_env summary iface
+ return $! HomeModInfo iface details mb_old_linkable
+ HscRecompNeeded mb_old_hash -> do
+ (tc_result, warnings) <- hscTypecheckAndGetWarnings plugin_hsc_env summary
+ runPostTc tc_result warnings mb_old_hash
where dflags0 = ms_hspp_opts summary
- this_mod = ms_mod summary
location = ms_location summary
input_fn = expectJust "compile:hs" (ml_hs_file location)
input_fnpp = ms_hspp_file summary
@@ -329,10 +252,8 @@ compileOne' m_tc_result mHscMessage
isProfWay = any (== WayProf) (ways dflags0)
internalInterpreter = not (gopt Opt_ExternalInterpreter dflags0)
- src_flavour = ms_hsc_src summary
- mod_name = ms_mod_name summary
- next_phase = hscPostBackendPhase src_flavour bcknd
- object_filename = ml_obj_file location
+ logger = hsc_logger hsc_env0
+ tmpfs = hsc_tmpfs hsc_env0
-- #8180 - when using TemplateHaskell, switch on -dynamic-too so
-- the linker can correctly load the object files. This isn't necessary
@@ -387,6 +308,59 @@ compileOne' m_tc_result mHscMessage
Interpreter -> True
_ -> False
+-- | Do the post typechecking compilation of a module in the --make mode
+compileOnePostTc
+ :: HscEnv
+ -> ModSummary
+ -> FrontendResult
+ -> WarningMessages
+ -> Maybe Fingerprint
+ -> IO HomeModInfo
+compileOnePostTc hsc_env summary tc_result warnings mb_old_hash = do
+ output_fn <- getOutputFilename logger tmpfs next_phase
+ (Temporary TFL_CurrentModule)
+ basename dflags next_phase (Just location)
+ (_, _, Just iface, mb_linkable) <- runPipeline StopLn hsc_env
+ (output_fn,
+ Nothing,
+ Just (HscPostTc summary tc_result warnings mb_old_hash))
+ (Just basename)
+ pipelineOutput
+ (Just location)
+ []
+ -- TODO: figure out a way to set this in runPipeline for HsSrcFile
+ mLinkable <- case () of
+ _ | Just l <- mb_linkable -> return $ Just l
+ | bcknd == NoBackend -> return Nothing
+ | src_flavour == HsSrcFile -> do
+ -- The object filename comes from the ModLocation
+ o_time <- getModificationUTCTime object_filename
+ let !linkable = LM o_time this_mod [DotO object_filename]
+ return $ Just linkable
+ | otherwise -> return Nothing
+ -- See Note [ModDetails and --make mode]
+ details <- initModDetails hsc_env summary iface
+ return $! HomeModInfo iface details mLinkable
+
+ where dflags = hsc_dflags hsc_env
+ this_mod = ms_mod summary
+ location = ms_location summary
+ input_fn = expectJust "compile:hs" (ml_hs_file location)
+
+ logger = hsc_logger hsc_env
+ tmpfs = hsc_tmpfs hsc_env
+ src_flavour = ms_hsc_src summary
+ next_phase = hscPostBackendPhase src_flavour bcknd
+ bcknd = backend dflags
+ object_filename = ml_obj_file location
+
+ basename = dropExtension input_fn
+
+ pipelineOutput = case bcknd of
+ Interpreter -> NoOutputFile
+ NoBackend -> NoOutputFile
+ _ -> Persistent
+
-----------------------------------------------------------------------------
-- stub .h and .c files (for foreign export support), and cc files.
@@ -413,7 +387,7 @@ compileForeign hsc_env lang stub_c = do
#if __GLASGOW_HASKELL__ < 811
RawObject -> panic "compileForeign: should be unreachable"
#endif
- (_, stub_o, _) <- runPipeline StopLn hsc_env
+ (_, stub_o, _, _) <- runPipeline StopLn hsc_env
(stub_c, Nothing, Just (RealPhase phase))
Nothing (Temporary TFL_GhcSession)
Nothing{-no ModLocation-}
@@ -668,17 +642,14 @@ compileFile hsc_env stop_phase (src, mb_phase) = do
-- When linking, the -o argument refers to the linker's output.
-- otherwise, we use it as the name for the pipeline's output.
output
- -- If we are doing -fno-code, then act as if the output is
- -- 'Temporary'. This stops GHC trying to copy files to their
- -- final location.
- | NoBackend <- backend dflags = Temporary TFL_CurrentModule
+ | NoBackend <- backend dflags = NoOutputFile
| StopLn <- stop_phase, not (isNoLink ghc_link) = Persistent
-- -o foo applies to linker
| isJust mb_o_file = SpecificFile
-- -o foo applies to the file we are compiling now
| otherwise = Persistent
- ( _, out_file, _) <- runPipeline stop_phase hsc_env
+ ( _, out_file, _, _) <- runPipeline stop_phase hsc_env
(src, Nothing, fmap RealPhase mb_phase)
Nothing
output
@@ -726,8 +697,8 @@ runPipeline
-> PipelineOutput -- ^ Output filename
-> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module
-> [FilePath] -- ^ foreign objects
- -> IO (DynFlags, FilePath, Maybe ModIface)
- -- ^ (final flags, output filename, interface)
+ -> IO (DynFlags, FilePath, Maybe ModIface, Maybe Linkable)
+ -- ^ (final flags, output filename, interface, linkable)
runPipeline stop_phase hsc_env0 (input_fn, mb_input_buf, mb_phase)
mb_basename output maybe_loc foreign_os
@@ -752,7 +723,8 @@ runPipeline stop_phase hsc_env0 (input_fn, mb_input_buf, mb_phase)
isHaskell (RealPhase (Cpp _)) = True
isHaskell (RealPhase (HsPp _)) = True
isHaskell (RealPhase (Hsc _)) = True
- isHaskell (HscOut {}) = True
+ isHaskell (HscPostTc {}) = True
+ isHaskell (HscBackend {}) = True
isHaskell _ = False
isHaskellishFile = isHaskell start_phase
@@ -780,7 +752,8 @@ runPipeline stop_phase hsc_env0 (input_fn, mb_input_buf, mb_phase)
throwGhcExceptionIO (UsageError
("cannot compile this file to desired target: "
++ input_fn))
- HscOut {} -> return ()
+ HscPostTc {} -> return ()
+ HscBackend {} -> return ()
-- Write input buffer to temp file if requested
input_fn' <- case (start_phase, mb_input_buf) of
@@ -856,15 +829,17 @@ runPipeline'
-> FilePath -- ^ Input filename
-> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module
-> [FilePath] -- ^ foreign objects, if we have one
- -> IO (DynFlags, FilePath, Maybe ModIface)
- -- ^ (final flags, output filename, interface)
+ -> IO (DynFlags, FilePath, Maybe ModIface, Maybe Linkable)
+ -- ^ (final flags, output filename, interface, linkable)
runPipeline' start_phase hsc_env env input_fn
maybe_loc foreign_os
= do
-- Execute the pipeline...
- let state = PipeState{ hsc_env, maybe_loc, foreign_os = foreign_os, iface = Nothing }
+ let state = PipeState{ hsc_env, maybe_loc, foreign_os = foreign_os, iface = Nothing
+ , maybe_linkable = Nothing }
(pipe_state, fp) <- evalP (pipeLoop start_phase input_fn) env state
- return (pipeStateDynFlags pipe_state, fp, pipeStateModIface pipe_state)
+ return (pipeStateDynFlags pipe_state, fp, pipeStateModIface pipe_state
+ , pipeStateLinkable pipe_state )
-- ---------------------------------------------------------------------------
-- outer pipeline loop
@@ -888,6 +863,7 @@ pipeLoop phase input_fn = do
case output_spec env of
Temporary _ ->
return input_fn
+ NoOutputFile -> return input_fn
output ->
do pst <- getPipeState
tmpfs <- hsc_tmpfs <$> getPipeSession
@@ -915,7 +891,7 @@ pipeLoop phase input_fn = do
(text "Running phase" <+> ppr phase)
case phase of
- HscOut {} -> do
+ HscBackend {} -> do
-- Depending on the dynamic-too state, we first run the
-- backend to generate the non-dynamic objects and then
-- re-run it to generate the dynamic ones.
@@ -1351,20 +1327,67 @@ runPhase (RealPhase (Hsc src_flavour)) input_fn
-- run the compiler!
let msg hsc_env _ what _ = oneShotMsg hsc_env what
- (result, plugin_hsc_env) <-
- liftIO $ hscIncrementalCompile True Nothing (Just msg) hsc_env'
- mod_summary source_unchanged Nothing (1,1)
+ plugin_hsc_env' <- liftIO $ initializePlugins hsc_env'
+
+ -- Need to set the knot-tying mutable variable for interface
+ -- files. See GHC.Tc.Utils.TcGblEnv.tcg_type_env_var.
+ -- See also Note [hsc_type_env_var hack]
+ type_env_var <- liftIO $ newIORef emptyNameEnv
+ let plugin_hsc_env = plugin_hsc_env' { hsc_type_env_var = Just (mod, type_env_var) }
- -- In the rest of the pipeline use the loaded plugins
- setPlugins (hsc_plugins plugin_hsc_env)
- (hsc_static_plugins plugin_hsc_env)
- -- "driver" plugins may have modified the DynFlags so we update them
- setDynFlags (hsc_dflags plugin_hsc_env)
+ status <- liftIO $ hscRecompStatus (Just msg) plugin_hsc_env mod_summary
+ source_unchanged Nothing (1, 1)
- return (HscOut src_flavour mod_name result,
- panic "HscOut doesn't have an input filename")
+ logger <- getLogger
+ case status of
+ HscUpToDate iface ->
+ do liftIO $ touchObjectFile logger dflags o_file
+ -- The .o file must have a later modification date
+ -- than the source file (else we wouldn't get Nothing)
+ -- but we touch it anyway, to keep 'make' happy (we think).
+ setIface iface
+ return (RealPhase StopLn, o_file)
+ HscRecompNeeded mb_old_hash -> do
+ (tc_result, warnings) <- liftIO $
+ hscTypecheckAndGetWarnings plugin_hsc_env mod_summary
+
+ -- In the rest of the pipeline use the loaded plugins
+ setPlugins (hsc_plugins plugin_hsc_env)
+ (hsc_static_plugins plugin_hsc_env)
+ -- "driver" plugins may have modified the DynFlags so we update them
+ setDynFlags (hsc_dflags plugin_hsc_env)
+
+ return (HscPostTc mod_summary tc_result warnings mb_old_hash,
+ panic "HscPostTc doesn't have an input filename")
+
+runPhase (HscPostTc mod_summary tc_result tc_warnings mb_old_hash) _ = do
+ PipeState{hsc_env=hsc_env'} <- getPipeState
+ hscBackendAction <- liftIO $ runHsc hsc_env' $ do
+ hscDesugarAndSimplify mod_summary tc_result tc_warnings mb_old_hash
+
+ dflags <- getDynFlags
+ let hscBackendPhase = HscBackend mod_summary hscBackendAction
+ next_phase <- case hscBackendAction of
+ HscUpdate iface -> do
+ setIface iface
+ -- Need to set a fake linkable
+ let setLinkableAndStop = do
+ unless (isHsBootOrSig $ ms_hsc_src mod_summary) $
+ setLinkable (LM (ms_hs_date mod_summary) (ms_mod mod_summary) [])
+ return $ RealPhase StopLn
+ case backend dflags of
+ NoBackend -> setLinkableAndStop
+ Interpreter -> setLinkableAndStop
+ _ -> return hscBackendPhase -- Need to create .o, and handle -dynamic-too
+ _ -> return hscBackendPhase
+
+ return (next_phase,
+ panic "HscBackend doesn't have an input filename")
+
+runPhase (HscBackend mod_summary result) _ = do
+ let mod_name = moduleName (ms_mod mod_summary)
+ src_flavour = (ms_hsc_src mod_summary)
-runPhase (HscOut src_flavour mod_name result) _ = do
dflags <- getDynFlags
logger <- getLogger
location <- getLocation src_flavour mod_name
@@ -1374,34 +1397,62 @@ runPhase (HscOut src_flavour mod_name result) _ = do
next_phase = hscPostBackendPhase src_flavour (backend dflags)
case result of
- HscNotGeneratingCode _ _ ->
- return (RealPhase StopLn,
- panic "No output filename from Hsc when no-code")
- HscUpToDate _ _ ->
- do liftIO $ touchObjectFile logger dflags o_file
- -- The .o file must have a later modification date
- -- than the source file (else we wouldn't get Nothing)
- -- but we touch it anyway, to keep 'make' happy (we think).
- return (RealPhase StopLn, o_file)
- HscUpdateBoot _ _ ->
- do -- In the case of hs-boot files, generate a dummy .o-boot
- -- stamp file for the benefit of Make
- liftIO $ touchObjectFile logger dflags o_file
- return (RealPhase StopLn, o_file)
- HscUpdateSig _ _ ->
- do -- We need to create a REAL but empty .o file
- -- because we are going to attempt to put it in a library
- PipeState{hsc_env=hsc_env'} <- getPipeState
- let input_fn = expectJust "runPhase" (ml_hs_file location)
- basename = dropExtension input_fn
- liftIO $ compileEmptyStub dflags hsc_env' basename location mod_name
+ HscUpdate iface ->
+ do
+ case src_flavour of
+ HsigFile -> do
+ -- We need to create a REAL but empty .o file
+ -- because we are going to attempt to put it in a library
+ PipeState{hsc_env=hsc_env'} <- getPipeState
+ let input_fn = expectJust "runPhase" (ml_hs_file location)
+ basename = dropExtension input_fn
+ liftIO $ compileEmptyStub dflags hsc_env' basename location mod_name
+
+ -- In the case of hs-boot files, generate a dummy .o-boot
+ -- stamp file for the benefit of Make
+ HsBootFile -> liftIO $ touchObjectFile logger dflags o_file
+ HsSrcFile -> panic "HscUpdate not relevant for HscSrcFile"
+
+ setIface iface
return (RealPhase StopLn, o_file)
HscRecomp { hscs_guts = cgguts,
hscs_mod_location = mod_location,
hscs_partial_iface = partial_iface,
hscs_old_iface_hash = mb_old_iface_hash
}
- -> do output_fn <- phaseOutputFilename next_phase
+ -> case backend dflags of
+ NoBackend -> panic "HscRecomp not relevant for NoBackend"
+ Interpreter -> do
+ PipeState{hsc_env=hsc_env'} <- getPipeState
+ -- In interpreted mode the regular codeGen backend is not run so we
+ -- generate a interface without codeGen info.
+ final_iface <- liftIO $ mkFullIface hsc_env' partial_iface Nothing
+ liftIO $ hscMaybeWriteIface logger dflags True final_iface mb_old_iface_hash location
+
+ (hasStub, comp_bc, spt_entries) <- liftIO $ hscInteractive hsc_env' cgguts mod_location
+
+ stub_o <- liftIO $ case hasStub of
+ Nothing -> return []
+ Just stub_c -> do
+ stub_o <- compileStub hsc_env' stub_c
+ return [DotO stub_o]
+
+ let hs_unlinked = [BCOs comp_bc spt_entries]
+ unlinked_time = ms_hs_date mod_summary
+ -- Why do we use the timestamp of the source file here,
+ -- rather than the current time? This works better in
+ -- the case where the local clock is out of sync
+ -- with the filesystem's clock. It's just as accurate:
+ -- if the source is modified, then the linkable will
+ -- be out of date.
+ let !linkable = LM unlinked_time (ms_mod mod_summary)
+ (hs_unlinked ++ stub_o)
+ setIface final_iface
+ setLinkable linkable
+ return (RealPhase StopLn,
+ panic "Interpreter backend doesn't have an output file")
+ _ -> do
+ output_fn <- phaseOutputFilename next_phase
PipeState{hsc_env=hsc_env'} <- getPipeState
@@ -1820,47 +1871,33 @@ getLocation src_flavour mod_name = do
PipeEnv{ src_basename=basename,
src_suffix=suff } <- getPipeEnv
- PipeState { maybe_loc=maybe_loc} <- getPipeState
- case maybe_loc of
- -- Build a ModLocation to pass to hscMain.
- -- The source filename is rather irrelevant by now, but it's used
- -- by hscMain for messages. hscMain also needs
- -- the .hi and .o filenames. If we already have a ModLocation
- -- then simply update the extensions of the interface and object
- -- files to match the DynFlags, otherwise use the logic in Finder.
- Just l -> return $ l
- { ml_hs_file = Just $ basename <.> suff
- , ml_hi_file = ml_hi_file l -<.> hiSuf dflags
- , ml_obj_file = ml_obj_file l -<.> objectSuf dflags
- }
- _ -> do
- location1 <- liftIO $ mkHomeModLocation2 dflags mod_name basename suff
-
- -- Boot-ify it if necessary
- let location2
- | HsBootFile <- src_flavour = addBootSuffixLocnOut location1
- | otherwise = location1
-
-
- -- Take -ohi into account if present
- -- This can't be done in mkHomeModuleLocation because
- -- it only applies to the module being compiles
- let ohi = outputHi dflags
- location3 | Just fn <- ohi = location2{ ml_hi_file = fn }
- | otherwise = location2
-
- -- Take -o into account if present
- -- Very like -ohi, but we must *only* do this if we aren't linking
- -- (If we're linking then the -o applies to the linked thing, not to
- -- the object file for one module.)
- -- Note the nasty duplication with the same computation in compileFile
- -- above
- let expl_o_file = outputFile dflags
- location4 | Just ofile <- expl_o_file
- , isNoLink (ghcLink dflags)
- = location3 { ml_obj_file = ofile }
- | otherwise = location3
- return location4
+ location1 <- liftIO $ mkHomeModLocation2 dflags mod_name basename suff
+
+ -- Boot-ify it if necessary
+ let location2
+ | HsBootFile <- src_flavour = addBootSuffixLocnOut location1
+ | otherwise = location1
+
+
+ -- Take -ohi into account if present
+ -- This can't be done in mkHomeModuleLocation because
+ -- it only applies to the module being compiles
+ let ohi = outputHi dflags
+ location3 | Just fn <- ohi = location2{ ml_hi_file = fn }
+ | otherwise = location2
+
+ -- Take -o into account if present
+ -- Very like -ohi, but we must *only* do this if we aren't linking
+ -- (If we're linking then the -o applies to the linked thing, not to
+ -- the object file for one module.)
+ -- Note the nasty duplication with the same computation in compileFile
+ -- above
+ let expl_o_file = outputFile dflags
+ location4 | Just ofile <- expl_o_file
+ , isNoLink (ghcLink dflags)
+ = location3 { ml_obj_file = ofile }
+ | otherwise = location3
+ return location4
-----------------------------------------------------------------------------
-- Look for the /* GHC_PACKAGES ... */ comment at the top of a .hc file